SAP ABAP开发实战:用BAPI_GOODSMVT_CANCEL冲销物料凭证的完整代码与避坑指南

张开发
2026/4/20 17:35:21 15 分钟阅读

分享文章

SAP ABAP开发实战:用BAPI_GOODSMVT_CANCEL冲销物料凭证的完整代码与避坑指南
SAP ABAP开发实战用BAPI_GOODSMVT_CANCEL冲销物料凭证的完整代码与避坑指南物料凭证冲销是SAP系统中常见的库存调整操作尤其在制造业和物流领域频繁使用。对于ABAP开发者而言熟练掌握BAPI_GOODSMVT_CANCEL的调用不仅关系到功能实现效率更直接影响业务数据的准确性。本文将从一个完整的企业级开发案例出发深入解析代码实现细节并分享实际项目中积累的七个关键避坑点。1. 环境准备与基础概念在开始编码前我们需要明确几个核心概念。物料凭证(Material Document)是SAP系统中记录物料移动的基础单据包含货物接收、发货、转移等操作。冲销操作不是简单的删除而是生成一个反向凭证来抵消原凭证的影响。1.1 开发环境配置确保你的开发环境满足以下条件SAP系统版本不低于ECC 6.0开发用户拥有以下权限对象M_MSEG_WMB物料凭证写入权限M_MATE_WMB物料主数据维护权限事务码SE38可用以创建程序事务码BAPI可用以查阅BAPI文档提示建议在开发前通过事务码MB22查看目标物料凭证的详细信息确认凭证状态可冲销1.2 关键数据表结构理解相关表结构对开发至关重要表名关键字段说明MSEGMBLNR, MJAHR, ZEILE物料凭证项目表MKPFMBLNR, MJAHR物料凭证抬头表BAPI2017_GM_HEAD_RETMAT_DOC, DOC_YEARBAPI返回的凭证头信息BAPIRET2TYPE, MESSAGEBAPI返回消息结构2. 完整代码实现与解析下面是一个可直接用于生产环境的完整实现方案包含详细的错误处理和日志记录。2.1 数据声明与初始化REPORT zmm_goods_mvt_cancel. * 输入参数定义 PARAMETERS: p_mblnr TYPE mblnr OBLIGATORY, 物料凭证号 p_mjahr TYPE mjahr OBLIGATORY. 会计年度 * 数据结构定义 DATA: ls_headret TYPE bapi2017_gm_head_ret, 返回凭证头 lt_return TYPE TABLE OF bapiret2, 返回消息表 lv_message TYPE string, 消息文本 lv_success TYPE abap_bool VALUE abap_false. 执行状态 * 自定义日志表结构 TYPES: BEGIN OF ty_log, mblnr TYPE mblnr, 凭证号 mjahr TYPE mjahr, 年度 msgty TYPE symsgty, 消息类型 message TYPE string, 消息文本 timestamp TYPE timestamp, 时间戳 END OF ty_log. DATA: lt_log TYPE TABLE OF ty_log, ls_log TYPE ty_log.2.2 核心业务逻辑实现START-OF-SELECTION. PERFORM validate_input. 输入校验 PERFORM cancel_material_document. 冲销凭证 PERFORM update_custom_tables. 更新自定义表 PERFORM display_result. 结果显示 *---------------------------------------------------------------------* * Form CANCEL_MATERIAL_DOCUMENT *---------------------------------------------------------------------* FORM cancel_material_document. 获取当前日期作为过账日期 DATA(lv_pstng_date) sy-datum. 调用BAPI冲销物料凭证 CALL FUNCTION BAPI_GOODSMVT_CANCEL EXPORTING materialdocument p_mblnr matdocumentyear p_mjahr goodsmvt_pstng_date lv_pstng_date goodsmvt_pr_uname sy-uname IMPORTING goodsmvt_headret ls_headret TABLES return lt_return. 检查返回消息 LOOP AT lt_return TRANSPORTING NO FIELDS WHERE type CA AEX. A-终止 E-错误 X-退出 EXIT. ENDLOOP. IF sy-subrc 0. 存在错误消息 PERFORM handle_errors. ELSE. 提交事务 CALL FUNCTION BAPI_TRANSACTION_COMMIT EXPORTING wait abap_true. lv_success abap_true. lv_message |冲销成功新凭证号: { ls_headret-mat_doc }|. 记录成功日志 ls_log-mblnr p_mblnr. ls_log-mjahr p_mjahr. ls_log-msgty S. ls_log-message lv_message. GET TIME STAMP FIELD ls_log-timestamp. APPEND ls_log TO lt_log. ENDIF. ENDFORM.2.3 错误处理与回滚*---------------------------------------------------------------------* * Form HANDLE_ERRORS *---------------------------------------------------------------------* FORM handle_errors. 回滚事务 CALL FUNCTION BAPI_TRANSACTION_ROLLBACK. 拼接错误消息 CLEAR lv_message. LOOP AT lt_return WHERE type CA AEX. CONCATENATE lv_message return-message ; INTO lv_message. ENDLOOP. 记录错误日志 ls_log-mblnr p_mblnr. ls_log-mjahr p_mjahr. ls_log-msgty E. ls_log-message lv_message. GET TIME STAMP FIELD ls_log-timestamp. APPEND ls_log TO lt_log. 显示错误消息 MESSAGE lv_message TYPE S DISPLAY LIKE E. ENDFORM.3. 七大避坑指南与实战技巧在实际项目开发中以下经验教训值得特别注意3.1 凭证年份的正确获取很多开发者容易直接从过账日期(BUDAT)截取年份这在跨年时会导致错误。正确做法应该是通过MKPF表查询凭证年份或者使用BAPI_GOODSMVT_GETDETAIL获取凭证详情错误做法跨年时可能出错 DATA(lv_mjahr) gs_alv-budat0(4). 正确做法 SELECT SINGLE mjahr FROM mkpf INTO lv_mjahr WHERE mblnr p_mblnr. IF sy-subrc 0. MESSAGE 物料凭证不存在 TYPE E. RETURN. ENDIF.3.2 返回表的空值判断陷阱直接判断内表是否为空(IS INITIAL)可能遗漏重要消息。推荐做法优先检查是否存在A/E/X类型消息使用READ TABLE比LOOP更高效记录所有返回消息供后续分析不推荐的做法 IF lt_return[] IS INITIAL. 提交事务 ENDIF. 推荐做法 READ TABLE lt_return TRANSPORTING NO FIELDS WITH KEY type E. IF sy-subrc 0. 没有错误消息 提交事务 ENDIF.3.3 自定义表字段更新时机在冲销成功后更新自定义状态字段时需注意必须在BAPI_TRANSACTION_COMMIT之后更新更新前再次确认冲销是否成功考虑添加数据库锁防止并发修改FORM update_custom_tables. CHECK lv_success abap_true. 确认冲销成功 锁定记录防止并发修改 CALL FUNCTION ENQUEUE_EZ_ZTMM_LOG EXPORTING mandt sy-mandt mblnr p_mblnr mjahr p_mjahr EXCEPTIONS foreign_lock 1 system_failure 2 OTHERS 3. IF sy-subrc 0. 处理锁冲突 RETURN. ENDIF. 更新自定义表 UPDATE ztmm_xsj_salesp SET: status C, C-已冲销 cancel_doc ls_headret-mat_doc, cancel_date sy-datum WHERE mblnr p_mblnr AND mjahr p_mjahr. 释放锁 CALL FUNCTION DEQUEUE_EZ_ZTMM_LOG EXPORTING mandt sy-mandt mblnr p_mblnr mjahr p_mjahr. ENDFORM.4. 高级调试技巧与性能优化4.1 使用SAT进行性能分析当处理大批量冲销时性能可能成为瓶颈。推荐使用事务码SAT进行分析在调用BAPI前执行/ron运行冲销程序执行/roff停止跟踪分析耗时最长的操作常见优化点包括减少数据库查询次数批量处理代替单条处理优化自定义表更新逻辑4.2 调试BAPI内部逻辑当BAPI行为不符合预期时可以在SE37中查找BAPI函数模块设置外部断点使用事务码ST05开启SQL跟踪检查传入参数和表数据注意生产环境调试需谨慎可能影响其他用户操作4.3 批量处理实现方案对于需要批量冲销的场景建议采用以下架构* 批量选择界面 SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-001. PARAMETERS: p_file TYPE rlgrap-filename. 上传文件路径 SELECTION-SCREEN END OF BLOCK b1. * 批量处理逻辑 FORM process_batch. DATA: lt_batch TYPE TABLE OF ty_batch, ls_batch TYPE ty_batch. 从文件读取批量数据 PERFORM read_file USING p_file CHANGING lt_batch. 处理每条记录 LOOP AT lt_batch INTO ls_batch. p_mblnr ls_batch-mblnr. p_mjahr ls_batch-mjahr. PERFORM cancel_material_document. 记录处理结果 ls_batch-status lv_success. ls_batch-message lv_message. MODIFY lt_batch FROM ls_batch. ENDLOOP. 生成处理报告 PERFORM generate_report USING lt_batch. ENDFORM.5. 异常场景处理方案实际业务中可能遇到各种异常情况需要特别处理5.1 凭证已冲销情况处理检查凭证是否已冲销 SELECT SINGLE xblnr FROM mkpf INTO lv_xblnr WHERE mblnr p_mblnr AND mjahr p_mjahr. IF lv_xblnr IS NOT INITIAL. MESSAGE |凭证{ p_mblnr }已被冲销冲销凭证号: { lv_xblnr }| TYPE I. RETURN. ENDIF.5.2 会计期间已关闭情况检查过账日期所在期间是否已关闭 CALL FUNCTION FI_PERIOD_DETERMINE EXPORTING i_budat lv_pstng_date i_bukrs lv_company_code IMPORTING e_gjahr lv_fisc_year e_poper lv_fisc_period e_perclosed lv_per_closed. IF lv_per_closed X. MESSAGE |会计期间{ lv_fisc_year }/{ lv_fisc_period }已关闭| TYPE E. RETURN. ENDIF.5.3 物料已冻结情况检查物料是否被冻结 SELECT SINGLE maktx, lvorm FROM makt INTO (lv_maktx, lv_lvorm) WHERE matnr ls_item-matnr AND spras sy-langu. IF lv_lvorm X. MESSAGE |物料{ ls_item-matnr }({ lv_maktx })已被标记为删除| TYPE E. RETURN. ENDIF.6. 增强与扩展方案根据企业特定需求可以考虑以下增强点6.1 添加审批工作流在冲销前检查审批状态集成SAP工作流或外部审批系统记录审批历史FORM check_approval. SELECT SINGLE status FROM ztmm_approval INTO lv_status WHERE mblnr p_mblnr AND mjahr p_mjahr AND doctype CANCEL. CANCEL-冲销类型 CASE lv_status. WHEN P. Pending-待审批 MESSAGE 冲销请求待审批 TYPE E. RETURN. WHEN R. Rejected-已拒绝 MESSAGE 冲销请求已被拒绝 TYPE E. RETURN. WHEN A OR . Approved或无记录 继续执行 WHEN OTHERS. MESSAGE 未知的审批状态 TYPE E. RETURN. ENDCASE. ENDFORM.6.2 与财务模块集成冲销后自动触发财务凭证冲销检查会计凭证状态提供财务冲销结果反馈FORM reverse_fi_document. 获取物料凭证对应的会计凭证 SELECT SINGLE belnr, gjahr, buzei FROM bseg INTO (lv_belnr, lv_gjahr, lv_buzei) WHERE mblnr p_mblnr AND mjahr p_mjahr AND bukrs lv_company_code. IF sy-subrc 0. 调用财务冲销BAPI CALL FUNCTION BAPI_ACC_DOCUMENT_REV_POST EXPORTING reversal_doc lv_belnr fiscal_year lv_gjahr posting_date sy-datum IMPORTING reversal_doc_new lv_new_belnr TABLES return lt_fi_return. 处理返回结果 ... ENDIF. ENDFORM.6.3 移动端集成方案开发Fiori应用调用冲销服务使用OData服务封装业务逻辑添加二维码扫描输入功能OData服务方法示例 METHOD cancel_material_doc. DATA: ls_input TYPE zcl_zmm_goods_mvt_mpcts_input, ls_output TYPE zcl_zmm_goods_mvt_mpcts_output. 获取输入参数 io_data_provider-read_entry_data( IMPORTING es_data ls_input ). 调用冲销逻辑 p_mblnr ls_input-mblnr. p_mjahr ls_input-mjahr. PERFORM cancel_material_document. 设置输出 ls_output-mblnr p_mblnr. ls_output-mjahr p_mjahr. ls_output-success lv_success. ls_output-message lv_message. 返回结果 copy_data_to_ref( EXPORTING is_data ls_output CHANGING cr_data er_entity ). ENDMETHOD.7. 版本管理与最佳实践7.1 代码版本控制策略建议采用以下版本管理方案使用CTS或Git管理ABAP代码每个功能变更创建独立传输请求添加详细的变更日志注释*---------------------------------------------------------------------* * 变更记录 *---------------------------------------------------------------------* * 日期 | 开发者 | 传输请求 | 描述 *----------------------------------------------------------------------* * 2023-07-01 | DEVELOPER1 | TR123456 | 初始版本 * 2023-08-15 | DEVELOPER2 | TR234567 | 添加批量处理功能 * 2023-09-20 | DEVELOPER1 | TR345678 | 增强错误处理逻辑7.2 单元测试方案为关键功能添加单元测试METHOD test_successful_cancel. 准备测试数据 test_data-setup( ). 设置模拟BAPI调用 cl_mock_servicesexpect_call(BAPI_GOODSMVT_CANCEL) -with_exporting_parameter(MATERIALDOCUMENT, 4900000123) -with_exporting_parameter(MATDOCUMENTYEAR, 2023) -returns_table(RETURN, lt_success_return). 执行测试 cut-cancel_material_document( EXPORTING iv_mblnr 4900000123 iv_mjahr 2023 IMPORTING ev_success lv_success ev_message lv_message ). 验证结果 cl_abap_unit_assertassert_true( lv_success ). cl_abap_unit_assertassert_equals( exp 冲销成功新凭证号: 4900000124 act lv_message ). ENDMETHOD.7.3 性能监控与日志分析建议在生产环境实施使用事务码SLG1记录详细日志设置性能阈值告警定期分析冲销操作统计记录应用日志 FUNCTION z_log_message. DATA: ls_log TYPE bal_s_msg. ls_log-msgty iv_msgty. ls_log-msgid iv_msgid. ls_log-msgno iv_msgno. ls_log-msgv1 iv_msgv1. ls_log-msgv2 iv_msgv2. ls_log-msgv3 iv_msgv3. ls_log-msgv4 iv_msgv4. CALL FUNCTION BAL_LOG_MSG_ADD EXPORTING i_s_msg ls_log i_log_handle gv_log_handle. ENDFUNCTION.

更多文章