zoukankan      html  css  js  c++  java
  • ME21N 屏幕增强 网上转载

    最近想更深入学习下classic BADI, 以前没玩过BADI屏幕增强, 所以决定玩一下.

    这次的屏幕增强主要用到两个BADI: ME_GUI_PO_CUST和ME_PROCESS_PO_CUST

     

    这两个BADI都是有例子的, 可以在se18那里按GoTo->Sample code->Display来查看, 也可以直接在SE24查看类CL_EXM_IM_ME_GUI_PO_CUST和CL_EXM_IM_ME_PROCESS_PO_CUST


     

    现在我们对PO header加上自己的subscreen, SAP的例子提供的是对item增加subscreen.

     

    Step 1: Create Function Group

    仿照Function Group MEPOBADIEX建一个Function Group

    我建的Function Group如下图所示


     

    Step 2: 在Function Group里建Screen, screen number随便



    在TOP里面加入对应屏幕的变量, 这里我是直接用tables.


     

    Step 3: 给BADI ME_GUI_PO_CUST建一个implementation


    在Public Section里加上TYPE-POOLS mmmfd .


    Step 4: 在Method IF_EX_ME_GUI_PO_CUST~SUBSCRIBE, 加入custom subscreen的设置代码

    1. METHOD if_ex_me_gui_po_cust~subscribe.  
    2.   DATA: lw_subscribers TYPE mepo_subscribers.  
    3.   
    4. * we want to add a customer subscreen on the Header tab  
    5.   CHECK im_application = 'PO'.  
    6.   CHECK im_element     = 'HEADER'.  
    7.   
    8.   CLEAR lw_subscribers.  
    9.   lw_subscribers-name = subscreen1.  
    10.   lw_subscribers-dynpro = '0100'.  
    11.   lw_subscribers-program = 'SAPLZCI_EKKODB'.  
    12.   lw_subscribers-struct_name = 'CI_EKKODB'.  
    13.   lw_subscribers-label = 'Zero test2'.  
    14.   lw_subscribers-position = 11.  
    15.   lw_subscribers-height = 8.  
    16.   APPEND lw_subscribers TO re_subscribers.  
    17. ENDMETHOD.  
    METHOD if_ex_me_gui_po_cust~subscribe.
      DATA: lw_subscribers TYPE mepo_subscribers.
    
    * we want to add a customer subscreen on the Header tab
      CHECK im_application = 'PO'.
      CHECK im_element     = 'HEADER'.
    
      CLEAR lw_subscribers.
      lw_subscribers-name = subscreen1.
      lw_subscribers-dynpro = '0100'.
      lw_subscribers-program = 'SAPLZCI_EKKODB'.
      lw_subscribers-struct_name = 'CI_EKKODB'.
      lw_subscribers-label = 'Zero test2'.
      lw_subscribers-position = 11.
      lw_subscribers-height = 8.
      APPEND lw_subscribers TO re_subscribers.
    ENDMETHOD.


    Step 5: 在Method: IF_EX_ME_GUI_PO_CUST~MAP_DYNPRO_FIELDS, 加入代码, 使field name和它的数字编号关联起来.

    1. FIELD-SYMBOLS: <mapping> LIKE LINE OF ch_mapping.  
    2.   
    3. LOOP AT ch_mapping ASSIGNING <mapping>.  
    4.   CASE <mapping>-fieldname.  
    5.     WHEN 'LV_TEST1'. <mapping>-metafield = mmmfd_cust_01.  
    6.     WHEN 'LV_TEST2'. <mapping>-metafield = mmmfd_cust_02.  
    7.     WHEN 'LV_TEST3'. <mapping>-metafield = mmmfd_cust_03.  
    8.   ENDCASE.  
    9. ENDLOOP.  
      FIELD-SYMBOLS: <mapping> LIKE LINE OF ch_mapping.
    
      LOOP AT ch_mapping ASSIGNING <mapping>.
        CASE <mapping>-fieldname.
          WHEN 'LV_TEST1'. <mapping>-metafield = mmmfd_cust_01.
          WHEN 'LV_TEST2'. <mapping>-metafield = mmmfd_cust_02.
          WHEN 'LV_TEST3'. <mapping>-metafield = mmmfd_cust_03.
        ENDCASE.
      ENDLOOP.

    Custom的field估计只能加9个, 因为我在TYPE-POOLS mmmfd看到最大的是mmfd_cust_09,

    这里也可以把一些standard field弄到custom subscreen上.

    经过以上五步, 我们可以在ME23N看到custom subscreen, 但在ME21N和ME22N依然是看不到的...这个是为什么, 我还搞不清楚.

     

    Step 6: 给BADI ME_PROCESS_PO_CUST建一个implementation


    在Public Section加入TYPE-POOLS mmmfd .


     

    Step 7: 在Method IF_EX_ME_PROCESS_PO_CUST~FIELDSELECTION_HEADER加入代码, 改变表ch_fieldselection的field status, '-'代表hidden, '+'或'.'表示editable, '*'代表display

    1. METHOD if_ex_me_process_po_cust~fieldselection_header.  
    2.   DATA: lv_persistent TYPE mmpur_bool.  
    3.   FIELD-SYMBOLS: <fs> LIKE LINE OF ch_fieldselection.  
    4.   
    5.   DEFINE set_input.  
    6.     read table ch_fieldselection assigning <fs> with table key metafield = &1.  
    7.     if sy-subrc = 0.  
    8.      if im_header->is_changeable( ) = mmpur_yes.  
    9.        <fs>-fieldstatus = '+'.  
    10.      else.  
    11.        <fs>-fieldstatus = '*'.  
    12.      endif.  
    13.     endif.  
    14.   END-OF-DEFINITION.  
    15.   
    16. * if the item is already on the database, we disallow to change field badi_bsgru  
    17.   lv_persistent = im_header->is_persistent( ).  
    18.   
    19.   set_input mmmfd_cust_01.  
    20.   set_input mmmfd_cust_02.  
    21.   set_input mmmfd_cust_03.  
    22.   
    23. ENDMETHOD.  
    METHOD if_ex_me_process_po_cust~fieldselection_header.
      DATA: lv_persistent TYPE mmpur_bool.
      FIELD-SYMBOLS: <fs> LIKE LINE OF ch_fieldselection.
    
      DEFINE set_input.
        read table ch_fieldselection assigning <fs> with table key metafield = &1.
        if sy-subrc = 0.
         if im_header->is_changeable( ) = mmpur_yes.
           <fs>-fieldstatus = '+'.
         else.
           <fs>-fieldstatus = '*'.
         endif.
        endif.
      END-OF-DEFINITION.
    
    * if the item is already on the database, we disallow to change field badi_bsgru
      lv_persistent = im_header->is_persistent( ).
    
      set_input mmmfd_cust_01.
      set_input mmmfd_cust_02.
      set_input mmmfd_cust_03.
    
    ENDMETHOD.

    这里有两点注意下:

    1. im_header->is_changeable()可以判断当前这些field是不是处于可编辑状态, 如果是则为'X'. 比如刚进TCODE ME21N, ME22N它们是可编辑的, 但当按save保存成功后, 它们暂时是不可以编辑的, 要再按把它改回编辑状态才可以编辑,这里就实现了这个功能.

    2. im_header->is_persistent()可以判断当这些field在数据库里有值了, 它就是'X', 当我们把数据写进表里就不想它被修改时, 可以用这个来判断, 比如把某个field设置成ME21N可编辑, ME22N不可编辑.

    经过这七步, ME21N/ME22N/ME23N都可以看到这个custom subscreen, 但所有自建field都是可编辑状态, 必需做完第八步, 才能正常显示

     

    Step 8: 在screen中调用2个module


    这两个module存放在下图的程序里


    注意: 如果不调用这两个module, BADI ME_GUI_PO_CUST下面的4个method都不会触发

    TRANSPORT_FROM_MODEL
    TRANSPORT_TO_DYNP
    TRANSPORT_FROM_DYNP
    TRANSPORT_TO_MODEL

     

    Step 9: 在Method IF_EX_ME_GUI_PO_CUST~TRANSPORT_FROM_MODEL加入代码, 把header的三个自建field传到attribute dynp_data_pho里

    1. METHOD if_ex_me_gui_po_cust~transport_from_model.  
    2.   DATA:     lw_header       TYPE REF TO if_purchase_order_mm,  
    3.             lw_mepoheader   TYPE mepoheader,  
    4.             lw_customer     TYPE ci_ekkodb.  
    5. *--------------------------------------------------------------------*  
    6. * system asks to transport data from the business logic into the view  
    7. *--------------------------------------------------------------------*  
    8.   
    9.   IF im_name = subscreen1.  
    10. * is it an Header? im_model can be header or item.  
    11.     mmpur_dynamic_cast lw_header im_model.  
    12.     CHECK NOT lw_header IS INITIAL.  
    13. * transport standard fields  
    14.     lw_mepoheader = lw_header->get_data( ).  
    15. * store info for later use  
    16.     MOVE-CORRESPONDING lw_mepoheader TO dynp_data_pbo.  
    17.   ENDIF.  
    18.   
    19. ENDMETHOD.  
    METHOD if_ex_me_gui_po_cust~transport_from_model.
      DATA:     lw_header       TYPE REF TO if_purchase_order_mm,
                lw_mepoheader   TYPE mepoheader,
                lw_customer     TYPE ci_ekkodb.
    *--------------------------------------------------------------------*
    * system asks to transport data from the business logic into the view
    *--------------------------------------------------------------------*
    
      IF im_name = subscreen1.
    * is it an Header? im_model can be header or item.
        mmpur_dynamic_cast lw_header im_model.
        CHECK NOT lw_header IS INITIAL.
    * transport standard fields
        lw_mepoheader = lw_header->get_data( ).
    * store info for later use
        MOVE-CORRESPONDING lw_mepoheader TO dynp_data_pbo.
      ENDIF.
    
    ENDMETHOD.


    Step 10: 在Method IF_EX_ME_GUI_PO_CUST~TRANSPORT_TO_DYNP加入代码, 通过调用FM: ZCI_EKKODB_PUSH 把attribute dynp_data_pho里的东西(这里为Header的三个自建field)传到Function group: ZCI_EKKODB的structure CI_EKKODB里面, 这样自建field的值就会反映到屏幕上. 

    1. METHOD if_ex_me_gui_po_cust~transport_to_dynp.  
    2.   
    3.   IF im_name = subscreen1.  
    4.     CALL FUNCTION 'ZCI_EKKODB_PUSH'  
    5.       EXPORTING  
    6.         im_dynp_data = dynp_data_pbo.  
    7.   ENDIF.  
    8. ENDMETHOD.  
    METHOD if_ex_me_gui_po_cust~transport_to_dynp.
    
      IF im_name = subscreen1.
        CALL FUNCTION 'ZCI_EKKODB_PUSH'
          EXPORTING
            im_dynp_data = dynp_data_pbo.
      ENDIF.
    ENDMETHOD.


     

    Step 11: 在IF_EX_ME_GUI_PO_CUST~TRANSPORT_FROM_DYNP加入代码, PAI事件时, 把屏幕的值传到attribute dynp_data_pai, 并且比较dynp_data_pbo和dynp_data_pai, 确定自建field的值有所改变, 把re_changed置为'X', 这样IF_EX_ME_PROCESS_PO_CUST~PROCESS_HEADER就会触发.

    1. METHOD if_ex_me_gui_po_cust~transport_from_dynp.  
    2.   IF im_name = subscreen1.  
    3.     CALL FUNCTION 'ZCI_EKKODB_POP'  
    4.       IMPORTING  
    5.         ex_dynp_data = dynp_data_pai.  
    6.   
    7.   ENDIF.  
    8.   
    9.   IF dynp_data_pai <> dynp_data_pbo.  
    10. * something has changed therefor we have to notify the framework  
    11. * to transport data to the model  
    12.     re_changed = mmpur_yes.  
    13.   ENDIF.  
    14. ENDMETHOD.  
    METHOD if_ex_me_gui_po_cust~transport_from_dynp.
      IF im_name = subscreen1.
        CALL FUNCTION 'ZCI_EKKODB_POP'
          IMPORTING
            ex_dynp_data = dynp_data_pai.
    
      ENDIF.
    
      IF dynp_data_pai <> dynp_data_pbo.
    * something has changed therefor we have to notify the framework
    * to transport data to the model
        re_changed = mmpur_yes.
      ENDIF.
    ENDMETHOD.



    Step 12: 在IF_EX_ME_GUI_PO_CUST~TRANSPORT_TO_MODEL加入代码, 把修改后的数据传到bussiness object里.

    1. METHOD if_ex_me_gui_po_cust~transport_to_model.  
    2.   
    3.   DATA: lw_header            TYPE REF TO if_purchase_order_mm,  
    4.         lw_mepoheader        TYPE mepoheader,  
    5.         lw_customer          TYPE ci_ekkodb,  
    6.         lw_po_header_handle  TYPE REF TO cl_po_header_handle_mm.  
    7. *--------------------------------------------------------------------*  
    8. * data have to be transported to business logic  
    9. *--------------------------------------------------------------------*  
    10.   IF im_name = subscreen1.  
    11.   
    12. * is it an item? im_model can be header or item.  
    13.     mmpur_dynamic_cast lw_header im_model.  
    14.     CHECK NOT lw_header IS INITIAL.  
    15.     lw_mepoheader = lw_header->get_data( ).  
    16. * standard fields changed?  
    17.     IF dynp_data_pbo-lv_test1 <> dynp_data_pai-lv_test1  
    18.     OR dynp_data_pbo-lv_test2 <> dynp_data_pai-lv_test2  
    19.     OR dynp_data_pbo-lv_test3 <> dynp_data_pai-lv_test3.  
    20. * update standard fields  
    21.       lw_mepoheader-lv_test1 = dynp_data_pai-lv_test1.  
    22.       lw_mepoheader-lv_test2 = dynp_data_pai-lv_test2.  
    23.       lw_mepoheader-lv_test3 = dynp_data_pai-lv_test3.  
    24.   
    25.       CALL METHOD lw_header->set_data  
    26.         EXPORTING  
    27.           im_data = lw_mepoheader.  
    28.   
    29.     ENDIF.  
    30.   ENDIF.  
    31. ENDMETHOD.  
    METHOD if_ex_me_gui_po_cust~transport_to_model.
    
      DATA: lw_header            TYPE REF TO if_purchase_order_mm,
            lw_mepoheader        TYPE mepoheader,
            lw_customer          TYPE ci_ekkodb,
            lw_po_header_handle  TYPE REF TO cl_po_header_handle_mm.
    *--------------------------------------------------------------------*
    * data have to be transported to business logic
    *--------------------------------------------------------------------*
      IF im_name = subscreen1.
    
    * is it an item? im_model can be header or item.
        mmpur_dynamic_cast lw_header im_model.
        CHECK NOT lw_header IS INITIAL.
        lw_mepoheader = lw_header->get_data( ).
    * standard fields changed?
        IF dynp_data_pbo-lv_test1 <> dynp_data_pai-lv_test1
        OR dynp_data_pbo-lv_test2 <> dynp_data_pai-lv_test2
        OR dynp_data_pbo-lv_test3 <> dynp_data_pai-lv_test3.
    * update standard fields
          lw_mepoheader-lv_test1 = dynp_data_pai-lv_test1.
          lw_mepoheader-lv_test2 = dynp_data_pai-lv_test2.
          lw_mepoheader-lv_test3 = dynp_data_pai-lv_test3.
    
          CALL METHOD lw_header->set_data
            EXPORTING
              im_data = lw_mepoheader.
    
        ENDIF.
      ENDIF.
    ENDMETHOD.


    Step 13: 如果要check这些field的值的话, 可以写在IF_EX_ME_PROCESS_PO_CUST~PROCESS_HEADER, 这里我要check field1必须是PALM.

    1. METHOD if_ex_me_process_po_cust~process_header.  
    2.   DATA: lw_mepoheader TYPE mepoheader,  
    3.         lw_customer TYPE ci_ekkodb.  
    4.   
    5.   DATA: lv_testflag TYPE c.  
    6.   
    7.   INCLUDE mm_messages_mac. "useful macros for message handling  
    8.   
    9.   lw_mepoheader = im_header->get_data( ).  
    10.   
    11.   IF lw_mepoheader-lv_test1 <> 'PALM'.  
    12. * Place the cursor onto field lv_test1. The metafield was defined in BAdI ME_GUI_PO_CUST,  
    13. * Method MAP_DYNPRO_FIELDS.  
    14.   
    15.     mmpur_metafield mmmfd_cust_01.  
    16.     mmpur_message_forced 'E' 'ZDEV001' '999' '' '' '' ''.  
    17. *    MESSAGE 'This field should be filled ''PALM''' TYPE 'W'.  
    18.   
    19. *    CLEAR lv_testflag.  
    20. *    lv_testflag = 'X'.  
    21. *    EXPORT lv_testflag FROM lv_testflag TO MEMORY ID 'Z_ZERO_ME22N'.  
    22.   
    23. * invalidate the object  
    24.     CALL METHOD im_header->invalidate( ).  
    25.   ENDIF.  
    26.   
    27. ENDMETHOD.  
    METHOD if_ex_me_process_po_cust~process_header.
      DATA: lw_mepoheader TYPE mepoheader,
            lw_customer TYPE ci_ekkodb.
    
      DATA: lv_testflag TYPE c.
    
      INCLUDE mm_messages_mac. "useful macros for message handling
    
      lw_mepoheader = im_header->get_data( ).
    
      IF lw_mepoheader-lv_test1 <> 'PALM'.
    * Place the cursor onto field lv_test1. The metafield was defined in BAdI ME_GUI_PO_CUST,
    * Method MAP_DYNPRO_FIELDS.
    
        mmpur_metafield mmmfd_cust_01.
        mmpur_message_forced 'E' 'ZDEV001' '999' '' '' '' ''.
    *    MESSAGE 'This field should be filled ''PALM''' TYPE 'W'.
    
    *    CLEAR lv_testflag.
    *    lv_testflag = 'X'.
    *    EXPORT lv_testflag FROM lv_testflag TO MEMORY ID 'Z_ZERO_ME22N'.
    
    * invalidate the object
        CALL METHOD im_header->invalidate( ).
      ENDIF.
    
    ENDMETHOD.

    如果按回车来check的话, 它会显示error message,一次改变后按一次回车有反应, 第二次就没反应.


    这里有一个缺陷, 当我们按save里, 这条message是不会显示到message表中的(研究了很久, 没研究出来怎么搞), 幸好这里有个功能十分不错, 选中PO header data still faulty这个message, 按Edit, 就可以定位到error message的field.

    至此, 增强完成.

    补充:

    1. IF_EX_ME_PROCESS_PO_CUST~INITIALIZE: initialize function groupZCI_EKKODB的变量语句可以写在这.

    1. METHOD if_ex_me_process_po_cust~initialize.  
    2.   CALL FUNCTION 'ZCI_EKKODB_INIT'  
    3.             .  
    4. ENDMETHOD.  
    METHOD if_ex_me_process_po_cust~initialize.
      CALL FUNCTION 'ZCI_EKKODB_INIT'
                .
    ENDMETHOD.



    2. IF_EX_ME_PROCESS_PO_CUST~OPEN: 如果要select自建表的东西可以写在这里, 这里有个field IM_TRTYP有一定的控制作用, 具体可以查看它的domain值.

    3. IF_EX_ME_PROCESS_PO_CUST~POST: update自建表的语句可以写在这里.

     

    4. Custom subscreen的field必须引用method IF_EX_ME_GUI_PO_CUST~SUBSCRIBE里的定义的那个structure, from dict要勾上.

    5. 如果有自建表里面的field, 必须在method IF_EX_ME_GUI_PO_CUST~TRANSPORT_TO_MODEL判断自建表的field改变时, 加上语句CALL METHOD lw_header->set_changed( ), 不这样的话, 你的自建表的field怎么变在保存时都会提示No data changed. 下面代码是例子.

    1. METHOD if_ex_me_gui_po_cust~transport_to_model.  
    2.   
    3.   DATA: lw_header            TYPE REF TO if_purchase_order_mm,  
    4.         lw_mepoheader        TYPE mepoheader,  
    5.         lw_customer          TYPE ci_ekkodb,  
    6.         lw_po_header_handle  TYPE REF TO cl_po_header_handle_mm.  
    7. *--------------------------------------------------------------------*  
    8. * data have to be transported to business logic  
    9. *--------------------------------------------------------------------*  
    10.   IF im_name = subscreen1.  
    11.   
    12. * is it an item? im_model can be header or item.  
    13.     mmpur_dynamic_cast lw_header im_model.  
    14.     CHECK NOT lw_header IS INITIAL.  
    15.     lw_mepoheader = lw_header->get_data( ).  
    16. * standard fields changed?  
    17.     IF dynp_data_pbo-lv_test1 <> dynp_data_pai-lv_test1  
    18.     OR dynp_data_pbo-lv_test2 <> dynp_data_pai-lv_test2  
    19.     OR dynp_data_pbo-lv_test3 <> dynp_data_pai-lv_test3.  
    20. * update standard fields  
    21.       lw_mepoheader-lv_test1 = dynp_data_pai-lv_test1.  
    22.       lw_mepoheader-lv_test2 = dynp_data_pai-lv_test2.  
    23.       lw_mepoheader-lv_test3 = dynp_data_pai-lv_test3.  
    24.   
    25.       CALL METHOD lw_header->set_data  
    26.         EXPORTING  
    27.           im_data = lw_mepoheader.  
    28.   
    29.     ENDIF.  
    30.   
    31.     IF dynp_data_pbo-zdamon <> dynp_data_pai-zdamon.  
    32.       CALL FUNCTION 'ZCI_EKKODB_SET_DATA'  
    33.         EXPORTING  
    34.           im_damon = dynp_data_pai-zdamon.  
    35.   
    36.       CALL METHOD lw_header->set_changed( ).  
    37.     ENDIF.  
    38.   
    39.   ENDIF.  
    40. ENDMETHOD.  
    METHOD if_ex_me_gui_po_cust~transport_to_model.
    
      DATA: lw_header            TYPE REF TO if_purchase_order_mm,
            lw_mepoheader        TYPE mepoheader,
            lw_customer          TYPE ci_ekkodb,
            lw_po_header_handle  TYPE REF TO cl_po_header_handle_mm.
    *--------------------------------------------------------------------*
    * data have to be transported to business logic
    *--------------------------------------------------------------------*
      IF im_name = subscreen1.
    
    * is it an item? im_model can be header or item.
        mmpur_dynamic_cast lw_header im_model.
        CHECK NOT lw_header IS INITIAL.
        lw_mepoheader = lw_header->get_data( ).
    * standard fields changed?
        IF dynp_data_pbo-lv_test1 <> dynp_data_pai-lv_test1
        OR dynp_data_pbo-lv_test2 <> dynp_data_pai-lv_test2
        OR dynp_data_pbo-lv_test3 <> dynp_data_pai-lv_test3.
    * update standard fields
          lw_mepoheader-lv_test1 = dynp_data_pai-lv_test1.
          lw_mepoheader-lv_test2 = dynp_data_pai-lv_test2.
          lw_mepoheader-lv_test3 = dynp_data_pai-lv_test3.
    
          CALL METHOD lw_header->set_data
            EXPORTING
              im_data = lw_mepoheader.
    
        ENDIF.
    
        IF dynp_data_pbo-zdamon <> dynp_data_pai-zdamon.
          CALL FUNCTION 'ZCI_EKKODB_SET_DATA'
            EXPORTING
              im_damon = dynp_data_pai-zdamon.
    
          CALL METHOD lw_header->set_changed( ).
        ENDIF.
    
      ENDIF.
    ENDMETHOD.

    6.Method IF_EX_ME_GUI_PO_CUST~EXECUTE可以处理function code.

    1. METHOD if_ex_me_gui_po_cust~execute.  
    2.   IF im_fcode = 'ZZZZ'.  
    3.     MESSAGE 'Zero test' TYPE 'I'.  
    4.   ENDIF.  
    5. ENDMETHOD.  
  • 相关阅读:
    对象,类,封装,继承,多态是什么
    面向对象和非面向对象程序的区别是什么?
    什么是OOA,OOP
    git stash git tag
    从一个远程仓库同步向另一个远程仓库同步代码
    VScode 配置rust开发环境
    IAR ICCARM V8.32.3在Windows Server端进行Ollydbg破解
    阅读笔记
    FP32转FP16能否加速libtorch调用
    阅读笔记-Chained-Tracker
  • 原文地址:https://www.cnblogs.com/eric0701/p/3114636.html
Copyright © 2011-2022 走看看