当前位置:   article > 正文

SAP PP 生产订单创建添加定制组件的ABAP实现方法_abap 生产订单组件

abap 生产订单组件

背景

此文适合对SAP PP模块生产订单业务有一定了解的PP顾问和ABAP开发人员阅读。

所在项目中遇到一个特殊需求,创建拆解工单时,拆除整机得到半成品和原材料。

这时候不是增加组件预留数量,而是减少预留数量(因为半成品和原材料增多了),业务方的要求是,这种特殊类型工单,组件数量默认是负数。说实话这种需求我见过,这种解决方案我是第一次听说(更别提见)。为什么不用物料凭证移动类型配置,同仓转储之类的成熟解决方案,我不知道,大概是财务科目配不明白吧。

OK,我的任务是实现需求,别的咱也不知道,咱也不敢问。

需求是通过接口创建拆解工单,组件物料是定制的,数量是负的。

有点绕的解决方案

我之前(差不多10年前)一直用一个标准BAPI处理PP生产订单的增删改,就是BAPI_ALM_ORDER_MAINTAIN。

实际上这是一个PM模块维修/服务工单使用的BAPI,SAP的PP,PM,PS模块使用了同一套底表来存储业务数据(问就是架构原因,我也不知道为什么),所以这个API也能够用来处理PP生产订单。为什么非得用PM的API来改PP的数据呢,因为PP模块没有相应功能的API,自带的BAPI_PRODORD_CREATE没有什么考虑定制组件之类的功能,SAP就是摆烂,OK?

SAP曾推出过一系列Note补丁,禁止客户开发人员使用这个BAPI改生产订单,都被我司的BASIS同事屏蔽了,所以我们一直这么用。

我在目前项目的系统一看,BAPI_ALM_ORDER_MAINTAIN这个BAPI不能用了。Note打了好几波,摘都摘不掉。

接口使用的账号不是dialog账号,不能支持BDC的CO01方式,只能另想办法。

最终考虑,使用COXT函数组的CO_XT_COMPONENT_ADD来添加定制组件和加工数量(负数)。

方案细节

  1. 先调用BAPI_PRODORD_CREATE创建生产订单,这一步会自动生成加工组件,不能定制。

这一步会根据表头的物料,工厂,订单类型,数量,计划起始/截止日期生成生产订单,同时会根据订单物料对应的生产BOM自动计算加工组件物料和数量,按常规方式不能改(非常规可以,我们下面聊)。

我们需要做的是,删除不需要的“自动计算”出来的组件,替换成需要的定制组件。

  1. FORM create_ppo.
  2. DATA:ls_orderdata TYPE bapi_pp_order_create,
  3. ls_return TYPE bapiret2,
  4. lv_order_number TYPE aufnr.
  5. * 创建生产订单
  6. CLEAR:ls_orderdata.
  7. ls_orderdata-material = gs_h-matnr.
  8. ls_orderdata-plant = gs_h-dwerk.
  9. ls_orderdata-order_type = gs_h-auart.
  10. ls_orderdata-quantity = gs_h-pgmng.
  11. ls_orderdata-basic_start_date = gs_h-gstrp.
  12. ls_orderdata-basic_end_date = gs_h-gltrp.
  13. CALL FUNCTION 'BAPI_PRODORD_CREATE'
  14. EXPORTING
  15. orderdata = ls_orderdata
  16. IMPORTING
  17. return = ls_return
  18. order_number = lv_order_number.
  19. IF ls_return-type = 'E'.
  20. CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
  21. MESSAGE ID ls_return-id
  22. TYPE ls_return-type
  23. NUMBER ls_return-number
  24. WITH ls_return-message_v1
  25. ls_return-message_v2
  26. ls_return-message_v3
  27. ls_return-message_v4.
  28. ELSE.
  29. CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
  30. EXPORTING
  31. wait = 'X'.
  32. ENDIF.
  33. DO 10 TIMES.
  34. SELECT COUNT(*)
  35. FROM aufk
  36. WHERE aufnr = lv_order_number.
  37. IF sy-subrc = 0.
  38. EXIT.
  39. ELSE.
  40. WAIT UP TO 1 SECONDS.
  41. ENDIF.
  42. ENDDO.
  43. * 由于生产订单创建时自动生成组件,需要先清空组件
  44. PERFORM delete_components USING lv_order_number.
  45. * 添加需要的组件
  46. PERFORM add_components USING lv_order_number.
  47. * 没有抛出错误消息,证明工单操作成功
  48. MESSAGE S100(CO) WITH lv_order_number.
  49. LEAVE TO SCREEN 0.
  50. ENDFORM.

2. 删除已存在的订单组件

这里需要调用CO_XT_COMPONENTS_DELETE这函数,删除工单对应RESB预留表中所有已存在组件。

