1、研究背景

1.1、业务背景

由于销售、研发、工艺等需要频繁变更,导致工单中组件需要频繁的进行变更,修改组件的物料,数量,库存地点,工序等内容。

1.2、技术痛点

为了满足要求,使用了函数:CO_XT_COMPONENT_ADD和CO_XT_COMPONENT_CHANGE用于组件的新增和修改,使用CO_XT_COMPONENTS_DELETE用于组件的批量删除。

痛点1:新增和修改函数,每次只能更改一行组件,而且无法按照订单维度,批量修改组件,只能按照组件维度,多次调用函数,每一次都需要提交保存一遍工单,效率很慢。

痛点2:项目中在工单修改保存时,调用了同步接口推送工单到MES,且MES必须返回成功结果,工单修改才允许保存。受接口+网络影响,工单保存效率很慢。

痛点3:受制于同步接口等原因,导致工单保存时耗时较长,且一直保持着对工单的锁定状态。而批导程序紧接着处理第二行同一工单的组件数据,就会导致出现工单锁表报错。

2、改造BAPI

2.1、BAPI现状

维护订单的BAPI:BAPI_ALM_ORDER_MAINTAIN,拥有丰富的工单修改字段,然而对于生产订单限制修改,只允许修改维护订单。

另外,经过测试,还有反冲强制取物料主数据内容导致不能指定;组件分配报错问题;组件分配BOM行号重新被指定问题等,需要逐一进行修改。

本文档,对BAPI的改造是否满足读者项目的要求,还需读者多加测试

2.1.1、反冲被默认

在原逻辑中,有赋默认值的函数,里面根据物料主数据对传入的反冲标识做了更改

调用子例程

在以下代码处修改了传入的反冲标识

2.1.2、组件分配

在工单中,工序可以通过主数据带入工艺路线,也可以直接在工单前台手工创建。

问题在于,当在CO02手工创建时,与CA01创建的工序不一样,缺少了部分字段值,最主要的序列字段为空

导致组件分配给30工序后,前台查看组件出现报错,或组件全部丢失,最终判定都是因为序列PLNFL字段为空导致

2.1.3、BOM行项目

标准程序中,会根据要分配的工序,查找已经存在分配给该工序的组件,获取这些组件的最大BOM号,+10获得最新BOM号。

如果当前分配的工序,没有存在已经分配给该工序的组件,则直接+10得到最新BOM号0010。

例如:将0030行分配给20工序,而现有的两个工序都是10,没有20工序的组件,则BOM号0030行分配完之后,BOM号将变为0010

2.1.4、工单类型限制

该BAPI只能修改维护订单,不能修改其他类型工单

2.2、增强改造(未采用)

第一次改造,使用了代码修改器,修改原有逻辑,如下所示:

跳过反冲默认

跳过订单类型限制

但是最终感觉太多的地方要修改,并且从未来持续优化功能的角度出发,写大量的代码片段不是一件好事情,且四代增强也要花很多时间调试,因此打算放弃改源码,而直接做代码拷贝。参考2.3自定义BAPI

2.3、自定义BAPI

根据多次的源码调试,找到程序运行相关的函数、包含文件等,依次进行代码的复制,过程不做过多说明,结果如下:

1、需要复制的函数组及函数,将IBAPI_ALM_ORDER复制为ZBAPI_ALM_ORDER,其余同理

2、ZBAPI_C_DEFAULT_VALUES_01 修改反冲标识

3、LZBAPI_ALM_ORDER_PROCESSINGF10

在AFVC表中,序列PLNFL为空,但是序列APLFL有值,可以使用

在程序中为PLNFL赋值,解决组件分配报错

4、LZBAPI_CF03

注释掉BOM号递增逻辑

5、ZBAPI_H_ORDER_READ

去掉对生产订单的限制

另外在标准逻辑调用过程中上下文需要做修改的程序可以参考3、修改路径图。

3、修改路径图

4、参考源码

调用BAPI代码示例:

