SAP 基于 BAPI_GOODS_MVT_CREATE 的 AI 驱动开发

文章目录

SAP 采购订单收货函数实战:基于 BAPI_GOODS_MVT_CREATE 的 AI 驱动开发

本文记录一次使用 AI 编程助手,在 SAP S/4HANA 系统中从零开发采购收货自定义函数的完整过程,涵盖技术选型、开发环境、踩坑过程、最终成果,希望对 SAP 开发 + AI 提效场景有参考价值。


一、需求背景--(测试AI功能使用-没有指定具体的业务要求)

业务需要封装一个可供其他程序复用的采购订单收货 函数模块,底层调用 SAP 标准 BAPI ------ BAPI_GOODS_MVT_CREATE(移动类型默认 101)。

要求:

  • 放置在现有的 PO 函数组 ZFG_COPY_PO 下;
  • 参数风格统一(IV_ / EV_ 前缀);
  • 业务逻辑完善:必填校验、默认日期/移动类型、成功判断、RETURN 表回传、测试运行控制;
  • 提交方式标准化:使用 BAPI 事务函数提交/回滚,而非裸 COMMIT WORK

二、技术栈与环境

开发过程不是"闷头写代码",而是基于 MCP(Model Context Protocol) 打通 AI 与 SAP 的三层通道:

通道 用途 写权限
(ABAP Development Tools) 创建/读取/编辑源代码、激活对象 ✅ 可写
(Remote Function Call) 只读查询(查表结构等) ❌ 只读
OData 系统登录与会话管理 中间层

开发对象:自定义函数 Z_MM_GR_PO_GOODSRCPT

  • 函数组:ZFG_COPY_PO
  • 包:$TMP
  • 关键依赖类型:
    • BAPI2017_GM_HEAD_01 抬头
    • BAPI2017_GM_CODE 代码
    • BAPI2017_GM_ITEM_CREATE 项目
    • BAPIRET2 返回消息

三、过程实现(核心踩坑与解决)

1. 第一步:确认对象与类型是否存在

按"字段名先查再写、禁止猜"的原则,用 RFC 读取数据字典 DD03L 确认所有 BAPI 结构真实存在:

  • BAPIRET2 结构存在 ------ 返回消息表行类型;
  • BAPI2017_GM_ITEM_CREATE 结构存在 ------ 项目字段(PO_NUMBER / PO_ITEM / MOVE_TYPE / PLANT / STGE_LOC / ENTRY_QNT)。

教训:类型名拼写错误是激活失败的主要来源之一。

2. 使用 ADT 创建函数模块

使用 ADT 的源码写入能力,一次性提交完整的 FUNCTION ... ENDFUNCTION. 块,完成对象创建与激活。

3. 遇到的"规则雷区"(关键经验)

在多次激活失败后,总结出该套件下的三大避坑点:

  1. 禁止 DATA: 冒号批量声明 :ADT 归一化解析器会把 DATA: a TYPE x, b TYPE y. 误判为函数参数接口,从而生成一堆错误的 EXPORTING 参数。必须一行一条 DATA x TYPE y.

  2. TABLES 参数类型写法 :需要一个 ET_RETURN TYPE BAPIRET2(直接给行类型 ),这一行写 STANDARD TABLE OF 会被解析器拆错。用行类型由系统自动转内表。

  3. Type 名称必须以数据字典为准 :曾把 BAPIRET2 误写成 BAPIRETAP / bapiretr 等,触发 Type unknown

4. 标准化的成功判断与提交

abap 复制代码
" 调用标准 BAPI 执行货物移动
CALL FUNCTION 'BAPI_GOODS_MVT_CREATE'
  EXPORTING goodsmvt_header = ls_header
            goodsmvt_code   = ls_code
            testrun         = iv_testrun
  TABLES    goodsmvt_item   = lt_item
            return          = lt_ret.

" 回传 BAPI 返回消息
et_return[] = lt_ret[].

" 检查是否存在错误/中止类型返回
LOOP AT lt_ret INTO ls_ret WHERE type CA 'EAX'.
  lv_error = 'X'.
  EXIT.
ENDLOOP.