COXT函数组的一些函数使用时,需要执行CO_XT_ORDER_PREPARE_COMMIT预提交,正式提交后需要执行CO_XT_ORDER_INITIALIZE再次初始化,这一点和PS模块的一些API类似(毕竟是同一套底表)。

  1. FORM delete_components USING pv_order_number TYPE aufnr.
  2. *** Deleting Components from Production Order
  3. DATA: lt_resbkeys TYPE coxt_t_resbdel,
  4. lt_return TYPE STANDARD TABLE OF bapiret2,
  5. ls_return TYPE bapiret2,
  6. lv_error TYPE flag,
  7. ls_bapireturn TYPE coxt_bapireturn.
  8. * Fetch existing components of given Production Order
  9. SELECT rsnum, rspos INTO TABLE @DATA(lt_resb)
  10. FROM resb
  11. WHERE aufnr = @pv_order_number. " Previously created order
  12. IF sy-subrc EQ 0.
  13. lt_resbkeys = CORRESPONDING #( lt_resb ).
  14. ENDIF.
  15. IF NOT lt_resbkeys[] IS INITIAL.
  16. * BAPI to delete the components of Production Order
  17. CALL FUNCTION 'CO_XT_COMPONENTS_DELETE'
  18. EXPORTING
  19. it_resbkeys_to_delete = lt_resbkeys
  20. IMPORTING
  21. e_error_occurred = lv_error
  22. TABLES
  23. ct_bapireturn = lt_return
  24. EXCEPTIONS
  25. delete_failed = 1
  26. OTHERS = 2.
  27. IF lv_error = space.
  28. CALL FUNCTION 'CO_XT_ORDER_PREPARE_COMMIT'
  29. IMPORTING
  30. es_bapireturn = ls_bapireturn
  31. e_error_occurred = lv_error.
  32. IF ( ls_bapireturn-type = 'S' OR
  33. ls_bapireturn-type = 'W' OR
  34. ls_bapireturn-type = 'I' ) OR
  35. ls_bapireturn IS INITIAL.
  36. CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'.
  37. CALL FUNCTION 'CO_XT_ORDER_INITIALIZE'.
  38. ELSE.
  39. CLEAR: lv_error.
  40. CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
  41. MESSAGE ID ls_bapireturn-id
  42. TYPE ls_bapireturn-type
  43. NUMBER ls_bapireturn-number
  44. WITH ls_bapireturn-message_v1
  45. ls_bapireturn-message_v2
  46. ls_bapireturn-message_v3
  47. ls_bapireturn-message_v4.
  48. ENDIF.
  49. ELSE.
  50. CLEAR lv_error.
  51. CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
  52. READ TABLE lt_return INTO ls_return WITH KEY type = 'E'.
  53. IF sy-subrc = 0.
  54. MESSAGE ID ls_return-id
  55. TYPE ls_return-type
  56. NUMBER ls_return-number
  57. WITH ls_return-message_v1
  58. ls_return-message_v2
  59. ls_return-message_v3
  60. ls_return-message_v4.
  61. ENDIF.
  62. ENDIF.
  63. ENDIF.
  64. ENDFORM.

3. 添加我们需要的定制组件

需要注意,CO_XT_COMPONENT_ADD这个函数每次只能处理一条数据。如果添加多条需要循环处理,都成功后统一预提交,再正式提交,清缓存。

这个函数不是标准BAPI,所以需要修改主程序内存中的预留表对应的变量(SAPLCOBC)RESB_BT[],给组件对应预留数据的行项目字段赋值,配合让它生效。这么做非常别扭,但没别的选择余地。

