ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SAP MIGO增强实战:基于BADI在收货行项目添加自定义字段与页签

SAP MIGO增强实战:基于BADI在收货行项目添加自定义字段与页签 做过SAP MM的人应该都有这个感受MIGO是仓库和财务每天都在点的T-code功能极其强大但真要在收货界面里加一个业务字段很多人第一反应是“这个能改吗会不会动到标准程序”答案是能改而且SAP官方留了很成熟的增强点。但MIGO又是一个结构非常复杂的程序行项目、页签、过账逻辑全部揉在一起如果你用老一套的CMOD方式去硬加屏幕很容易把标准界面改得乱七八糟甚至影响过账。这篇实战指南我基于自己做过的一个真实项目来拆解客户需要在MIGO收货行项目上新增“质检标志”和“备注说明”两个自定义字段并且要求以独立页签的形式展示数据要跟物料凭证一起保存后续还能在MB03里回看。下面我把从方案选型、BADI实施、自定义页签挂接、字段读写、到常见坑位排查的完整过程都写出来。这套内容适合两类人一类是刚接手SAP MM增强开发的ABAPer另一类是正在头疼“MIGO加字段”该怎么落地的MM顾问。照着这个思路走你至少能少走一半弯路。1. 整体设计思路与增强方案选型1.1 一次MIGO增强需求的拆解过程先别急着写代码。拿到需求的第一步是把业务诉求翻译成技术语言。客户的原始需求是“收货的时候要填质检结果和备注并且要能留痕”。这句话拆开来看是四个问题数据要显示在哪里、数据要存在哪里、数据要跟着哪条业务记录走、数据什么时候写进去。对应到MIGO这个场景答案分别是显示在行项目页签区域、存到自建表或MSEG扩展字段、关联到物料凭证的凭证号和行号、在保存过账时一起落库。我把这个思路画成一张需求拆解表建议你以后也照这个方式来整理业务需求技术落点实现难度收货行填写质检标志MIGO行项目新增自定义页签/字段中数据随凭证保存BADI实施类 自建表/MSEG附加结构中后续可查询MB03 / 自建报表低不影响标准过账只做增强不动标准代码低这一步的重点在于MIGO涉及到的数据载体是什么。MIGO一旦过账会生成物料凭证MKPF MSEG所以你的自定义字段要么挂在MSEG附加结构上要么用独立自建表去关联凭证号和行号。两者各有优劣我在后面会单独讲。1.2 为什么首选BADI而不是CMOD很多老ABAPer习惯性打开SMOD/CMOD去找USER EXIT但MIGO这个事物码要慎用。MIGO是在SAP NetWeaver时代重构过的程序内部大量使用了面向对象框架传统的CMOD增强点覆盖范围有限而且很分散经常出现“界面加了字段但过账时取不到值”这种诡异问题。SAP官方为MIGO预留的标准增强方式是BADIMB_MIGO_BADI。这个BADI的核心价值在于它把MIGO的关键动作都包装成了一系列方法回调包括行项目新增、修改、删除以及最终的过账后处理。你只需要在SE19里创建一个实施类重写需要的方法MIGO就会在对应的业务节点上调用你的逻辑。选型BAdI而不是CMOD我的理由有三个BADI是面向对象方式一个实施类可以管理MIGO新增、修改、删除、过账等所有事件代码结构清晰。BADI支持多个实施不同业务场景可以各自建实施类互不干扰后续维护成本低。BADI的参数传递非常明确尤其能拿到MKPF、MSEG的行项目上下文数据这是做行级字段读写的基础。说实话我一开始也用CMOD试过在MIGO里往行项目上塞自定义字段结果发现很多屏幕控制逻辑是MIGO主程序用ALV管控的老式增强的字段控制根本插不进去。所以如果你正在评估MIGO增强方案直接选BADI省得返工。1.3 数据保存的表结构规划接着聊数据怎么存。这是MIGO增强里最容易翻车的一步。方案A是把自定义字段挂到MSEG表的附加结构上。在SE11里给MSEG创建附加结构添加ZQCZ质检标志CHAR1、ZREMARK备注CHAR40这类字段。这种方案的优点是数据就在物料凭证行项目里查询、报表、ALV展示天然跟随不需要额外关联也不会有数据不同步的问题。缺点是MSEG是核心表附加结构涉及系统级修改传输、升级都要谨慎而且不是所有字段都适合往上挂比如跨行、多行的汇总类数据就别放这里。方案B是建自建表ZMM_MIGO_EX字段包含MBLNR物料凭证号、MJAHR年度、ZEILE行号、ZQCZ、ZREMARK、ZUSER录入人、ZDATE录入日期等然后用凭证号行号去关联MKPF/MSEG。这种方案的优点是自由度高业务字段想怎么扩就怎么扩不碰核心表。缺点是查询时多一张表如果做报表需要JOIN还要自己在BADI里维护写入时机。我的项目里客户既要显示又要查询而且后续可能还要加更多质检字段所以我采用了“组合方案”自定义页签上的核心字段挂在MSEG附加结构上保证凭证数据一体同时单独建一张自建表存扩展信息用于后续质检追溯报表。如果你只是单纯加一两个字段用方案A就够没必要搞两张表增加维护成本。2. 自定义页签与字段的前置搭建2.1 创建BADI实施类方案定了开始动手。第一步是创建BADI实施类。登录SE19输入增强名称MB_MIGO_BADI点击创建输入实施类名称建议ZCL_IM_MIGO_XXX格式系统会自动生成对应的接口实现。这里要特别说明MIGO增强的BADI名称是MB_MIGO_BADI接口类是IF_EX_MB_MIGO_BADI在SE18里可以查到定义。实施类创建后你会看到接口下面挂了很多方法常用的包括GO_ITEM_CREATE行项目新增时触发GO_ITEM_UPDATE行项目修改时触发GO_ITEM_DELETE行项目删除时触发POST_DOCUMENT过账后触发这些方法的核心参数就是MKPF凭证抬头和MSEG行项目的数据载体你可以在方法里拿到当前的凭证号、行号、物料、数量然后做业务逻辑处理。创建完实施类记得分配一个包和传输请求。我的习惯是每个增强需求单独开一个请求避免和别人的开发混在一起后续释放传输更干净。注意BADI实施类的激活状态很重要如果实施类没有激活MIGO运行时增强逻辑不会被调用而且系统不会给出明显报错。这个坑我踩过后来排查了半天才发现是激活状态问题。2.2 附加结构、自建表与屏幕准备绑定好BADI之后下面做两件准备工作表和屏幕。如果走MSEG附加结构方案先在SE11里输入MSEG点击“附加结构”创建一个以Z开头的附加结构比如ZMIGO_ADD_FIELDS添加字段ZQCZ、ZREMARK。激活后MSEG就拥有了这两个字段后续BADI代码可以直接读写。自建表方面我用SE11创建了ZMM_MIGO_EX表结构如下字段数据元素说明MANDTMANDT客户端MBLNRMBLNR物料凭证号MJAHRMJAHR年度ZEILEMBLPO行号ZQCZ自定义质检标志ZREMARK自定义备注说明ZUSERUNAME录入人ZDATEDATUM录入日期表创建好之后可以通过SE11的“维护生成”功能快速生成表维护视图这样测试阶段可以直接用SM30手工补数据不用每次跑代码。屏幕方面MIGO行项目页签区域的自定义屏幕我建议用独立的函数组Function Group来管理。创建一个包含子屏幕Subscreen的程序子屏幕里绘制两个输入框分别绑定ZQCZ和ZREMARK。屏幕编号建议从0100开始避免和标准程序冲突。2.3 页签嵌入的两类实现思路MIGO的自定义页签嵌入我总结出来主要有两种常见思路这里给你做对比思路一BADI回调 ALV容器托管在BADI方法里拿到行项目对应的ALV GRID或容器引用然后创建自己的容器CL_GUI_CUSTOM_CONTAINER把自己的子屏幕挂进去。这种方案定制性最强页签长什么样完全由你控制适合做复杂的质检面板、多行明细展示。思路二菜单增强 标准页签区域的子屏幕替换MIGO界面本身支持通过BADI的CUSTOMER_FUNCTION或者菜单增强来挂载自定义功能你可以把自开发的子屏幕通过屏幕控制逻辑插入到行项目页签区域。它的优点是嵌入感好长得像标准页签缺点是对屏幕流控PBO/PAI的掌握要求高容易出刷新丢失的问题。我的实际选择是方案二的简化版利用BADI方法中能拿到行项目上下文的特性在PBO阶段触发子屏数据填充页签标签文本使用增强方式写入。这种方式在界面观感上最接近原生MIGO客户接受度最高。具体代码实现我在下一章展开。3. 核心代码实现与配置步骤3.1 BADI各方法的职责划分与代码骨架BADI接口的方法之间是有执行顺序的。我做增强之前先把MIGO的运行逻辑捋清楚了先进入界面加载已有行项目触发UPDATE用户新增行触发CREATE用户删除行触发DELETE点过账时检查数据调用字段校验过账成功触发POST_DOCUMENT。所以你的逻辑要按这个生命周期去分派。以“收货时填写质检标志”为例我的代码骨架是这样设计的METHOD if_ex_mb_migo_badi~go_item_create. DATA: ls_selfield TYPE zmm_migo_ex. 新增行项目时的初始化操作比如默认质检标志为未检 ls_selfield-zqcz X. ls_selfield-zremark . MOVE-CORRESPONDING im_mkpf TO ls_selfield. MOVE-CORRESPONDING im_mseg TO ls_selfield. MODIFY zmm_migo_ex FROM ls_selfield. IF sy-subrc 0. MESSAGE 自定义数据保存失败 TYPE E. ENDIF. ENDMETHOD.这里有个点要提醒你BADI收到的IM_MKPF和IM_MSEG有些字段在新增时是空的尤其是物料凭证号MBLNR要等过账时才会生成。所以我不能在GO_ITEM_CREATE里用凭证号去写扩展表否则写进去都是空值。正确的做法是把界面输入值暂存到内存表或全局变量等POST_DOCUMENT里凭证号生成了再真正落库。POST_DOCUMENT方法的核心逻辑METHOD if_ex_mb_migo_badi~post_document. DATA: lt_selfield TYPE TABLE OF zmm_migo_ex, ls_selfield TYPE zmm_migo_ex. 从内存表中取出本次会话暂存的自定义数据 把IM_MKPF-MBLNR、IM_MKPF-MJAHR、行号等关联字段补全 LOOP AT lt_selfield INTO ls_selfield. MOVE-CORRESPONDING im_mkpf TO ls_selfield. MOVE-CORRESPONDING im_mseg TO ls_selfield. MODIFY zmm_migo_ex FROM ls_selfield. ENDLOOP. ENDMETHOD.为什么非要POST_DOCUMENT再落库因为MIGO的过账事务是单会话处理的如果你在行项目事件里直接写表碰到用户点了“保存”但后续校验失败回滚的情况自建表就会产生脏数据。而在POST_DOCUMENT里写意味着过账已经成功数据跟凭证一起提交逻辑上更可靠。3.2 菜单/子屏幕挂接的关键代码自定义页签挂接我这边用的是在BADI方法里通过容器ID去创建自定义容器再把子屏幕的控制权转交给容器。简化后的代码实现逻辑如下METHOD if_ex_mb_migo_badi~header_create. DATA: lo_container TYPE REF TO cl_gui_custom_container, lv_container_name TYPE scrfname. 根据MIGO屏幕上的容器控件名称创建自定义容器 lv_container_name Z_MIGO_QC_CONTAINER. CREATE OBJECT lo_container EXPORTING container_name lv_container_name. 调用自定义函数组的子屏幕把输入控件放入容器 CALL SCREEN 100 STARTING AT 1 1. ENDMETHOD.这里的关键是容器名必须和你在屏幕上假设的容器控件名称一致而且MIGO的页面结构在不同版本里可能有差异所以开发时最好先在调试模式里看一下当前屏幕的控件树用SE80或SPRY屏幕录制工具。如果你不确定直接在屏幕上做一个自定义容器控件再把它挂到MIGO的页签区域。还有一点页签的显示文本通常需要在程序初始化时通过BADI或者屏幕流控写入。最简单的做法是定义一个屏幕元素标签Label在PBO里给它的TEXT属性赋值“质检信息”这样显示出来就是一个带标签的自定义页签。3.3 行项目自定义字段的读写逻辑自定义字段的读写是本项目的重头戏。因为MIGO默认的ALV网格只显示标准字段自建页签里的字段需要跟当前选中的行项目联动。具体做法是在自定义页签子屏幕的PBO事件里读取当前行项目的数据把值填到屏幕字段上在PAI事件里把屏幕上的值写入内存和待保存的表。PROCESS BEFORE OUTPUT. MODULE get_row_data. 根据当前行号读取MSEG/ZMM_MIGO_EX填充屏幕字段 PROCESS AFTER INPUT. MODULE set_row_data. 把屏幕字段的值写入内存表准备过账时保存GET_ROW_DATA的核心逻辑是通过MIGO当前选中行的行号通常可以从BADI传入的上下文或者ALV的GET_CURRENT_CELL方法拿到查自建表把ZQCZ和ZREMARK赋值给屏幕字段。SET_ROW_DATA则是反过来把屏幕输入的值保存到内存表。要注意的是MIGO在同一时刻可能显示多行如果用户切换行你得保证当前屏幕上的值对应正确的行。我的处理方式是用行号为索引的内存表来存切换行时先PUSH当前屏幕值再LOAD新行值避免串行。3.4 过账后数据落库与传输数据落库我前面提到是在POST_DOCUMENT里做。但还有一个细节要注意如果自定义数据要跟着物料凭证一起被查看你需要把自建表也纳入到凭证归档逻辑里。SAP标准做了归档接口自建表默认不在归档范围内但这属于后续运维扩展这里不展开。落库完成后要在MB03里能查到这个自定义数据。最简单的方案是做一个自定义报表输入物料凭证号展示ZMM_MIGO_EX里的质检信息。如果你希望直接在MB03的表头或行项目界面显示那就要再做一次BADI增强或者使用文档流扩展成本会高一些。我的项目里客户当时只要求“能查”所以我做了一个查询报表交付开发量不大实用性却很直接。整个增强开发完成之后要记得把相关对象打包进传输请求BADI实施类、自建表、附加结构、函数组、报表程序。传输顺序没有严格限制但建议先传表结构再传程序逻辑不然目标系统程序激活时会报表结构不存在的错。4. 常见问题与排查技巧实录4.1 页签挂上了但在运行时不显示这是MIGO增强里出现频率最高的问题。页签代码写了、激活了、传输也做了但进MIGO就是看不到。排查思路是三步走第一步确认BADI实施类状态是“已激活”第二步在调试模式里看BADI方法有没有被调用到如果连断点都不进说明实施类没有被MIGO触发重点检查增强名称是否准确、是否传到了对应系统第三步如果断点进了但页签不显示大概率是容器名不匹配或者子屏幕绘制时没有绑定到容器上。调试模式下看一下屏幕控件树找到真实的容器名称再改代码。4.2 保存后自定义字段值丢失有朋友遇到过页签里输入内容点过账再看自建表数据是空的。这个问题的根源通常是我前面提到的“写入时机不对”。如果你在GO_ITEM_UPDATE里直接落库而MIGO因为业务校验失败回滚数据自然就不在了如果你在GO_ITEM_CREATE里用MBLNR去写表而此时MBLNR还没生成那写进去的就是空凭证号查询时自然关联不上。我的建议是所有需要在过账时保存的数据统一走POST_DOCUMENT前置方法里只做暂存。另外要注意MIGO一次过账可能涉及多个行项目POST_DOCUMENT触发时要在方法体内按行项目循环把每一行都补全关联键值。4.3 多行数据串行、错行MIGO增强在单行场景下一般不出问题一旦用户一次收货多个行项目自定义页签的数据就很容易出现“写到别行去了”的错乱。这个问题基本都出在临时存储上。如果你用单变量去存当前行的质检标志用户切换行之后旧的单变量值还没刷新就可能被新行覆盖或者写错。解决办法是不要用单变量改用按行号索引的内表每一行独立存放。切换行的时候先保存当前屏幕到内表对应索引再读取新行的值回填屏幕。这里再补充一个细节MIGO的网格在保存后可能会刷新页签上的值随着屏幕刷新会重新PBO加载。如果发现刷新后自定义页签内容都被清空了检查一下PBO里是否有初始化赋值逻辑确保刷新后能重新从内存表读取并回显。4.4 性能与其他坑位最后集中说几个我在项目里踩过的坑第一BADI方法里别做数据库主表查询。比如每个行项目都SELECT单条MSEG几百行的收货单性能马上崩给你看。正确做法是批量取数或者利用BADI传入的MKPF/MSEG结构。第二MSEG附加结构虽然方便但字段长度要克制。核心表附加结构一旦传输到生产后续想改字段长度会非常痛苦层层审批不说还要考虑数据转换。所以附加字段尽量短小精悍长文本类内容放自建表。第三不要把标准字段的控制逻辑覆盖掉。MIGO里做了字段控制你要是在BADI里强制修改标准字段的显示值可能引起过账时数据不一致。自增字段的行为可以自由点但标准字段只读、不强行干预。第四测试时一定要覆盖“新增行-删除行-再次新增”的场景。我在实际开发中遇到过一次用户把行项目删了再重新加结果BADI里的内存表还残留着原先的数据导致新行项目带出了上一行已删除的值。解决方式是在GO_ITEM_DELETE里同步清理内存表对应索引的数据。结语MIGO增强说难不难说简单也不简单关键是要吃透SAP为它预留的BADI调用链。我做了这么多年的ABAP开发最大的体会是碰到MIGO这种大程序千万别硬改标准代码也别图省事用老旧的CMOD方式硬塞老老实实走BADI理解清楚方法的调用时机你的增强代码就是可维护的、可传承的。最后再分享一个小技巧如果你不确定BADI里某个方法具体在什么时候被调用直接在方法里写个测试输出或者打一个静态断点用MIGO做一次完整流程操作调试器会告诉你答案。实践出真知胜过翻半天文档。
返回列表