一、业务背景
我们公司的销售订单,是通过第三方销售管理平台创建好订单后,把表头和行项目数据,定时推送到SAP;SAP通过自定义表ZZT_ORDER_HEAD存放订单表头数据,通过ZZT_ORDER_DETAIL存放行项目数据;然后再用自定义的后台作业,定时调用创建销售订单的程序,从这两个自定义表中获取对应的数据来创建销售订单。
起因是财务同事发现10月份销售管理平台的订单金额与SAP的订单金额核对不上,经过对比分析发现,SAP有部分订单的单价扩大了10倍~~!!
二、问题分析
通过把数据复刻到测试环境,多次调试创建销售订单的程序后发现,只要销售订单行项目的货币为空,那么金额就会扩大10倍,如下图所示~~
销售订单创建的BAPI为:BAPI_SALESORDER_CREATEFROMDAT2
- CALL FUNCTION 'BAPI_SALESORDER_CREATEFROMDAT2'EXPORTINGSALESDOCUMENTIN =ORDER_HEADER_IN = LS_ORDER_HEADER_INORDER_HEADER_INX = LS_ORDER_HEADER_INXSENDER =BINARY_RELATIONSHIPTYPE =INT_NUMBER_ASSIGNMENT =BEHAVE_WHEN_ERROR =LOGIC_SWITCH =TESTRUN =CONVERT = ' 'IMPORTINGSALESDOCUMENT = LS_ORDERH_LOG-VBELNTABLESRETURN = LT_RETURNORDER_ITEMS_IN = LT_ORDER_ITEMS_INORDER_ITEMS_INX = LT_ORDER_ITEMS_INXORDER_PARTNERS = LT_ORDER_PARTNERSORDER_SCHEDULES_IN = LT_ORDER_SCHEDULES_INORDER_SCHEDULES_INX = LT_ORDER_SCHEDULES_INXORDER_CONDITIONS_IN = LT_ORDER_CONDITIONS_INORDER_CONDITIONS_INX = LT_ORDER_CONDITIONS_INX.
三、问题处理
问题源头找到后,剩下的就是如何批量更新这批销售订单的价格了。这里有两个方法,各有优劣;
方法1:通过VK11,维护对应的定价条件;然后使用VA05,批量更新销售订单的价格;
优势:不需要开发,标准功能即可完成销售订单价格更新;
劣势:维护了一批原本不应该维护的价格主数据,后续通过自开发程序,用同样的物料+客户等数据创建销售订单时,会出现两个相同的条件类型(一个是系统自动带出来,一个是程序赋值进去的,也可以理解为就是手工维护的价格);虽然这种销售订单只有自己维护的条件类型生效,但是看上去不太好看,另外,如果创建订单的程序,忘记对价格赋值时,正常应该是有不完整日志,但是现在因为维护了价格主数据,那么就会带出来(实际上每次的价格不一定一样)
方法2:通过LSMW录屏,批量更新销售订单价格(我这里操作失败了,不知道哪里出问题了,也懒得去研究折腾了,所以这里就不记录了)
方法3:通过自开发程序,批量更新销售订单价格主数据;
优势:方便快捷,直接更新
劣势:需要开发,测试,花了不少时间,而且在开发调用订单修改BAPI的过程中,会有几个坑,下面会记录
1、通过系统标准功能处理
(1)VK11:维护对应的价格主数据
(2)修改原来订单的定价定价日期
注意原订单的定价日期,一定要在VK11维护的价格主数据的有效期范围内;
A、VK12修改价格主数据的有效期,把有效期提前
B、批量修改销售订单的定价日期(MASS-BUS2032-修改VBAP字段-MASSSDHEAD_S-PRSDT)
这里为了方便,我把价格主数据的有效期,提前到2024/10/23
(3)VA05:批量更新订单价格
全选后,点击抬头的编辑-批量更改-新定价
PS:附加测试,如果价格主数据的有效期没改(还是2024/10/25),而订单的定价日期是2024/10/23,不在价格有效期范围内;那么执行:B--执行新的定价时,价格会变成0
执行后,含税单价变为0;
(4)本方案的劣势数据记录;
记录VK11维护价格主数据后,重新调用订单创建函数,生成的订单
2、通过自开发批量更新订单价格的程序
(1)程序操作执行演示
PS:这里需要注意,一定要确认,先把销售订单的发票取消,再去调用程序更改价格,否则就会出现问题,如下图所示:订单价格是459,但是不含税价格竟然是4061.95(未修改前的价格)
(2)程序开发及使用的一些注意事项;
A、该程序除了批量更改订单行项目价格外,还可以批量关闭订单(维护拒绝原因)
B、更新销售订单价格,不需要取消交货过帐,但是需要取消发票(通过前台操作也可以知道,开票情况下是无法修改订单价格的)
C、使用的BAPI为:“BAPI_SALESORDER_CHANGE”
D、只有导入模板同时填写了单价和价格单位,并且销售订单存在条件类型ZC01时,才会执行更新函数(如果单价和价格单位都不维护,那么不更新,也不考虑插入条件类型ZC01)
E、如果lt_conditions_inx-cond_st_no 和lt_conditions_inx-cond_count不赋实际的值,而是赋值‘X’,那么销售订单行项目,是会插入一个ZC01,而不是更新原来的ZC01!!!
四、总结
1、通过BAPI创建销售订单时,如果发现订单价格扩大十倍,可以查看函数赋值时,是否没有把货币码赋值进去;
2、VA05批量更新销售订单价格时,需要注意三个地方;
(1)提前用VK11维护好价格主数据,并且确保销售订单的定价条件在价格主数据的有效期范围内
(2)选择B-执行新的定价;
3、在修改销售订单价格之前,需要确保先用VF11取消了发票;
以上,本次记录完成~~
完整代码如下;
*&---------------------------------------------------------------------*
*& Report ZSDR0012
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT zsdr0012.
TABLES sscrfields.DATA gv_grid TYPE REF TO cl_gui_alv_grid.DATA: BEGIN OF gs_alv,vbeln TYPE vbap-vbeln,posnr TYPE vbap-posnr,abgru TYPE vbap-abgru,"拒绝原因kbetr TYPE konv-kbetr,"订单行项目价格kpein TYPE konv-kpein,"价格单位icon TYPE icon_d,msg TYPE string,sel(1),END OF gs_alv,gt_alv LIKE TABLE OF gs_alv.DATA: gs_layout TYPE lvc_s_layo,gs_fieldcat TYPE lvc_s_fcat,gt_fieldcat TYPE lvc_t_fcat.DATA: gv_error TYPE c.DEFINE set_fieldcat.CLEAR gs_fieldcat.gs_fieldcat-fieldname = &1.gs_fieldcat-scrtext_l = &2.gs_fieldcat-no_zero = &3.APPEND gs_fieldcat TO gt_fieldcat.
END-OF-DEFINITION.SELECTION-SCREEN FUNCTION KEY 1.
PARAMETERS:p_file TYPE rlgrap-filename.AT SELECTION-SCREEN.CASE sscrfields-ucomm.WHEN 'FC01'.PERFORM frm_down_temp.WHEN OTHERS.IF p_file IS INITIAL.MESSAGE '请输入导入数据文件' TYPE 'E'.ENDIF.ENDCASE.AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_file .CALL FUNCTION 'WS_FILENAME_GET'EXPORTINGdef_filename = ''def_path = ''mask = ',EXCEL FILES(*.XLS),*.XLS,ALL FILES(*.*),*.*,'mode = 'O'title = 'Find the input file'IMPORTINGfilename = p_fileEXCEPTIONSinv_winsys = 1no_batch = 2selection_cancel = 3selection_error = 4OTHERS = 5.INITIALIZATION.sscrfields-functxt_01 = '下载模板'.START-OF-SELECTION." # 上传数据PERFORM frm_get_data." # 检查数据PERFORM frm_check_data." # 显示结果PERFORM frm_display_data.
*&---------------------------------------------------------------------*
*& Form frm_down_temp
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& --> p1 text
*& <-- p2 text
*&---------------------------------------------------------------------*
FORM frm_down_temp .DATA:ls_wwwdata_item LIKE wwwdatatab,lv_file TYPE rlgrap-filename,lv_rc LIKE sy-subrc.CALL FUNCTION 'WS_FILENAME_GET'EXPORTINGdef_filename = 'ZSDR004.xls'
* DEF_PATH = 'C:\'mask = ',EXCEL FILES(*.XLS),*.XLS,ALL FILES(*.*),*.*,'mode = 'S'title = '选择模板导入文件'IMPORTINGfilename = lv_fileEXCEPTIONSinv_winsys = 1no_batch = 2selection_cancel = 3selection_error = 4OTHERS = 5.IF sy-subrc <> 0.EXIT.ENDIF.SELECT SINGLE *INTO CORRESPONDING FIELDS OF ls_wwwdata_itemFROM wwwdataWHERE srtf2 = 0AND relid = 'MI'AND objid = 'ZSDR0010_DOC01'.IF sy-subrc NE 0 OR ls_wwwdata_item-objid EQ space.MESSAGE '模版文件不存在!' TYPE 'E'.EXIT.ENDIF.CALL FUNCTION 'DOWNLOAD_WEB_OBJECT'EXPORTINGkey = ls_wwwdata_itemdestination = lv_fileIMPORTINGrc = lv_rc.IF lv_rc = 0.MESSAGE s398(00) DISPLAY LIKE 'S' WITH '模版文件下载成功!'.ELSE.MESSAGE s398(00) DISPLAY LIKE 'E' WITH '模版文件下载失败!'.ENDIF.ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_get_data
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& --> p1 text
*& <-- p2 text
*&---------------------------------------------------------------------*
FORM frm_get_data .DATA: lt_excel TYPE TABLE OF zalsmex_tabline2 WITH HEADER LINE.FIELD-SYMBOLS:<field> TYPE any." # EXCEL导入" HACK" 注意大数据量Excel的性能问题" 此处限制是6W 可能已经有问题了CALL FUNCTION 'ZALSM_EXCEL_TO_INTERNAL_TABLE'EXPORTINGfilename = p_filei_begin_col = 1i_begin_row = 2i_end_col = 5i_end_row = 5000sheet_name = 'Sheet1'TABLESintern = lt_excelEXCEPTIONSinconsistent_parameters = 1upload_ole = 2OTHERS = 3.IF sy-subrc <> 0.MESSAGE '文件上传失败' TYPE 'S' DISPLAY LIKE 'E'.LEAVE LIST-PROCESSING.ENDIF.SORT lt_excel BY row col.CLEAR: gt_alv,gs_alv.LOOP AT lt_excel.ASSIGN COMPONENT lt_excel-col OF STRUCTURE gs_alv TO <field>.<field> = lt_excel-value.AT END OF row.APPEND gs_alv TO gt_alv.CLEAR: gs_alv.ENDAT.ENDLOOP.IF gt_alv[] IS INITIAL.MESSAGE '上传文件内容为空' TYPE 'S' DISPLAY LIKE 'E'.LEAVE LIST-PROCESSING.ENDIF.SORT gt_alv BY vbeln posnr.REFRESH lt_excel.ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_check_data
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& --> p1 text
*& <-- p2 text
*&---------------------------------------------------------------------*
FORM frm_check_data .CLEAR: gv_error.IF gt_alv IS NOT INITIAL.
***订单前补0LOOP AT gt_alv ASSIGNING FIELD-SYMBOL(<lfs_alv>).CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'EXPORTINGinput = <lfs_alv>-vbelnIMPORTINGoutput = <lfs_alv>-vbeln.ENDLOOP.SELECTvbeln,posnrINTO TABLE @DATA(lt_vbap)FROM vbapFOR ALL ENTRIES IN @gt_alvWHERE vbeln EQ @gt_alv-vbelnAND posnr EQ @gt_alv-posnr.SORT lt_vbap BY vbeln posnr.SELECTabgruINTO TABLE @DATA(lt_tvag)FROM tvag.SORT lt_tvag BY abgru.ENDIF.LOOP AT gt_alv ASSIGNING <lfs_alv>."必填项检查IF <lfs_alv>-vbeln IS INITIAL.<lfs_alv>-msg = '销售订单号必填'.<lfs_alv>-icon = icon_led_red.gv_error = 'X'.ENDIF.IF <lfs_alv>-posnr IS INITIAL.IF <lfs_alv>-msg IS INITIAL.<lfs_alv>-msg = '订单行项目必填'.<lfs_alv>-icon = icon_led_red.gv_error = 'X'.ELSE.<lfs_alv>-msg = <lfs_alv>-msg && '|订单行项目必填'.ENDIF.ENDIF.IF <lfs_alv>-abgru IS NOT INITIAL.READ TABLE lt_tvag TRANSPORTING NO FIELDS WITH KEY abgru = <lfs_alv>-abgru BINARY SEARCH.IF sy-subrc NE 0.IF <lfs_alv>-msg IS INITIAL.<lfs_alv>-msg = '拒绝原因不存在'.<lfs_alv>-icon = icon_led_red.gv_error = 'X'.ELSE.<lfs_alv>-msg = <lfs_alv>-msg && '|拒绝原因不存在'.ENDIF.ENDIF.ENDIF.IF <lfs_alv>-vbeln IS NOT INITIAL AND <lfs_alv>-posnr IS NOT INITIAL.READ TABLE lt_vbap TRANSPORTING NO FIELDS WITH KEY vbeln = <lfs_alv>-vbeln posnr = <lfs_alv>-posnr BINARY SEARCH.IF sy-subrc NE 0.IF <lfs_alv>-msg IS INITIAL.<lfs_alv>-msg = '销售订单不存在'.<lfs_alv>-icon = icon_led_red.gv_error = 'X'.ELSE.<lfs_alv>-msg = <lfs_alv>-msg && '|销售订单不存在'.ENDIF.ENDIF.ENDIF."价格检查IF <lfs_alv>-kbetr IS NOT INITIAL AND <lfs_alv>-kpein IS INITIAL.IF <lfs_alv>-msg IS INITIAL.<lfs_alv>-msg = '价格填写后,价格单位必填'.<lfs_alv>-icon = icon_led_red.gv_error = 'X'.ELSE.<lfs_alv>-msg = <lfs_alv>-msg && '|价格单位必填'.ENDIF.ENDIF.IF <lfs_alv>-kpein IS NOT INITIAL AND <lfs_alv>-kbetr IS INITIAL.IF <lfs_alv>-msg IS INITIAL.<lfs_alv>-msg = '价格单位填写后,含税单价必填'.<lfs_alv>-icon = icon_led_red.gv_error = 'X'.ELSE.<lfs_alv>-msg = <lfs_alv>-msg && '|含税单价必填'.ENDIF.ENDIF.ENDLOOP.ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_display_data
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& --> p1 text
*& <-- p2 text
*&---------------------------------------------------------------------*
FORM frm_display_data .gs_layout-cwidth_opt = 'X'.gs_layout-zebra = 'X'.
* gs_layout-box_fname = 'SEL'.set_fieldcat:'ICON' '图标' '','MSG' '消息' '' ,'VBELN' '销售订单' '','POSNR' '销售订单行项目' '','ABGRU' '拒绝原因' '','KBETR' '含税单价' '','KPEIN' '价格单位' ''.CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY_LVC'EXPORTINGi_callback_program = sy-repidi_callback_pf_status_set = 'FRM_SET_STATUS'i_callback_user_command = 'FRM_USER_COMMAND'is_layout_lvc = gs_layoutit_fieldcat_lvc = gt_fieldcati_save = 'A'TABLESt_outtab = gt_alv.ENDFORM.FORM frm_set_status USING exclud TYPE slis_t_extab.SET PF-STATUS 'STATUS' EXCLUDING exclud.
ENDFORM.FORM frm_user_command USING ucomm rs_selfield TYPE slis_selfield.CALL FUNCTION 'GET_GLOBALS_FROM_SLVC_FULLSCR'IMPORTINGe_grid = gv_grid.CALL METHOD gv_grid->check_changed_data.CASE ucomm.WHEN 'ZCHANGE'.PERFORM frm_change_data.WHEN OTHERS.ENDCASE.rs_selfield-row_stable = 'X'. "保证行、列位置在自动刷新时不变rs_selfield-col_stable = 'X'.rs_selfield-refresh = 'X'.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_change_data
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& --> p1 text
*& <-- p2 text
*&---------------------------------------------------------------------*
FORM frm_change_data .TYPES: BEGIN OF ty_prcd,knumv TYPE knumv,kposn TYPE kposn,stunr TYPE stunr,zaehk TYPE dzaehk,kbetr TYPE kbetr, "条件金额kpein TYPE kpein, "价格单位kmein TYPE kmein, "条件单位waers TYPE waers, "货币END OF ty_prcd.DATA: lv_vbeln TYPE bapivbeln-vbeln,ls_headrx TYPE bapisdh1x,lt_return TYPE TABLE OF bapiret2 WITH HEADER LINE,lt_item TYPE TABLE OF bapisditm WITH HEADER LINE,lt_itemx TYPE TABLE OF bapisditmx WITH HEADER LINE,lt_conditions_in TYPE TABLE OF bapicond WITH HEADER LINE,lt_conditions_inx TYPE TABLE OF bapicondx WITH HEADER LINE,lt_prcd TYPE TABLE OF ty_prcd,ls_prcd TYPE ty_prcd.DATA: lv_message TYPE string."先获取所有需要处理的订单的条件记录SELECT knumv, kposn, stunr, zaehk,kbetr, kpein, kmein, waersFROM prcd_elementsINTO TABLE @lt_prcdFOR ALL ENTRIES IN @gt_alvWHERE knumv IN ( SELECT knumv FROM vbakWHERE vbeln = @gt_alv-vbeln )AND kschl = 'ZC01'AND kappl = 'V' "销售定价AND kposn <> '000000'. "非抬头条件IF sy-subrc = 0.SORT lt_prcd BY knumv kposn.ENDIF.LOOP AT gt_alv INTO DATA(wa) GROUP BY ( vbeln = wa-vbeln ).CLEAR: lv_vbeln,ls_headrx.REFRESH: lt_return,lt_item,lt_itemx, lt_conditions_in, lt_conditions_inx.lv_vbeln = wa-vbeln.ls_headrx-updateflag = 'U'."获取定价过程号SELECT SINGLE knumvFROM vbakINTO @DATA(lv_knumv)WHERE vbeln = @lv_vbeln.LOOP AT GROUP wa INTO gs_alv.CLEAR:lt_item.lt_item-itm_number = gs_alv-posnr.lt_item-reason_rej = gs_alv-abgru.APPEND lt_item.CLEAR:lt_itemx.lt_itemx-itm_number = gs_alv-posnr.lt_itemx-updateflag = 'U'.lt_itemx-reason_rej = 'X'.APPEND lt_itemx."仅当价格和价格单位都有值时才更新价格IF gs_alv-kbetr IS NOT INITIAL ANDgs_alv-kpein IS NOT INITIAL ANDlv_knumv IS NOT INITIAL."查找对应的条件记录READ TABLE lt_prcd INTO ls_prcdWITH KEY knumv = lv_knumvkposn = gs_alv-posnrBINARY SEARCH.IF sy-subrc = 0. "只有存在原条件记录时才更新CLEAR: lt_conditions_in.lt_conditions_in-itm_number = gs_alv-posnr.lt_conditions_in-cond_type = 'ZC01'.lt_conditions_in-cond_st_no = ls_prcd-stunr. "条件步骤号lt_conditions_in-cond_count = ls_prcd-zaehk. "条件计数器"lt_conditions_in-cond_count = '001'. "条件计数器:有多个相同的ZC01时,默认更新第一个lt_conditions_in-cond_value = gs_alv-kbetr. "新价格lt_conditions_in-cond_unit = gs_alv-kpein. "价格单位lt_conditions_in-currency = ls_prcd-waers. "货币lt_conditions_in-cond_unit = ls_prcd-kmein. "条件单位APPEND lt_conditions_in.CLEAR: lt_conditions_inx.lt_conditions_inx-itm_number = gs_alv-posnr.lt_conditions_inx-cond_type = 'ZC01'.lt_conditions_inx-updateflag = 'U'.lt_conditions_inx-cond_st_no = ls_prcd-stunr.lt_conditions_inx-cond_count = ls_prcd-zaehk.lt_conditions_inx-cond_value = 'X'.lt_conditions_inx-cond_unit = 'X'.lt_conditions_inx-currency = 'X'.lt_conditions_inx-cond_unit = 'X'.APPEND lt_conditions_inx.ENDIF.ENDIF.ENDLOOP.CALL FUNCTION 'BAPI_SALESORDER_CHANGE'EXPORTINGsalesdocument = lv_vbeln
* ORDER_HEADER_IN =order_header_inx = ls_headrx
* SIMULATION =
* BEHAVE_WHEN_ERROR = ' '
* INT_NUMBER_ASSIGNMENT = ' '
* LOGIC_SWITCH =
* NO_STATUS_BUF_INIT = ' 'TABLESreturn = lt_returnorder_item_in = lt_itemorder_item_inx = lt_itemx
* PARTNERS =
* PARTNERCHANGES =
* PARTNERADDRESSES =
* ORDER_CFGS_REF =
* ORDER_CFGS_INST =
* ORDER_CFGS_PART_OF =
* ORDER_CFGS_VALUE =
* ORDER_CFGS_BLOB =
* ORDER_CFGS_VK =
* ORDER_CFGS_REFINST =
* SCHEDULE_LINES =
* SCHEDULE_LINESX =
* ORDER_TEXT =
* ORDER_KEYS =conditions_in = lt_conditions_inconditions_inx = lt_conditions_inx
* EXTENSIONIN = ..CLEAR: lv_message.LOOP AT lt_return WHERE type = 'E' OR type = 'A'.CONCATENATE lt_return-message ';' lv_message INTO lv_message.ENDLOOP.IF sy-subrc NE 0.CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'EXPORTINGwait = 'X'.CLEAR: gs_alv.gs_alv-icon = icon_led_green.gs_alv-msg = '修改成功'.MODIFY gt_alv FROM gs_alv TRANSPORTING icon msg WHERE vbeln = wa-vbeln.ELSE.CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.CLEAR: gs_alv.gs_alv-icon = icon_led_red.gs_alv-msg = lv_message.MODIFY gt_alv FROM gs_alv TRANSPORTING icon msg WHERE vbeln = wa-vbeln.ENDIF.ENDLOOP.
ENDFORM.
EXCEL上传函数ZALSM_EXCEL_TO_INTERNAL_TABLE懒得上传了,网上随便都能搜到,搜不到的效果吧,需要的可以私聊~~