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.  
  • 相关阅读:
    算法竞赛入门经典习题2-3 韩信点兵
    ios入门之c语言篇——基本函数——5——素数判断
    ios入门之c语言篇——基本函数——4——数值交换函数
    144. Binary Tree Preorder Traversal
    143. Reorder List
    142. Linked List Cycle II
    139. Word Break
    138. Copy List with Random Pointer
    137. Single Number II
    135. Candy
  • 原文地址:https://www.cnblogs.com/eric0701/p/3114636.html
Copyright © 2011-2022 走看看