值得一提的是,某些旧版本系统在执行完添加组件后,不会生成组件的状态对象。你会看到组件状态是空的,不是CRTD已创建。这时候你需要根据预留号和预留行项目号,自己创建一个状态对象。新版本不需要了,对这一步有疑问的伙计,我们可以单独再聊。

  1. FORM add_components USING pv_order_number TYPE aufnr.
  2. DATA: ls_requ TYPE coxt_s_quantity,
  3. ls_storage TYPE coxt_s_storage_location,
  4. ls_storagex TYPE coxt_s_storage_locationx,
  5. ls_return TYPE coxt_bapireturn,
  6. lt_return TYPE coxt_t_bapireturn,
  7. lv_msg TYPE string,
  8. lv_tabix TYPE sy-tabix,
  9. lv_postp TYPE postp,
  10. lv_operation TYPE co_aplzl,
  11. lv_sequence TYPE plnfolge,
  12. lv_material TYPE matnr,
  13. lv_positionno TYPE positionno,
  14. lv_error TYPE flag.
  15. TYPES: BEGIN OF ty_resb_bt.
  16. INCLUDE TYPE resbb.
  17. TYPES: indold LIKE sy-tabix,
  18. no_req_upd LIKE sy-datar,
  19. END OF ty_resb_bt.
  20. TYPES: lt_resb_bt TYPE TABLE OF ty_resb_bt.
  21. FIELD-SYMBOLS: <ft_resb_bt> TYPE lt_resb_bt,
  22. <fs_resb_bt> TYPE ty_resb_bt.
  23. SELECT SINGLE aufnr, aufpl
  24. INTO @DATA(ls_afko)
  25. FROM afko
  26. WHERE aufnr = @pv_order_number.
  27. IF sy-subrc EQ 0.
  28. * Fetch operation to which it has to be assigned
  29. SELECT SINGLE aufpl, aplzl, plnfl
  30. INTO @DATA(ls_afvc)
  31. FROM afvc
  32. WHERE aufpl = @ls_afko-aufpl.
  33. IF sy-subrc EQ 0.
  34. lv_operation = ls_afvc-aplzl.
  35. lv_sequence = ls_afvc-plnfl.
  36. ENDIF.
  37. ENDIF.
  38. * gt_i为存储定制组件的内表,gs_i为对应的工作区
  39. LOOP AT gt_i INTO gs_i.
  40. lv_tabix = sy-tabix.
  41. CLEAR: ls_requ,ls_storage,ls_storagex.
  42. ls_requ-quantity = gs_i-menge.
  43. ls_requ-uom = gs_i-meins.
  44. ls_storage-werks = gs_h-dwerk.
  45. ls_storage-lgort = gs_i-lgpro.
  46. ls_storagex-werks = 'X'.
  47. ls_storagex-lgort = 'X'.
  48. lv_positionno = sy-tabix * 10.
  49. lv_postp = 'L'.
  50. lv_material = gs_i-idnrk.
  51. * BAPI to add components to Production Order
  52. CALL FUNCTION 'CO_XT_COMPONENT_ADD'
  53. EXPORTING
  54. is_order_key = pv_order_number
  55. i_material = lv_material
  56. is_requ_quan = ls_requ
  57. i_operation = lv_operation
  58. i_sequence = lv_sequence
  59. is_storage_location = ls_storage
  60. is_storage_locationx = ls_storagex
  61. i_postp = lv_postp
  62. i_posno = lv_positionno
  63. IMPORTING
  64. es_bapireturn = ls_return
  65. e_error_occurred = lv_error.
  66. IF lv_error IS NOT INITIAL.
  67. EXIT.
  68. ENDIF.
  69. ENDLOOP.
  70. IF lv_error = space.
  71. CLEAR: lv_tabix,
  72. ls_return.
  73. * Modify POSNR via ASSIGN before DB update to correct the blank
  74. * item number in Components due to incompatible types of I_POSNO
  75. * (type CIF_R3RES-POSITIONNO) and RESB-POSNR
  76. ASSIGN ('(SAPLCOBC)RESB_BT[]') TO <ft_resb_bt>.
  77. LOOP AT <ft_resb_bt> ASSIGNING <fs_resb_bt>.
  78. lv_tabix = sy-tabix * 10.
  79. <fs_resb_bt>-posnr = lv_tabix.
  80. CLEAR lv_tabix.
  81. ENDLOOP.
  82. * Commit transaction
  83. CALL FUNCTION 'CO_XT_ORDER_PREPARE_COMMIT'
  84. IMPORTING
  85. es_bapireturn = ls_return
  86. e_error_occurred = lv_error.
  87. IF ( ls_return-type = 'S' OR
  88. ls_return-type = 'W' OR
  89. ls_return-type = 'I' ) OR
  90. ls_return IS INITIAL.
  91. * Commit data
  92. CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'.
  93. CALL FUNCTION 'CO_XT_ORDER_INITIALIZE'.
  94. ELSE.
  95. CLEAR: lv_error.
  96. * Data Rollback
  97. CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
  98. IF ls_return-type = 'E'.
  99. MESSAGE ID ls_return-id
  100. TYPE ls_return-type
  101. NUMBER ls_return-number
  102. WITH ls_return-message_v1
  103. ls_return-message_v2
  104. ls_return-message_v3
  105. ls_return-message_v4.
  106. ENDIF.
  107. ENDIF.
  108. ELSE.
  109. CLEAR: lv_error.
  110. * Data Rollback
  111. CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
  112. IF ls_return-type = 'E'.
  113. MESSAGE ID ls_return-id
  114. TYPE ls_return-type
  115. NUMBER ls_return-number
  116. WITH ls_return-message_v1
  117. ls_return-message_v2
  118. ls_return-message_v3
  119. ls_return-message_v4.
  120. ENDIF.
  121. ENDIF.
  122. ENDFORM.

其他的非常规方案

既然BAPI_PRODORD_CREATE这个官方主推的BAPI功能这么少,那么想改组件,工序之类的内容有什么办法吗?

答案是,有!但不是SAP官方推荐的方法。

使用SMOD事务码可以查到一个PP的生产订单保存前增强-PPCO0007,这是一个客户出口增强,其中只有一个组件函数EXIT_SAPLCOZV_001。里面只能看到表头数据CAUFVD。SAP本意是让你在里面做定制校验抛异常的,不是让你改东西。

如果非要改组件之类的行不行?用上文那个方法,字段符号直接匹配主程序内存中的更新数据库表变量(SAPLCOBC)RESB_BT[],以及其他工序,文本表之类。

这么做不但SAP不推荐,我也不推荐,可能出一些奇怪的问题。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/323825
推荐阅读
  

闽ICP备14008679号