" 存在错误则标准回滚
IF lv_error = 'X'.
  IF iv_testrun IS INITIAL.
    CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
  ENDIF.
  ev_success = ''.
  RETURN.
ENDIF.

" 处理成功:标准提交(测试运行不提交)
ev_success = 'X'.
IF iv_testrun IS INITIAL.
  CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
    EXPORTING wait = 'X'.
ENDIF.

要点:

  • 成功判断:遍历 RETURN 表的 type,含 E/A/X 视为失败;
  • 提交:统一走 BAPI_TRANSACTION_COMMIT(WAIT='X')
  • 回滚:出错走 BAPI_TRANSACTION_ROLLBACK,不再直接用 `COMMIT WORK》;
  • 测试运行 IV_TESTRUN 时不提交,只做验证。

四、最终成果

生成对象

plaintext 复制代码
对象名称  : Z_MM_GR_PO_GOODSRCPT
所属函数组: ZFG_COPY_PO
所属包    : $TMP
激活状态  : ✓ 成功激活(activated = true, 无错误)
参数数量  : 14

接口清单

方向 参数 类型 说明
IMPORTING IV_PO_NUMBER EBELN 采购订单号(必输)
IV_PO_ITEM EBELP 采购订单行项目(必输)
IV_QTY MENGE_D 收货数量(必输)
IV_UOM MEINS 收货单位
IV_PLANT WERKS_D 工厂
IV_STGE_LOC LGORT_D 存储地点
IV_MOVE_TYPE BWART 移动类型(默认 101)
IV_PSTNG_DATE BUDAT 过账日期(默认当天)
IV_HEADER_TXT BKTXT 抬头文本
IV_TESTRUN XFELD 测试运行
EXPORT EV_SUCCESS XFELD 是否成功
EV_MAT_DOC MBLNR 物料凭证号
EV_MAT_YEAR MJAHR 物料凭证年度
TABLES ET_RETURN BAPIRET2 BAPI 返回消息

开发亮点

  1. 多通道协作:ADT 写、RFC 查、OData 登录,三层通道各司其职,全程无人为手工录入;
  2. 先查后写:所有字段/类型名先经 DDIC 核实,杜绝盲猜;
  3. 标准化提交:BAPI 事务函数 + 测试运行处理,安全合规;
  4. 注释与格式:程序头文档、逐段中文注释、变量前缀规范。

五、结尾

这次开发说明了一个判断:即使是一个小功能 BAPI 封装函数,背后也涉及类型名精确性、参数写法兼容、事务提交规范 等细节。而借助统一的 MCP 通道,AI 可以完成「分析 → 查询 → 编码 → 激活 → 校验」的闭环,大幅提升开发效率。

如果你也想用类似方式,提升 SAP 常规功能的开发体验,建议先从「小函数封装 + 类型字典查询」这类低风险场景入手。

最后附上代码

ABAP 复制代码
function z_mm_gr_po_goodsrcpt.
*"----------------------------------------------------------------------
*"*"本地接口:
*"  IMPORTING
*"     VALUE(IV_PO_NUMBER) TYPE  EBELN
*"     VALUE(IV_PO_ITEM) TYPE  EBELP
*"     VALUE(IV_QTY) TYPE  MENGE_D
*"     VALUE(IV_UOM) TYPE  MEINS OPTIONAL
*"     VALUE(IV_PLANT) TYPE  WERKS_D OPTIONAL
*"     VALUE(IV_STGE_LOC) TYPE  LGORT_D OPTIONAL
*"     VALUE(IV_MOVE_TYPE) TYPE  BWART OPTIONAL
*"     VALUE(IV_PSTNG_DATE) TYPE  BUDAT OPTIONAL
*"     VALUE(IV_HEADER_TXT) TYPE  BKTXT OPTIONAL
*"     VALUE(IV_TESTRUN) TYPE  XFELD OPTIONAL
*"  EXPORTING
*"     VALUE(EV_SUCCESS) TYPE  XFELD
*"     VALUE(EV_MAT_DOC) TYPE  MBLNR
*"     VALUE(EV_MAT_YEAR) TYPE  MJAHR
*"  TABLES
*"      ET_RETURN STRUCTURE  BAPIRET2
*"----------------------------------------------------------------------
  .

  DATA ls_header TYPE bapi2017_gm_head_01.       " 货物移动抬头
  DATA ls_code   TYPE bapi2017_gm_code.          " 货物移动代码
  DATA lt_item   TYPE TABLE OF bapi2017_gm_item_create.  " 货物移动项目表
  DATA ls_item   LIKE LINE OF lt_item.           " 货物移动项目行
  DATA lt_ret    TYPE TABLE OF bapiret2.         " BAPI返回消息表
  DATA ls_ret    LIKE LINE OF lt_ret.            " BAPI返回消息行
  DATA lv_move   TYPE bwart.                     " 移动类型
  DATA lv_error  TYPE flag.                      " 错误标记

  CLEAR: ev_success, ev_mat_doc, ev_mat_year, et_return.

  " 必填参数校验
  IF iv_po_number IS INITIAL OR iv_po_item IS INITIAL OR iv_qty IS INITIAL.
    RETURN.
  ENDIF.

  " 设置货物移动代码(01=收货)
  ls_code-gm_code = '01'.

  " 设置抬头过账日期(默认当前日期)
  ls_header-pstng_date = sy-datum.
  IF iv_pstng_date IS NOT INITIAL.
    ls_header-pstng_date = iv_pstng_date.
  ENDIF.
  ls_header-header_txt = iv_header_txt.

  " 移动类型默认101(采购订单收货)
  lv_move = iv_move_type.
  IF lv_move IS INITIAL.
    lv_move = '101'.
  ENDIF.
  ls_item-move_type = lv_move.

  " 组装BAPI项目字段
  ls_item-po_number = iv_po_number.
  ls_item-po_item   = iv_po_item.
  ls_item-plant     = iv_plant.
  ls_item-stge_loc  = iv_stge_loc.
  ls_item-entry_qnt = iv_qty.
  ls_item-entry_uom = iv_uom.
  APPEND ls_item TO lt_item.

  " 调用标准BAPI执行货物移动
  CALL FUNCTION 'BAPI_GOODS_MVT_CREATE'
    EXPORTING goodsmvt_header = ls_header
              goodsmvt_code   = ls_code
              testrun         = iv_testrun
    TABLES    goodsmvt_item   = lt_item
              return          = lt_ret.

  " 回传BAPI返回消息
  et_return[] = lt_ret[].

  " 检查是否存在错误/中止类型返回
  LOOP AT lt_ret INTO ls_ret WHERE type CA 'EAX'.
    lv_error = 'X'.
    EXIT.
  ENDLOOP.

  " 存在错误则标准回滚
  IF lv_error = 'X'.
    IF iv_testrun IS INITIAL.
      CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
    ENDIF.
    ev_success = ''.
    RETURN.
  ENDIF.

  " 处理成功:标准提交(测试运行不提交)
  ev_success = 'X'.
  IF iv_testrun IS INITIAL.
    CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
      EXPORTING wait = 'X'.
  ENDIF.
endfunction.
相关推荐
爱喝水的鱼丶24 分钟前
SAP-ABAP:ABAP 用户出口开发规范与避坑指南:10 类典型错误与运维方案
运维·性能优化·sap·abap·增强·经验交流·出口
爱喝水的鱼丶3 小时前
SAP-ABAP:BAdI 上下文数据获取与交互:标准数据读取与修改逻辑实现
运维·性能优化·sap·abap·增强·经验交流·badi
高彬14 小时前
SAP ECC6.0 对接 C# web Services服务
开发语言·前端·c#·sap
Henry-SAP3 天前
AI产业迎来标准化与商业化双突破
人工智能·云原生·sap·erp
Henry-SAP3 天前
SAP PP 从停工待料到精准排产
人工智能·云原生·sap·erp
Henry-SAP3 天前
AI标准落地加速 安全与应用双突破
人工智能·云原生·sap·erp
Henry-SAP4 天前
SAP独立需求与相关需求的区别解析
人工智能·云原生·sap·erp
Henry-SAP4 天前
SAP MRP类型与计划策略配置精髓解析
人工智能·云原生·sap·erp
Henry-SAP5 天前
AI突破重塑未来科技格局
人工智能·云原生·sap·erp