"--------------------@斌将军--------------------
LOOP AT lt_alv INTO DATA(ls_alv) GROUP BY ls_alv-aufnr.
REFRESH:lt_methods[],lt_component[],lt_componentup[],lt_return[].
CLEAR:lv_rspos. CLEAR:ls_methods.
ls_methods-refnumber = 1.
ls_methods-method = 'SAVE'.
ls_methods-objectkey = ls_alv-aufnr.
APPEND ls_methods TO lt_methods. LOOP AT GROUP ls_alv ASSIGNING FIELD-SYMBOL(<fs_alv>). READ TABLE gt_resb INTO gs_resb WITH KEY aufnr = <fs_alv>-aufnr
rspos = <fs_alv>-rspos BINARY SEARCH.
IF sy-subrc EQ 0."修改逻辑
IF gs_resb-xloek = 'X'.
<fs_alv>-icon = icon_led_red.
<fs_alv>-log = <fs_alv>-log && '项目已删除,不允许修改'.
MODIFY gt_alv FROM <fs_alv>.
CONTINUE.
ENDIF. IF gs_resb-enmng > abs( gs_alv-bdmng ).
<fs_alv>-icon = icon_led_red.
<fs_alv>-log = <fs_alv>-log && '修改的数量小于已提货数,不允许修改'.
MODIFY gt_alv FROM <fs_alv>.
CONTINUE.
ELSE.
lv_rspos = lv_rspos + 1.
CLEAR:ls_component.
* ls_component-item_number = gs_alv-posnr. "BOM
ls_component-reserv_no = gs_resb-rsnum. "预留号
ls_component-res_item = gs_resb-rspos. "预留项目
ls_component-material = <fs_alv>-idnrk. "物料编码
ls_component-requirement_quantity = <fs_alv>-bdmng."数量
* ls_component-plant = gs_alv-werks.
IF <fs_alv>-lgort IS NOT INITIAL.
ls_component-stge_loc = <fs_alv>-lgort."存储地点
ENDIF. ls_component-batch = <fs_alv>-charg."批次号
ls_component-req_date = <fs_alv>-bdter."组件的需求日期
IF <fs_alv>-rgekz IS NOT INITIAL.
ls_component-backflush = 'X'."反冲标识
ELSE.
ls_component-backflush = ''."反冲标识
ENDIF.
ls_component-special_stock = <fs_alv>-sobkz."特殊库存
ls_component-activity = gs_resb-vornr."操作/活动编号
APPEND ls_component TO lt_component. CLEAR:ls_componentup.
* ls_componentup-item_number = 'X'. "BOM
ls_componentup-material = 'X'. "物料编码
ls_componentup-requirement_quantity = 'X'."数量
* ls_componentup-plant = 'X'.
IF <fs_alv>-lgort IS NOT INITIAL.
ls_componentup-stge_loc = 'X'."存储地点
ENDIF.
ls_componentup-batch = 'X'."批次号
ls_componentup-req_date = 'X'."组件的需求日期
ls_componentup-backflush = 'X'."反冲标识
ls_componentup-special_stock = 'X'."特殊库存
APPEND ls_componentup TO lt_componentup. CLEAR:ls_methods.
ls_methods-refnumber = lv_rspos. "参照组件编号
ls_methods-objecttype = 'COMPONENT'. "组件
ls_methods-method = 'CHANGE'. "修改
ls_methods-objectkey = <fs_alv>-aufnr. "订单号
ls_methods-objectkey+12(4) = gs_resb-rspos. "预留行
APPEND ls_methods TO lt_methods. "组件分配
IF <fs_alv>-vornr IS NOT INITIAL.
lv_rspos = lv_rspos + 1.
CLEAR:ls_component.
ls_component-reserv_no = gs_resb-rsnum. "预留号
ls_component-res_item = gs_resb-rspos. "预留项目
ls_component-activity = <fs_alv>-vornr."新分配的工序
APPEND ls_component TO lt_component. CLEAR:ls_componentup.
ls_componentup-activity = 'X'.
APPEND ls_componentup TO lt_componentup. CLEAR:ls_methods.
ls_methods-refnumber = lv_rspos. "参照组件编号
ls_methods-objecttype = 'COMPONENT'. "组件
ls_methods-method = 'REASSIGN'. "重新分配
ls_methods-objectkey = <fs_alv>-aufnr. "订单号
ls_methods-objectkey+12(4) = gs_resb-rspos. "预留行
APPEND ls_methods TO lt_methods.
ENDIF.
ENDIF.
ELSE."新增逻辑
lv_rspos = lv_rspos + 1. CLEAR:ls_component.
ls_component-item_number = <fs_alv>-posnr. "BOM
ls_component-material = <fs_alv>-idnrk. "物料编码
ls_component-requirement_quantity = <fs_alv>-bdmng."数量
ls_component-plant = <fs_alv>-werks."工厂
ls_component-stge_loc = <fs_alv>-lgort."存储地点
ls_component-batch = <fs_alv>-charg."批次
ls_component-req_date = <fs_alv>-bdter."组件的需求日期
IF <fs_alv>-rgekz IS NOT INITIAL.
ls_component-backflush = 'X'."反冲标识
ELSE.
ls_component-backflush = ''."反冲标识
ENDIF.
ls_component-special_stock = <fs_alv>-sobkz."特殊库存
ls_component-activity = <fs_alv>-vornr."工序
ls_component-item_cat = 'L'."项目类别
APPEND ls_component TO lt_component. CLEAR:ls_componentup.
ls_componentup-item_number = 'X'. "BOM
ls_componentup-material = 'X'. "物料编码
ls_componentup-requirement_quantity = 'X'."数量
ls_componentup-plant = 'X'."工厂
ls_componentup-stge_loc = 'X'."存储地点
ls_componentup-batch = 'X'."批次
ls_componentup-req_date = 'X'."组件的需求日期
ls_componentup-backflush = 'X'."反冲标识
ls_componentup-special_stock = 'X'."特殊库存
ls_componentup-activity = 'X'."工序
ls_componentup-item_cat = 'X'."项目类别
APPEND ls_componentup TO lt_componentup. CLEAR:ls_methods.
ls_methods-refnumber = lv_rspos. "参照组件编号
ls_methods-objecttype = 'COMPONENT'. "组件
ls_methods-method = 'CREATE'. "创建
ls_methods-objectkey = <fs_alv>-aufnr. "订单号
APPEND ls_methods TO lt_methods.
ENDIF.
ENDLOOP. READ TABLE gt_afko INTO DATA(ls_afko) WITH KEY aufnr = ls_alv-aufnr BINARY SEARCH.
IF sy-subrc EQ 0.
CALL FUNCTION 'T350_READ'
EXPORTING
auart = ls_afko-auart
EXCEPTIONS
no_t350_entry = 1
OTHERS = 2. * override buffered table T350
ASSIGN ('(SAPLINST)T350') TO <t350>.
IF sy-subrc = 0.
<t350>-auart = ls_afko-auart.
ENDIF.
ENDIF. "调用ZBAPI
CALL FUNCTION 'ZBAPI_ALM_ORDER_MAINTAIN'
TABLES
it_methods = lt_methods
it_component = lt_component[]
it_component_up = lt_componentup[]
return = lt_return. CLEAR:lv_check,lv_message.
LOOP AT lt_return INTO ls_return WHERE type CA 'AEX'.
lv_check = 'E'.
lv_message = lv_message && ls_return-message.
CLEAR:ls_return.
ENDLOOP. IF lv_check = 'E'.
CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'. ls_alv-icon = icon_led_red.
ls_alv-log = lv_message. ELSE.
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
EXPORTING
wait = 'X'.
ls_alv-icon = icon_led_green.
ls_alv-log = '添加成功'.
ENDIF.
MODIFY gt_alv FROM ls_alv TRANSPORTING icon log WHERE aufnr = ls_alv-aufnr
AND xloek = ''
AND item = 'X'
AND icon <> icon_led_red. CLEAR:ls_alv.
ENDLOOP.
"--------------------@斌将军--------------------

