在SAP生产制造场景中,报工(Confirmation)是连接计划与执行的关键环节。BAPI_PRODORDCONF_CREATE_TT这个函数模块就像生产线上的"确认按钮",它负责将实际生产数据(如完成数量、工时消耗)反馈给系统。想象一下车间主任拿着记事本记录每个工序的完成情况——这个BAPI就是数字化版本的记事本,只不过它能实时更新系统数据。
这个BAPI最厉害的地方在于它能同时处理两类数据:
我曾经在一个汽车零部件项目里,亲眼看到错误使用这个BAPI导致系统库存和实际对不上。后来发现是因为没处理好goodsmovements参数中的物料比例计算。这也说明理解每个参数的用途有多重要。
在真正报工前,我们需要先获取工序的基准数据。这就像做饭前要先看菜谱——得知道标准工时和允许报工量。下面这段代码展示了如何获取这些信息:
abap复制DATA:
ls_propose TYPE bapi_pp_conf_prop,
lt_timetickets TYPE STANDARD TABLE OF bapi_pp_timeticket.
" 设置需要获取的数据类型标记
ls_propose-quantity = 'X'. " 需要数量信息
ls_propose-activity = 'X'. " 需要工时信息
" 填充查询条件
ls_timetickets-orderid = v_aufnr. " 生产订单号
ls_timetickets-operation = iv_vornr. " 工序号
APPEND ls_timetickets TO lt_timetickets.
CALL FUNCTION 'BAPI_PRODORDCONF_GET_TT_PROP'
EXPORTING
propose = ls_propose
TABLES
timetickets = lt_timetickets.
这里有个容易踩的坑:一定要检查返回的yield字段。有次我发现系统允许报工量总是比预期少,后来发现是工艺路线里设置了最大报工限制。建议加上这样的校验逻辑:
abap复制IF ls_timetickets-yield < iv_yield.
MESSAGE '可报工数量小于本次报工数量' TYPE 'E'.
ENDIF.
拿到基准数据后,需要按实际完成情况计算比例。比如标准工时是4小时,完成了50%数量,那么应该记录2小时:
abap复制" 计算物料消耗量
LOOP AT lt_goodsmovements INTO ls_goodsmovements.
ls_goodsmovements-entry_qnt = ls_goodsmovements-entry_qnt * iv_yield / ls_timetickets-yield.
MODIFY lt_goodsmovements FROM ls_goodsmovements.
ENDLOOP.
" 计算实际工时
ls_timetickets-conf_activity1 = ls_timetickets-conf_activity1 * iv_yield / ls_timetickets-yield.
ls_timetickets-yield = iv_yield. " 更新为实际报工数量
特别注意工时可能分布在多个activity字段(conf_activity1/2/3),我在一个纺织厂项目就遇到过只更新了conf_activity1导致成本计算错误的情况。
正式调用BAPI前,需要完善几个关键字段:
abap复制" 设置操作人员
ls_timetickets-pers_no = iv_pernr.
" 如果是返工订单需要特殊标记
IF iv_rework = 'X'.
ls_timetickets-conf_type = 'R2'.
ENDIF.
conf_type参数特别重要,它决定了报工类型。常见值有:
终于到了最关键的报工环节:
abap复制CALL FUNCTION 'BAPI_PRODORDCONF_CREATE_TT'
EXPORTING
post_wrong_entries = '0' " 错误数据不进缓存
IMPORTING
return = ls_return
TABLES
timetickets = lt_timetickets
goodsmovements = lt_goodsmovements.
建议在测试阶段加上testrun = 'X'参数,这样能检查数据而不实际更新系统。有次我在上线前用这个参数发现了物料主数据缺失的问题,避免了生产事故。
BAPI的返回信息可能分布在三个地方:
return参数:整体执行状态detail_return表:每个确认项的详细结果goodsmovements表的错误信息完整的错误处理应该这样写:
abap复制" 转换系统消息到自定义消息结构
o_msg->convert_bapi_return_coru( lt_detail_return ).
" 检查是否有错误
IF o_msg->s_msg-type = 'E'.
CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
ELSE.
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
EXPORTING
wait = 'X'. " 等待提交完成
ENDIF.
在复杂场景中,我建议:
BAPI_TRANSACTION_COMMIT清除之前未提交的数据曾经有个客户因为没及时提交,导致8小时的生产数据在系统崩溃时全部丢失。现在我都习惯在代码里加上自动重试机制:
abap复制DATA lv_retry TYPE i VALUE 0.
WHILE lv_retry < 3.
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
EXPORTING
wait = 'X'.
IF sy-subrc = 0.
EXIT.
ELSE.
lv_retry = lv_retry + 1.
WAIT UP TO 1 SECONDS.
ENDIF.
ENDWHILE.
对于需要记录批次特性的场景(如制药行业),需要使用额外的参数表:
abap复制DATA:
lt_characteristics TYPE TABLE OF bapi1003_alloc_values_char,
lt_link_conf_char TYPE TABLE OF bapi_link_conf_char.
" 填充批次特性数据
lt_characteristics-charact = '纯度'.
lt_characteristics-value_char = '99.9%'.
APPEND lt_characteristics.
CALL FUNCTION 'BAPI_PRODORDCONF_CREATE_TT'
EXPORTING
...
TABLES
...
characteristics_batch = lt_characteristics
link_gm_char_batch = lt_link_conf_char.
在智能制造环境下,通常需要实时传递报工数据到MES。我常用的模式是:
abap复制" 先执行SAP报工
CALL FUNCTION 'BAPI_PRODORDCONF_CREATE_TT'...
" 然后调用MES接口
CALL FUNCTION 'Z_MES_CONFIRMATION'
DESTINATION 'MES_SERVER'
EXPORTING
order_number = v_aufnr.
" 最后统一提交
IF sy-subrc = 0.
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'.
ENDIF.
这种模式下要特别注意网络超时问题,建议设置合理的超时时间并在异常时回滚整个事务。