ARTICLE DETAIL

资讯详情

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

SAP凭证替代与AC_DOCUMENT BADI:VF01/MIRO利润中心自动填充实战

SAP凭证替代与AC_DOCUMENT BADI:VF01/MIRO利润中心自动填充实战 做SAP财务模块顾问或者ABAPer的应该都碰过这种事月底财务往系统里录发票VF01冲了一批销售发票MIRO录了一批供应商发票结果过账之后一看凭证利润中心是空的功能范围乱套成本中心对不上。查了几层发现标准功能锁得太死用户又不想手工一个一个填。这时候最稳妥的做法就是用凭证替代加AC_DOCUMENT BADI把字段自动带出来。这篇我把自己在VF01和MIRO上配置凭证替代、写AC_DOCUMENT BADI增强的整套经验整理出来包括GGB1配置步骤、替代分配方法、完整的ABAP代码示例和排错技巧适合正在做SD/FI增强的ABAPer看。1. 凭证替代到底解决什么问题1.1 VF01和MIRO过账时的真实痛点先明确一个概念VF01是销售发票过账MIRO是采购发票校验。这俩事务码看着分属SD和MM但最终都会生成财务会计凭证也就是FI凭证。对FI顾问来说麻烦就出在这个“最终”上——用户销售发货后执行VF01供应商月结后执行MIRO系统按标准逻辑生成的凭证里很多管理维度是空白或者不对的。举几个我实际遇到过的例子。第一个销售发票过账后利润中心是空的。因为物料发票关联的成本对象没有正确传到BI或者行项目里压根没带出PRCTR。月底CO模块做利润中心报表的时候数据对不上财务天天找人补录。第二个MIRO过账时供应商行项目里的功能范围FBUDA是错的。采购订单行项目明明有这个字段但发票校验过账时没有被正确复制结果CO内部订单归集出问题。第三个场景更典型同一个供应商有几笔发票要记到不同的事业部用户希望根据金额大小或采购订单来源自动分配利润中心手工改效率太低容易错。这些需求都有两条路可以走。要么在过账前让用户手工维护要么通过增强自动带出。生产环境下让用户手工改百分之百会出乱子所以我一般直接走自动化。SAP里现成的自动化工具就是凭证替代也就是Substitution。碰到标准替代搞不定的再上AC_DOCUMENT BADI写代码。1.2 替代与校验的分工逻辑很多刚接触这块的ABAPer会把替代和校验搞混我先帮大家理一下。校验Validation是检查凭证过账前某个条件是否满足不满足就报错拦截这个过账动作。替代Substitution则是满足某个条件后把凭证上的某个字段值自动替换成预设值过账继续执行只是字段内容变了。设计上替代更符合“自动带出字段”这类需求。比如设置一个规则当公司代码是1000、过账码是31时把利润中心替换成P1000。替代有一套标准配置界面不需要写代码实施顾问自己就能维护。校验也很好用比如检查凭证金额不能为负数或者供应商主数据里必须有税号不满足就抛错。但校验的定位是“把关”不是“赋值”。执行顺序上SAP在会计凭证创建时会先跑校验再跑替代然后在更新数据库前还有其他增强点。如果校验和替代同时配置了校验的公式会因为替代修改过的字段值重新判断。这块后面讲Debug定位时还会提到总之不要以为校验看到的值就是输入界面上原始的值很可能已经被替代改过了。1.3 什么时候用标准替代什么时候上BADI标准替代GGB1配置优点是直观、维护成本低、顾问自己能改缺点是能改的字段有限条件公式的写法也有限制。BADI则几乎可以改任意字段能做任意复杂的逻辑判断可以读表、调用函数缺点是必须写ABAP代码还要考虑传输和权限。我的选型原则很简单如果只是根据公司代码、过账码、科目这样的基础字段做一对一替换优先用GGB1省事。如果涉及跨表取数、动态逻辑判断、需要根据多条件组合决定字段值或者要读采购订单、客户主数据、销售订单来补充凭证字段那就直接用AC_DOCUMENT BADI。还有一个统一考量同一个需求如果既要改头又要改行或要改多个字段BADI明显比在GGB1里维护一堆步骤要清爽。还有一个重要原因让我更倾向于在S/4HANA环境里用AC_DOCUMENT BADI标准替代在S4里虽然还支持但SAP更推荐用新增强点来做扩展而且AC_DOCUMENT BADI的执行时机稳定不受替代步骤顺序影响。一句话简单的用标准配置复杂的用BADI两者不冲突甚至可以同时存在。2. 凭证替代的标准配置流程保姆级步骤2.1 先认识GGB1和OBBH这两个事务码替代相关的事务码不多核心就是GGB1和OBBH。GGB1用来维护替代规则本身比如定义替代的名称、步骤、条件公式和要替换的字段值。OBBH用来把替代分配给具体的公司代码和调用点。可以理解为GGB1是“写规则”OBBH是“挂规则”。少了任何一步替代都不会生效。在GGB1里你会看到左半边是替代列表右半边是步骤列表。一个替代下面可以挂多步Step每一步里有两个关键内容前置条件Prerequisite和替代规则Substitution。前置条件是一个逻辑表达式只有为真时这个步骤里的替代规则才会执行。系统会从上往下依次检查步骤步骤之间用步骤号区分。OBBH的界面则是维护一张分配表把替代名称、公司代码、调用点组合起来。调用点可以理解成“替代在哪种业务场景下触发”常见的会计凭证相关的调用点是01对应VF01和MIRO最终生成FI凭证那一下。具体值以你系统里配置为准因为不同行业模板会自定义调用点。2.2 用GGB1定义替代规则从零开始配置我现在以一个实际配置为例公司代码1000下MIRO过账产生的供应商行项目过账码31如果成本中心为空自动把利润中心替换成P1000。步骤一进入GGB1点新建或复制标准替代输入替代名称比如ZFI_MIRO_PRCTR。描述写上“MIRO凭证替代-利润中心自动带出”保存。步骤二创建步骤号10。双击步骤号进入编辑画面。前置条件写BUKRS 1000 AND BSCHL 31。注意这里用的是内部字段名不是显示名称。字段名可以用插入按钮从数据字典里选择或者直接输入。BUKRS是公司代码BSCHL是过账码这两个是替代里最常用的判断字段。步骤三维护替代规则。在替代规则框中选择或填写PRCTR P1000。意思就是满足了上面的前置条件后把利润中心字段值设为P1000。如果你还想设置其他字段可以继续加行。但要注意不是所有字段都能被替代系统会有一个可替代字段列表选不到的就是不允许替代。步骤四保存并激活。GGB1里维护的规则保存后不一定直接生效必须点激活按钮状态才会变成已激活。这一步很容易漏我见过好多项目上了传输结果代码激活了规则没激活半天排查不出来。再补充一个常见写法如果你想限制只在MIRO供应商发票类型的凭证内生效可以加一个凭证类型字段BLART的判断但注意MIR0生成的是KR凭证还是RE凭证不同版本有区别测试前最好先在调试里确认凭证类型。2.3 用OBBH把替代挂到公司代码和调用点GGB1维护完规则下面就是OBBH分配。进入OBBH后左边是调用点列表右边是分配明细。选择调用点01或根据你项目定义好的调用点点新建输入公司代码1000和之前创建的替代名称ZFI_MIRO_PRCTR保存。这里有几个坑。第一个替代名称不要搞错大小写或者前后空格SAP里这个字段是严格按照输入值匹配的。第二个公司代码如果没分配替换不会触发但系统也不会给你报错。第三替代可以分配给多个公司代码如果公司代码很多建议事务码OBBH里集中维护不要每个公司代码单独建一套规则否则后面维护成本高。分配完成后可以用标准事务码GCBX来跟踪替代的执行情况。不过说实话跟踪界面不算好用我更喜欢用调试器直接看。替代是在凭证过账的某个标准函数里执行的你只要在前面放一个断点替换发生时就能看到替代前后的字段值变化。调试技巧后面第四章详细写。2.4 验证替代是否生效VF02/VF03实操演示配置完不能光看不跑我用VF02或VF03来做验证比较快。先创建一笔测试销售发票VF01直接过账然后VF03查看凭证检查行项目里的利润中心是不是自动带出来了。MIRO的话找一个测试供应商发票过账再用FB03查看财务会计凭证。如果替代没生效第一步查OBBH分配第二步查替代的激活状态第三步查前置条件是否真的满足。我经常遇到一种情况用户在GGB1里写的公司代码是文本字段但实际业务传过来的可能是带前导零的这时候条件就匹配不上。比如BUKRS 1000和BUKRS 00001000虽然都是同一个公司代码但在替代公式里比较时不一定相等。写条件的时候尽量用系统里显示的值或者先跑一遍程序看清楚字段实际值。另外验证时记得清数据库缓冲尤其是配置刚激活未做传输的时候最好在实施系统上用SM30的“生成”按钮更新缓存或者直接登出重进避免看到旧配置。3. 用AC_DOCUMENT BADI做更灵活的替代增强3.1 为什么SAP会单独留一个BADI给会计凭证GGB1替代在标准字段内很好用但一旦涉及跨表取数、动态逻辑判断就力不从心了。比如从EKPO采购订单行项目里取利润中心或者从客户主数据里取销售组织对应的功能范围这些逻辑没法在替代公式里维护。这时就需要一个真正的代码入口。SAP在标准会计凭证创建流程中预留了AC_DOCUMENT这个BADI。它在凭证过账前执行允许开发人员读取凭证头和行项目信息同时可以修改这些信息。你可以理解成替代是给顾问在配置界面上用的“傻瓜相机”AC_DOCUMENT BADI则是给ABAPer的“单反机身”镜头、光圈、快门全由代码控制。在S/4HANA及后续版本中AC_DOCUMENT BADI已经覆盖了大部分传统会计凭证增强的场景。我在ECC升级到S4的项目里做过不少迁移很多原先挂在标准函数后面的老式增强逻辑都逐步搬到了这个BADI里。原因也很直接老式隐式增强点版本一升级就可能失效而BADI是SAP公开支持的增强接口相对稳定。3.2 AC_DOCUMENT BADI的实现步骤第一步SE18输入BADI名称AC_DOCUMENT查看定义。你会看到它有一个方法CHANGE接口名一般是IF_EX_AC_DOCUMENT。双击方法可以查看参数ID_AC_HEADER传入凭证头IT_AC_ITEMS传入原始行项目列表CS_AC_HEADER允许修改凭证头CT_AC_ITEMS允许修改行项目列表。实际开发中我90%的操作都在CT_AC_ITEMS上完成。第二步SE19创建BADI实现。输入一个实现名称比如ZCL_AC_DOCUMENT_IMPL然后选择参考BADI定义AC_DOCUMENT进入接口编辑器后系统会自动生成实现类框架。第三步在方法CHANGE里写代码。写完后激活实现类。这一步如果有语法错误会直接拦截激活成功后在SE19里实现状态会显示为“已实现”。第四步验证。直接用VF01或MIRO过账测试不需要额外配置。需要注意的是如果这个BADI在系统里已经存在其他实现你的实现必须考虑多个实现的情况。AC_DOCUMENT作为一个多用途BADI理论上可以注册多个实现执行顺序按SE19里的排序。不要让多个实现之间逻辑互踩否则排查起来非常痛苦。3.3 完整代码示例MIRO场景自动带利润中心下面我贴一段我实际用得最多的逻辑MIRO过账时如果凭证行项目里有供应商就按照“采购订单利润中心优先供应商主数据利润中心兜底最后默认值收尾”的顺序自动填充PRCTR。CLASS ZCL_AC_DOCUMENT_IMPL DEFINITION PUBLIC CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_ex_ac_document . PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS ZCL_AC_DOCUMENT_IMPL IMPLEMENTATION. METHOD if_ex_ac_document~change. DATA: ls_lfa1 TYPE lfa1, lv_prctr TYPE prctr. FIELD-SYMBOLS: fs_item LIKE LINE OF ct_ac_items. LOOP AT ct_ac_items ASSIGNING fs_item. 只处理供应商行项目 CHECK fs_item-lifnr IS NOT INITIAL. 1. 如果凭证行项目上有采购订单号优先从EKPO取利润中心 IF fs_item-ebeln IS NOT INITIAL. SELECT SINGLE prctr FROM ekpo INTO lv_prctr WHERE ebeln fs_item-ebeln AND ebelp fs_item-ebelp. IF sy-subrc 0 AND lv_prctr IS NOT INITIAL. fs_item-prctr lv_prctr. CONTINUE. ENDIF. ENDIF. 2. 如果采购订单没取到或没有采购订单从供应商主数据LFA1读取 CLEAR lv_prctr. SELECT SINGLE prctr FROM lfa1 INTO ls_lfa1-prctr WHERE lifnr fs_item-lifnr. IF sy-subrc 0 AND ls_lfa1-prctr IS NOT INITIAL. fs_item-prctr ls_lfa1-prctr. CONTINUE. ENDIF. 3. 最后兜底给一个默认利润中心避免字段空白 IF fs_item-prctr IS INITIAL. fs_item-prctr P1000. ENDIF. ENDLOOP. ENDMETHOD. ENDCLASS.这套逻辑解决的是最典型的MIRO场景。实际项目里可以在这个基础上扩展比如按公司代码分支、按供应商行业分支、或者结合采购订单抬头上的字段做更细的判断。需要注意AC_DOCUMENT BADI里对CT_AC_ITEMS的修改只影响后续过账步骤显示的凭证行项目不代表所有字段都能无限制改有些核心字段系统仍会做一致性校验改坏了会报错。3.4 代码要点解析与VF01场景扩展首先要注意CHECK语句的位置。我放在LIFNR非空的判断确保不会去处理总账科目行或者客户行。如果你在VF01里判断条件就要改成客户不为空比如KUNNR IS NOT INITIAL因为销售发票的往来单位是客户不是供应商。第二采购订单取利润中心时EBELN和EBELP在ACC_ITEM结构里存在但有些过账路径下可能没传上来。如果DEBUG时发现EBELN为空可以退回从BSEG底表取或者在调用点前面的功能里找。这也是为什么我在代码里用IF判断绕过空值避免SELECT条件带空值导致全线失败。第三从EKPO和LFA1取利润中心只是两种最常见的来源。更复杂的场景可能是从物料主数据、项目定义WBS、销售订单行项目里取。方法都差不多先SELECT再赋值给fs_item-prctr。但要注意性能虽然凭证行项目不会大到几千行但SELECT写在循环里也要保证能走到索引。比如EKPO本身主键就是EBELNEBELP效率没问题。第四如果同一笔MIRO里既有采购订单行的应付也有无采购订单的费用行那费用行就没有EBELN代码会自动走到供应商主数据兜底。如果你希望费用行走成本中心而不是利润中心可以再加一个KOSTL的赋值逻辑具体看业务。第五关于VF01场景的扩展。销售发票过账一般不会从采购订单取数更多的是从销售订单、交货单或者物料主数据带出。例如通过VBRK-VBELN找到销售订单再读VBAP利润中心字段赋给凭证行项目。这个逻辑不算复杂但要注意标准销售发票里凭证行项目可能没有类似EBELN的字段直接存储销售订单号这时候需要从VBRP或接口结构里反查也可以借助凭证中的参考字段。说到底只要理解AC_DOCUMENT BADI的赋值模式剩下的都是数据源的问题。4. 常见问题与排查技巧实录4.1 替代不生效的排查思路这个我在前面多少提过这里系统整理一遍排查顺序。第一步检查OBBH分配。确认公司代码和调用点都正确。我遇到过项目里同时存在两个调用点一个叫01一个叫Z1业务凭证实际走的是Z1结果顾问在01上配置了好几天白费功夫。第二步检查替代的激活状态。GGB1里看替代名称前的小图标是灰色的还是黄色的未激活是灰的。务必点激活。另外如果通过传输请求传输配置不同系统间激活状态可能不一致生产环境里照样要检查。第三步检查前置条件。把业务凭证里实际的字段值拉出来和条件公式对比。用调试最直接在标准程序调用替代的位置设断点看传递进去的凭证结构里BUKRS、BSCHL这些值到底是什么。重点检查前导零、空格、大小写这类肉眼容易忽略的问题。第四步确认替代字段是否在允许范围内。如果替换规则里设置了一个字段但这个字段不在系统允许替代的字段列表内替代执行时会直接被跳过不会报错。这属于沉默失败特别坑。4.2 BADI不触发的定位方法确认BADI实现已激活确认接口方法确实在CHANGE里打了断点然后重新执行VF01或MIRO。如果断点没停下来从下面三个方向查。第一个BADI实现有没有过滤器。AC_DOCUMENT支持过滤器值如果你在SE19里维护了过滤器只有满足调用条件时实现才触发。常见误操作是过滤器值本来为空结果被误填了一个公司代码导致其他公司代码的凭证不触发。第二个系统里是否已经有另一个实现提前改变了凭证类型或动作导致你的实现被跳过。比如前一个实现直接RETURN了或者修改了凭证类型后后一个实现认为不是自己该处理的场景。这时候需要调整实现顺序或者干脆在方法开头再加上自己的场景判断防止被别人带偏。第三个BADI的调用位置有没有因为SPRING增强或用户出口被绕过。这种情况少见但排查思路是直接用WHERE-USED-LIST查标准程序中调用AC_DOCUMENT的地方确认当前过账代码路径是否经过这段逻辑。我在S4HANA项目里碰到过一次某个自定义过账程序没有走标准会计凭证接口而是直写BSEGAC_DOCUMENT自然不触发最后用客户增强绕回到标准接口处理了。调试方面我强烈建议在方法CHANGE第一行打外部断点再配合事务码ST05或SAT做SQL跟踪一层一层看执行路径。这一套下来基本能定位95%的问题。4.3 排查速查表与独家避坑技巧问题现象可能原因排查方法解决思路GGB1替代完全不生效OBBH未分配公司代码检查OBBH分配表维护公司代码和调用点GGB1替代不生效替代规则未激活GGB1查看激活状态点激活并保存条件公式始终不满足字段名用错或前导零差异调试看实际字段值改用系统内部字段名统一前导零替换字段没变也没报错字段不在允许替代列表GGB1字段列表检索改用AC_DOCUMENT BADIBADI方法未触发过滤器不匹配SE19查看过滤器值调整过滤器或移除BADI方法触发但字段未变字段在后续步骤被覆盖在标准程序后续位置打断点调整赋值逻辑或控制执行顺序凭证过账报错修改了关键字段导致一致性校验失败查看错误日志或调试只改必要字段做值域检查我再分享两个独家避坑技巧。第一个不管是用GGB1还是BADI都要注意凭证行的“补充”逻辑——很多字段是可以在行项目里带两个不同值的比如同一个贷款凭证行项目既有利润中心又有功能范围业务上可能希望能从不同来源分别填充。如果写代码只覆盖PRCTR另一个字段被标准逻辑生成了错误值月底照样对不上。所以第一批上线前一定把关键行项目的字段梳理一遍做一个“字段填充对照表”哪些由标准逻辑带哪些由替代带哪些由BADI带确认之后才能上线。第二个我常在BADI里加一个自定义日志点。在方法CHANGE里对修改过的行项目写一条应用日志存到Z表里内容包含凭证号、行项目号、填充前值、填充后值、处理时间。生产环境上线初期这个日志特别有用能帮你快速回答“为什么这行没带到利润中心”这种问题。等项目稳定后可以再决定是保留还是定期清空。5. 最后再分享几个实操细节上面这套流程我在五六个项目里用过有ECC也有S/4HANA整体逻辑是通用的。但每一次切换系统我都会把GGB1的替代和AC_DOCUMENT BADI的执行顺序再确认一遍不因为上次能用就直接照搬。一个容易忽略的细节是AC_DOCUMENT BADI里如果修改了利润中心后续的CO对象分配、成本要素过账等逻辑都会跟着变。所以改动之前一定要和模块顾问确认影响范围别只盯着FI凭证本身。另一个细节是版本升级。S4HANA的后续版本对AC_DOCUMENT的参数结构有时会微调升级前最好重新查看SE18的接口定义避免按老版本的字段名写代码导致编译错误。一般来讲标准字段如LIFNR、PRCTR、EBELN这类变化不大但涉及新启用的字段比如业务伙伴、会计原则等写法就会有差异。最后再分享一个提高开发效率的小技巧我会在SE19的实现里先把常用字段的取值逻辑封装成私有方法比如GET_PRCTR_FROM_PO、GET_PRCTR_FROM_VENDOR这样主方法CHANGE看着非常清爽后续业务要换数据来源只改私有方法就行。这个习惯帮我省了不少维护时间。
返回列表