5、补充说明

5.1、并行工序组件分配研究

对读者提出的该BAPI改造后是否能进行并行工序组件分配进行了研究。

在组件分配过程中,程序调用了函数CO_BT_READ_MASTER_SEQUENCE,通过工单编号,查询对应的序列信息

但是函数中通过常量限制了序列为0,即只查找标准顺序,不查找并行顺序

导致获取的序列值为000000,

导致查询AFVC数据时,获取到标准顺序0的工序,而不是并行顺序1的工序

综上所述,认为直接使用该函数无法进行并行工序的组件分配。

但是源代码逻辑已经梳理很清晰,想必稍加改造,例如直接抛内存传值,查询对应的并行顺序的工序,应该就可以解决问题。

读者有兴趣可自行研究一下。

定期更文,欢迎关注

关于改造维护工单BAPI_ALM_ORDER_MAINTAIN用于生产订单组件批量修改的更多相关文章

  1. PP篇11 增、改生产订单组件BAPI

    增.改生产订单组件BAPI BAPI_ALM_ORDER_MAINTAIN USE BAPI_ALM_ORDER_MAINTAIN TO CREATE OR CHANGE PM WORK ORDER ...

  2. 增、改生产订单组件BAPI BAPI_ALM_ORDER_MAINTAIN

    转载留存 IT_METHODS    LIKE    BAPI_ALM_ORDER_METHOD处理方法,必选项,存储CREATE CREATETONOTIF CHANGE DELETE RELEAS ...

  3. SAP PP 生产订单变更记录保存

    *&---------------------------------------------------------------------* *& 包括 ZXCO1U01 *&am ...

  4. 部署用于生产的Exceptionlees(一个强大易用的日志收集服务)

    Exceptionless是一个非常优秀的事件记录服务,目前我们的自部署的Exceptionless已经稳定运行了近一年的时间,收集了千万条事件信息.但Exceptionless官方自宿主部署的文档不 ...

  5. 基于redis的分布式锁(不适合用于生产环境)

    基于redis的分布式锁 1 介绍 这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁.会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁. 本篇文章会将分布式锁的实现分 ...

  6. mysql_secure_installation 安全安装(用于生产环境设置)

    编译安装完mysql5.6,如果用于生产环境,最好执行mysql_secure_installation来做一些常规化安全设置. 需要提前将~mysql/bin加入环境变量 /apps/mysql// ...

  7. 【ABAP系列】SAP 生产订单完工确认(CO11N) BAPI : BAPI_PRODORDCONF_CREATE_TT

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP 生产订单完工确认(CO1 ...

  8. PP生产订单创建、下达、报工、收货、投料

    转自http://blog.sina.com.cn/s/blog_69fb8eb60102vpjd.html SAP 物料订单创建.下达.报工.收货与投料(ABAP代码) (2015-06-03 22 ...

  9. PP生产订单的BADI增强 WORKORDER_UPDATE

    METHOD if_ex_workorder_update~before_update. *---------------------->增强1 开始* "当生产订单类型为PP01时, ...

  10. SAP 生产订单变更管理 OCM Order Changement Management

    SAP OCM Order Changement Management  一.目的 订单变更管理系统是当我们的订单(生产订单.计划订单.采购订单)已经存在的时候,其物料主数据或销售数据有变更时,我们可 ...

随机推荐

  1. 聊聊分布式 SQL 数据库Doris(二)

    Doris中,Leader节点与非Leader节点和Observer节点之间的元数据高可用和一致性,是通过bdbje(全称:Oracle Berkeley DB Java Edition)的一致性和高 ...

  2. RIPEMD加密技术

    摘要:RIPEMD(RACE Integrity Primitives Evaluation Message Digest)是一种密码散列函数,广泛应用于网络安全领域.本文首先介绍RIPEMD的起源和 ...

  3. 线性代数导论MIT第二章知识点上

    线性代数导论MIT第二章求解线性方程组 2.1--2.2知识点 1.向量与线性方程组 2.不同角度看方程式 也就是矩阵的乘法原型: 以行来看方程式就是原式 以列来看方程式 以矩阵来看方程式 3.消元法 ...

  4. 轻松应对复杂集成场景!用友U8API开发适配

    在企业上云的大趋势下,U8+ 全面转向互联网方向,深入融合云应用,一站式提供财务.营销.制造.采购.设计.协同.人力等领域的"端 + 云"服务,并通过软硬一体化.产业链协同的策略全 ...

  5. 黑客玩具入门——2、Kali常用命令与简单工具

    一.Linux常用命令 首先,我们启动kali系统,然后点击这里的命令行工具. 就可以使用下面学习的命令了,另外,如果你有过计算机基础,那么Mac的terminal和Git的gitbash,都是可以练 ...

  6. Java 21 官方速览:全面拥抱虚拟线程

    前言 首先,感谢一下不少xdm私信关心我的身体状况,我也不是什么厉害的大佬,点开通知看到一堆私信还是蛮感动的. 近来有意大幅缩短了更新频率,增加了日常调养身体的时间,淋巴结确实变小了,睡眠也逐渐正常, ...

  7. 为什么MySQL不建议使用delete删除数据?

    MySQL并不直接建议禁止使用DELETE语句删除数据,但是在某些情况下,使用DELETE可能会带来一些潜在的问题,特别是在大型数据库中. 下面我将详细介绍为什么在某些情况下MySQL不建议过度使用D ...

  8. 大数据 - MapReduce:从原理到实战的全面指南

    本文深入探讨了MapReduce的各个方面,从基础概念和工作原理到编程模型和实际应用场景,最后专注于性能优化的最佳实践. 关注[TechLeadCloud],分享互联网架构.云服务技术的全维度知识.作 ...

  9. Gson和fastJson应用场景

      如果有性能上面的要求可以使用Gson将bean转换json确保数据的正确,使用FastJson将Json转换Bean 二.Google的Gson包的使用简介. Gson类:解析json的最基础的工 ...

  10. java-图片添加水印

    前言:    需求:需要在图片中添加水印,防止盗用   优缺点:     优点:保护版权,防止盗用     缺点 可能会影响图片的视觉效果:如果水印过大或过醒目,可能会影响图片的视觉效果. 可能会增加 ...