MDG Change Request Attachments – Hide/Disable attachments in MDG CR based on User Role
2023-10-21 05:19:24 Author: blogs.sap.com(查看原文) 阅读量:42 收藏

Hello Colleagues,

During MDG Supplier implementation, I received a unique requirement from one of my client.

Business Requirement 

When requester submits a Change Request with some Bank or HR related sensitive attachments. Then the Bank related approvers should not view the HR attachments. Similarly, the HR related approvers should not view the Bank attachments.

Well, this is quite logical and interesting requirement from Client. Below is implementation process I followed to achieve this unique requirement.

Thinking on the Solution and Obstacles:

  • If we enhance the CR page, then it will be visible to all Masters in MDG. But this requirement is applicable only to MDG Supplier.
  • Adding custom attribute to Form UIBB of Attachment Popup as well as taking back that value to List UIBB of Attachments.
  • Saving and reading this custom attribute value during CR processing as it was not saved in SAP standard tables.

Implementation Process:

Let’s divide this requirement in to 4 steps.

  1. GeniL Structure Update
  2. Create Customizing and Custom Feeder class for Add File Popup Screen (Form UIBB)
  3. Create Customizing and Custom Feeder class for List of attachments (List UIBB)
  4. Custom Table to store the custom attribute values.

1. Update Genil Structure for Attachment:

If we want to enhance CR attachments to add new attribute, we have to extend Genil component “CR”.

So, I planned to add custom attribute “Attach Type” in the Popup which will differentiate the type of attachment.

GeniL%20Model%20for%20CR

GeniL Model for CR

So, we need to append Genil Structure for Attachment BSS_CRIL_ATTACHMENT_ATTRIBUTES to have a custom attribute.

Append%20attribute%20to%20BSS_CRIL_ATTACHMENT_ATTRIBUTES

Append attribute to BSS_CRIL_ATTACHMENT_ATTRIBUTES

2. Now let’s create customizing to FORM UIBB for Attachment (Add File Popup)

First let’s create a customizing to USMD_CR_ATT_FILE WD component and attach custom feeder class to add this custom attribute. This is a form UIBB, and its feeder class is CL_USMD_CR_ATT_FILE_BOL_FEEDER. Since this feeder class is final, we cannot provide this class as super class to our custom feeder class.

CL_USMD_CR_ATT_FILE_BOL_FEEDER

CL_USMD_CR_ATT_FILE_BOL_FEEDER

CL_USMD_CR_ATT_FILE_BOL_FEEDER%20--%20Implemented%20Methods

CL_USMD_CR_ATT_FILE_BOL_FEEDER — Implemented Methods

How to solve this technical block?

What I have done is, created a custom feeder class ZCL_***_CR_ATT_FILE_FEEDER and assign the super class as CL_GUIBB_BOL_FORM which is a super class for CL_USMD_CR_ATT_FILE_BOL_FEEDER.

Custom%20Feeder%20class%20for%20Attachment%20Popup

Custom Feeder class for Attachment Popup

And Reimplemented all the methods as shown below.

Custom%20Feeder%20Class%20with%20Standard%20Reimplemented%20Methods

Custom Feeder Class with Standard Reimplemented Methods

GET_DATA & GET_DEFINITION methods are redefined to have the custom field (attachment type value, visibility and other options only applicable to MDG-Supplier)

Reimplemented PROCESS_EVENT to through an error message when this field is not field from MDG-Supplier

Code Snippet for this custom feeder class.

IF_FPM_GUIBB_FORM~GET_DATA

  METHOD if_fpm_guibb_form~get_data.

    DATA : ls_attachment_data TYPE bss_cril_attachment_attributes,
           lv_crequest_type   TYPE usmd_crequest_type.

    FIELD-SYMBOLS: <lv_filename>  TYPE any,
                   <lv_timestamp> TYPE any,
                   <lv_createdby> TYPE any.

    IF me->mv_first_time = abap_false.
      ASSIGN COMPONENT 'FILENAME' OF STRUCTURE cs_data TO <lv_filename>.
      IF sy-subrc = 0.
        mv_filename = <lv_filename>.
      ENDIF.
    ENDIF.

    CALL METHOD super->if_fpm_guibb_form~get_data
      EXPORTING
        io_event                = io_event
        it_selected_fields      = it_selected_fields
        iv_raised_by_own_ui     = iv_raised_by_own_ui
        iv_edit_mode            = iv_edit_mode
      IMPORTING
        et_messages             = et_messages
        ev_data_changed         = ev_data_changed
        ev_field_usage_changed  = ev_field_usage_changed
        ev_action_usage_changed = ev_action_usage_changed
      CHANGING
        cs_data                 = cs_data
        ct_field_usage          = ct_field_usage
        ct_action_usage         = ct_action_usage.

    IF me->mv_first_time = abap_false.
      ASSIGN COMPONENT 'FILENAME' OF STRUCTURE cs_data TO <lv_filename>.
      IF sy-subrc = 0.
        <lv_filename> = mv_filename.
      ENDIF.
    ENDIF.

    IF me->mv_first_time = abap_true.
      me->mv_first_time = abap_false.
      CLEAR mv_filename.
" Get parameter
      CALL METHOD io_event->mo_event_data->get_value
        EXPORTING
          iv_key   = me->cv_att_mode
        IMPORTING
          ev_value = me->mv_file_edit_mode.

      IF me->mv_file_edit_mode = cv_file_mode_edit.
        " Store the initial data of the popup in order to undo changes  (if happened)
        " when the popup processing will be cancelled
        CLEAR me->ms_attachment_file_data.
        MOVE-CORRESPONDING cs_data TO me->ms_attachment_file_data.
        "me->ms_attachment_file_data = cs_data.
      ENDIF.

      IF
         me->is_mode_read_only( ) = abap_true AND
         me->mo_entity IS BOUND AND
        NOT ( io_event->mv_event_id = if_fpm_constants=>gc_event-local_edit AND iv_raised_by_own_ui = abap_true ).
        me->raise_local_event_by_id( if_fpm_constants=>gc_event-local_edit ).
      ENDIF.
    ENDIF.

* Below code makes sure that the logic will execute only for MDG-Supplier
    IF zcl_oug_vm_util=>get_instance( )->check_app( ) EQ zcl_oug_vm_util=>gc_mdgs. 
      DATA : ls_field_usage       TYPE fpmgb_s_fieldusage,
             lt_field_usage       TYPE fpmgb_t_fieldusage,

             ls_field_usage_value TYPE wdr_context_attr_value,
             lt_field_usage_value TYPE wdr_context_attr_value_list.

      READ TABLE ct_field_usage ASSIGNING FIELD-SYMBOL(<fs_field_usage>) WITH KEY name = gc_attachment_type.
      IF sy-subrc IS INITIAL.
*Add Fixed Values.

        ls_field_usage_value-value = gc_bank.
        ls_field_usage_value-text = gc_bank.
        APPEND ls_field_usage_value TO lt_field_usage_value.

        ls_field_usage_value-value = gc_hr.
        ls_field_usage_value-text = gc_hr.
        APPEND ls_field_usage_value TO lt_field_usage_value.

        ls_field_usage_value-value = gc_non_sen.
        ls_field_usage_value-text = gc_non_sen.
        APPEND ls_field_usage_value TO lt_field_usage_value.

        ls_field_usage-fixed_values = lt_field_usage_value.
        APPEND ls_field_usage TO lt_field_usage.

        <fs_field_usage>-fixed_values = lt_field_usage_value.
        <fs_field_usage>-fixed_values_changed = abap_true.
        <fs_field_usage>-mandatory = abap_true.
        <fs_field_usage>-visibility = '02'.
      ENDIF.
      ev_field_usage_changed = 'X'.
    ELSE.
      READ TABLE ct_field_usage ASSIGNING FIELD-SYMBOL(<fs_field_usage1>) WITH KEY name = gc_attachment_type.
      <fs_field_usage1>-visibility = '01'.
      ev_field_usage_changed = 'X'.
    ENDIF.
  ENDMETHOD.

IF_FPM_GUIBB_FORM~GET_DEFINITION

 METHOD if_fpm_guibb_form~get_definition.
    FIELD-SYMBOLS:  <ls_field_description>  TYPE fpmgb_s_formfield_descr.
    CALL METHOD super->if_fpm_guibb_form~get_definition
      IMPORTING
        es_message               = es_message
        eo_field_catalog         = eo_field_catalog
        et_field_description     = et_field_description
        et_action_definition     = et_action_definition
        et_special_groups        = et_special_groups
        ev_additional_error_info = ev_additional_error_info
        et_dnd_definition        = et_dnd_definition.

    READ TABLE et_field_description WITH TABLE KEY name = 'CONTENT' ASSIGNING <ls_field_description>.
    IF sy-subrc = 0.
      <ls_field_description>-file_name_ref = 'FILENAME'.
      <ls_field_description>-mime_type_ref = 'FILE_TYPE'.
    ENDIF.

    " Enter empty field for dropdown list box for "Attachment Type"
    READ TABLE et_field_description ASSIGNING FIELD-SYMBOL(<field_description>) WITH KEY name = gc_attachment_type.
    IF sy-subrc = 0 AND <field_description> IS ASSIGNED.
      <field_description>-is_nullable = abap_true.
    ENDIF.

  ENDMETHOD.

IF_FPM_GUIBB_FORM~PROCESS_EVENT

  METHOD if_fpm_guibb_form~process_event.

    DATA:
      lv_dialog_action_id TYPE string,
      ls_message          LIKE LINE OF et_messages,
      lv_message          TYPE string,                      "#EC NEEDED
      lv_success          TYPE abap_bool,
      ls_attachment_data  TYPE bss_cril_attachment_attributes.


    IF mo_entity IS NOT BOUND  OR mo_entity->alive( ) EQ abap_false.

      DATA : lr_access1 TYPE REF TO if_bol_bo_property_access,
             lr_entity1 TYPE REF TO cl_crm_bol_entity.

      lr_access1 = get_property_access( iv_index = 1 ).
      TRY.
          me->mo_entity ?= lr_access1.
        CATCH cx_sy_move_cast_error.
          RETURN.
      ENDTRY.
    ENDIF.

    CASE io_event->mv_event_id.
      WHEN if_fpm_constants=>gc_event-close_dialog.

        io_event->mo_event_data->get_value( EXPORTING iv_key = if_fpm_constants=>gc_dialog_box-dialog_buton_key
                                            IMPORTING ev_value = lv_dialog_action_id ).
        CASE lv_dialog_action_id.
          WHEN if_fpm_constants=>gc_dialog_action_id-ok.
            " Do the necessary popup checks
            CHECK me->mo_entity IS BOUND.
            CALL METHOD me->mo_entity->if_bol_bo_property_access~get_properties
              IMPORTING
                es_attributes = ls_attachment_data.
            " 1.) Check Mandatory fields
            " a.) Link
            IF ls_attachment_data-content IS INITIAL.
              CLEAR ls_message.
              ls_message-msgid    = 'USMD2'.
              ls_message-msgno    = '116'.
              ls_message-severity = 'E'.
              ls_message-ref_name = 'CONTENT'.
              MESSAGE e116(usmd2) INTO lv_message.
              APPEND ls_message TO et_messages.
              ev_result = if_fpm_constants=>gc_event_result-failed.
            ENDIF.
*           b.) Title
            IF ls_attachment_data-title IS INITIAL.
              CLEAR ls_message.
              ls_message-msgid       = 'USMD2'.
              ls_message-msgno       = '106'.
              ls_message-severity    = 'E'.
              ls_message-ref_name    = 'TITLE'.
              ls_message-parameter_1 = TEXT-001.
              MESSAGE e106(usmd2) INTO lv_message WITH ls_message-parameter_1.
              APPEND ls_message TO et_messages.
              ev_result = if_fpm_constants=>gc_event_result-failed.
            ENDIF.
*           c.) Attach Type for MDG-S
            IF zcl_oug_vm_util=>get_instance( )->check_app( ) EQ zcl_oug_vm_util=>gc_mdgs.
              IF ls_attachment_data-attach_type IS INITIAL.
                CLEAR ls_message.
                ls_message-msgid       = ''. " Your Custom Message Class
                ls_message-msgno       = ''. " Message ID from custom message class
                ls_message-severity    = 'E'.
                ls_message-ref_name    = 'ATTACH_TYPE'.
                ls_message-parameter_1 = TEXT-002.
                MESSAGE e106(usmd2) INTO lv_message WITH ls_message-parameter_1.
                APPEND ls_message TO et_messages.
                ev_result = if_fpm_constants=>gc_event_result-failed.
              ENDIF.
            ENDIF.
            IF ev_result = if_fpm_constants=>gc_event_result-failed.
              IF mv_filename IS NOT INITIAL.
                CLEAR ls_message.
                ls_message-msgid       = 'USMDCRUI'.
                ls_message-msgno       = '002'.
                ls_message-severity    = 'S'.
                ls_message-ref_name    = 'CONTENT'.
                ls_message-parameter_1 = mv_filename.
                MESSAGE s002(usmdcrui) INTO lv_message WITH ls_message-parameter_1.
                APPEND ls_message TO et_messages.
              ENDIF.
              RETURN.
            ELSE.
              " Processing was fine (no errors)
              ev_result = if_fpm_constants=>gc_event_result-ok.
              " Initialize variables
              me->mv_first_time = abap_true.
              CLEAR me->ms_attachment_file_data.
            ENDIF.

          WHEN if_fpm_constants=>gc_dialog_action_id-cancel OR
               if_fpm_constants=>gc_dialog_action_id-close.
            IF me->mv_file_edit_mode = cv_file_mode_create.
              " If editing has been cancelled in create mode delete the newly created entity again
              CALL METHOD me->delete_entity
                EXPORTING
                  io_entity  = me->mo_entity
                RECEIVING
                  rv_success = lv_success.

            ELSEIF me->mv_file_edit_mode = cv_file_mode_edit.
              " If editing has been cancelled in edit mode undo the current changes
              CHECK me->mo_entity IS BOUND.
              CALL METHOD me->mo_entity->if_bol_bo_property_access~set_properties
                EXPORTING
                  is_attributes = me->ms_attachment_file_data.
              CLEAR me->ms_attachment_file_data.
            ENDIF.
            me->mv_first_time = abap_true.
        ENDCASE.

      WHEN if_fpm_constants=>gc_event-refresh.
        IF mv_filename IS NOT INITIAL.
          CLEAR ls_message.
          ls_message-msgid       = 'USMDCRUI'.
          ls_message-msgno       = '002'.
          ls_message-severity    = 'S'.
          ls_message-ref_name    = 'CONTENT'.
          ls_message-parameter_1 = mv_filename.
          MESSAGE s002(usmdcrui) INTO lv_message WITH ls_message-parameter_1.
          APPEND ls_message TO et_messages.
        ENDIF.

      WHEN OTHERS.
        RETURN.
    ENDCASE.
  ENDMETHOD.

So far, we have completed the design for Add File Popup screen. Let’s test the functionality in MDG!

Add%20File%20Popup%20with%20Custom%20Attribute

Add File Popup with Custom Attribute

Dropdown%20values

Dropdown values

3. Create customizing to LIST UIBB for Attachments:

Now let’s start our next phase of development which is to enhance the Attachments list UIBB to hold/save the “Attach Type” provide from the Add File Popup screen.

So let’s create a customizing to USMD_CR_ATTACHMENTS WD component and attach custom feeder class to add the same custom attribute which we created in GeniL. This is a list UIBB and its feeder class is CL_USMD_CR_GUIBB_ATTACHMENTS. Since this feeder class is not final, we can provide this class as super class to our custom feeder class.

CL_USMD_CR_GUIBB_ATTACHMENTS

CL_USMD_CR_GUIBB_ATTACHMENTS

Custom%20Feeder%20Class%20for%20Attachments%20List%20UIBB

Custom Feeder Class for Attachments List UIBB

In this custom feeder class, I have redefined GET_DATA and PROCESS_EVENT methods. Also, created additional methods for Hiding/Disable and checking authorization of the user.

The three custom methods have been called in IF_FPM_GUIBB_LIST~GET_DATA method to check user authorization (at approver level) and to hide/disable the attachments.

Code Snippet for IF_FPM_GUIBB_LIST~GET_DATA

  METHOD if_fpm_guibb_list~get_data.
    CALL METHOD super->if_fpm_guibb_list~get_data
      EXPORTING
        iv_eventid                = iv_eventid
        it_selected_fields        = it_selected_fields
        iv_raised_by_own_ui       = iv_raised_by_own_ui
        iv_visible_rows           = iv_visible_rows
        iv_edit_mode              = iv_edit_mode
        io_extended_ctrl          = io_extended_ctrl
      IMPORTING
        et_messages               = et_messages
        ev_data_changed           = ev_data_changed
        ev_field_usage_changed    = ev_field_usage_changed
        ev_action_usage_changed   = ev_action_usage_changed
        ev_selected_lines_changed = ev_selected_lines_changed
        ev_dnd_attr_changed       = ev_dnd_attr_changed
        eo_itab_change_log        = eo_itab_change_log
      CHANGING
        ct_data                   = ct_data
        ct_field_usage            = ct_field_usage
        ct_action_usage           = ct_action_usage
        ct_selected_lines         = ct_selected_lines
        cv_lead_index             = cv_lead_index
        cv_first_visible_row      = cv_first_visible_row
        cs_additional_info        = cs_additional_info
        ct_dnd_attributes         = ct_dnd_attributes.

    DATA lv_index TYPE i.
    CASE iv_eventid->mv_event_id.
      WHEN 'CR_ATT_DELETE'.
        CALL METHOD iv_eventid->mo_event_data->get_value
          EXPORTING
            iv_key   = 'FPM_GUIBB_LIST_ON_LEAD_SELECTI'
          IMPORTING
            ev_value = lv_index
            er_value = DATA(er_value).
    ENDCASE.

* Hide Attachment Type attribute for other Masters. Its applicable only for MSG-S
    IF zcl_oug_vm_util=>get_instance( )->check_app( ) NE zcl_oug_vm_util=>gc_mdgs.
      READ TABLE ct_field_usage ASSIGNING FIELD-SYMBOL(<fs_field_usage>) WITH KEY name = 'ATTACH_TYPE'.
      IF sy-subrc EQ 0.
        <fs_field_usage>-visibility = '01'.
        ev_field_usage_changed = 'X'.
      ENDIF.
    ENDIF.


* Hide HR and Bank Attachments based on user Role/Auth object.
    IF zcl_oug_vm_util=>get_instance( )->check_app( ) EQ zcl_oug_vm_util=>gc_mdgs.

      DATA : lv_crequest_id     TYPE usmd_crequest,
             lr_data            TYPE REF TO data,
             lv_leadindex       TYPE i,
             lt_attachment_data TYPE TABLE OF bss_cril_attachment_attributes,
             ls_attachment_data TYPE bss_cril_attachment_attributes,
             ls_message         TYPE fpmgb_s_t100_message.

      FIELD-SYMBOLS <lt_data> TYPE ANY TABLE.
      GET REFERENCE OF ct_data INTO lr_data.
      ASSIGN lr_data->* TO <lt_data>.

* Get Instance of Conv API.
      IF go_mdg_conv IS NOT BOUND.
        TRY.
            go_mdg_conv = cl_usmd_conv_som_gov_api=>get_instance(
                            iv_model_name = zcl_oug_vm_util=>gc_model
                            iv_classname  = 'CL_USMD_CONV_SOM_GOV_API' ).
          CATCH cx_usmd_conv_som_gov_api.       " General Processing Error CONV_API
          CATCH cx_usmd_app_context_cons_error. " Exception: Consistency Error in Design of Appl. Context
          CATCH cx_usmd_gov_api.                " General Processing Error GOV_API
        ENDTRY.
      ENDIF.

* Get Change Request Attributes to restrict the call after requester step.
      IF go_mdg_conv IS BOUND.
        go_mdg_conv->get_crequest_attributes( RECEIVING rs_crequest = DATA(rs_crequest) ).
      ENDIF.

      IF rs_crequest-usmd_creq_status NE '02'. " CR not with Requester
* Check user authorization to view attachments
        CALL METHOD me->check_authorization
          EXPORTING
            im_user           = sy-uname                 " ABAP System Field: Name of Current User
          IMPORTING
            ev_auth_flag_hr   = DATA(lv_auth_flag_hr)    " Auth Check Flag for HR Attachments
            ev_auth_flag_bank = DATA(lv_auth_flag_bank). " Auth Check Flag for Bank Attachments

        IF lv_auth_flag_hr EQ abap_true.
          CALL METHOD me->hide_hr_attachments EXPORTING ct_data = lr_data IMPORTING es_message = ls_message.
          IF ls_message IS NOT INITIAL.
            APPEND ls_message  TO et_messages.
          ENDIF.
        ENDIF.

        IF lv_auth_flag_bank EQ abap_true.
          CALL METHOD me->hide_bank_attachments EXPORTING ct_data = lr_data IMPORTING es_message = ls_message.
          IF ls_message IS NOT INITIAL.
            APPEND ls_message  TO et_messages.
          ENDIF.
        ENDIF.
      ENDIF.
    ENDIF.

  ENDMETHOD.

Code Snippet for Custom Method CHECK_AUTHORIZATION

I have created two authorization objects & special roles to differentiate the users. And assigned these roles to users based on requirement. I was checking whether the current CR processor is authorized are not in below method and returning the flag back to GET_DATA method if he is not authorized to view.

  METHOD check_authorization.
    CLEAR : ev_auth_flag_hr,
            ev_auth_flag_bank.

    CALL FUNCTION 'AUTHORITY_CHECK'
      EXPORTING
        user                = im_user
        object              = '' " Custom Auth.Object created for HR
        field1              = 'ACTVT'
        value1              = '01'
        field2              = 'ACTVT'
        value2              = '02'
        field3              = 'ACTVT'
        value3              = '03'
      EXCEPTIONS
        user_dont_exist     = 1
        user_is_authorized  = 2
        user_not_authorized = 3
        user_is_locked      = 4
        OTHERS              = 5.
    IF sy-subrc = 3.
*   User not authorized to view HR attachments
      ev_auth_flag_hr = 'X'.
    ENDIF.

    CALL FUNCTION 'AUTHORITY_CHECK'
      EXPORTING
        user                = im_user
        object              = '' " Custom Auth.Object created for Bank
        field1              = 'ACTVT'
        value1              = '01'
        field2              = 'ACTVT'
        value2              = '02'
        field3              = 'ACTVT'
        value3              = '03'
      EXCEPTIONS
        user_dont_exist     = 1
        user_is_authorized  = 2
        user_not_authorized = 3
        user_is_locked      = 4
        OTHERS              = 5.
    IF sy-subrc = 3.
*   User not authorized to view Bank attachments
      ev_auth_flag_bank = 'X'.
    ENDIF.
  ENDMETHOD.

Code Snippet for Custom Method HIDE_HR_ATTACHMENTS 

In this method, I am receiving the CT_DATA and hiding/disable the data based on custom attribute value. Also, I am sending a warning message. So that the current processor will get an information that there is some sensitive data in that particular CR, but he is not authorized to view.

  METHOD hide_hr_attachments.
    DATA: lr_data TYPE REF TO data.
    FIELD-SYMBOLS: <lt_data>  TYPE ANY TABLE,
                   <ls_line>  TYPE any,
                   <ld_field> TYPE any.
    lr_data = ct_data.
    ASSIGN lr_data->* TO <lt_data>.
    LOOP AT <lt_data> ASSIGNING <ls_line>.
      ASSIGN COMPONENT 'CREATED_BY' OF STRUCTURE <ls_line> TO FIELD-SYMBOL(<ls_user>).
        ASSIGN COMPONENT 'ATTACH_TYPE' OF STRUCTURE <ls_line> TO <ld_field>.
        IF <ld_field> EQ gc_hr.
          ASSIGN COMPONENT 'FPM_BOL_GUIBB_REF_0000000020' OF STRUCTURE <ls_line> TO FIELD-SYMBOL(<ls_hr>).
          IF <ls_hr> IS ASSIGNED.
            <ls_hr> = abap_false.
          ENDIF.
          ASSIGN COMPONENT 'FPM_BOL_GUIBB_REF_0000000024' OF STRUCTURE <ls_line> TO FIELD-SYMBOL(<ls_langu>).
          IF <ls_langu> IS ASSIGNED.
            <ls_langu> = abap_false.
          ENDIF.
          es_message-msgid  = ''. " Custom Message Class
          es_message-msgno  = ''. " Custom Message ID
          es_message-parameter_1  = gc_hr.
          es_message-severity = 'W'.
        ENDIF.
    ENDLOOP.
  ENDMETHOD.

Code Snippet for Custom Method HIDE_BANK_ATTACHMENTS 

  METHOD hide_bank_attachments.
    DATA: lr_data TYPE REF TO data.
    FIELD-SYMBOLS: <lt_data>  TYPE ANY TABLE,
                   <ls_line>  TYPE any,
                   <ld_field> TYPE any.

    lr_data = ct_data.
    ASSIGN lr_data->* TO <lt_data>.

    LOOP AT <lt_data> ASSIGNING <ls_line>.
      ASSIGN COMPONENT 'CREATED_BY' OF STRUCTURE <ls_line> TO FIELD-SYMBOL(<ls_user>).
        ASSIGN COMPONENT 'ATTACH_TYPE' OF STRUCTURE <ls_line> TO <ld_field>.
        IF <ld_field> EQ gc_bank.
          ASSIGN COMPONENT 'FPM_BOL_GUIBB_REF_0000000020' OF STRUCTURE <ls_line> TO FIELD-SYMBOL(<ls_bank>).
          IF <ls_bank> IS ASSIGNED.
            <ls_bank> = abap_false.
          ENDIF.
          ASSIGN COMPONENT 'FPM_BOL_GUIBB_REF_0000000024' OF STRUCTURE <ls_line> TO FIELD-SYMBOL(<ls_langu>).
          IF <ls_langu> IS ASSIGNED.
            <ls_langu> = abap_false.
          ENDIF.
          es_message-msgid  = 'ZOUG_MSGS'.
          es_message-msgno  = '69'.
          es_message-parameter_1  = gc_bank.
          es_message-severity = 'W'.
        ENDIF.
    ENDLOOP.
  ENDMETHOD.

4. Now we are at the final stage of this development.

So before proceeding, let’s test the development at the Requester step.

We can see the new custom attribute which was added to GeniL and Feeder class is appearing in the attachments List UIBB.

Let’s add some attachments and check whether the data getting passed from Popup to List UIBB of attachments.

Ok Data is getting passed and visible in the List UIBB of attachments. So far development is Woking fine as expected.

Now the next task is, once the CR is submitted this custom attribute value also needs to be saved. So that we can retrieve the same for the further CR steps.

For this I have created a custom table Z* as shown below. In this table I have taken Change Request and Timestamp as a key to store the custom attribute value.

The reason behind to create this custom table was to avoid modification/append to SAP standard tables USMD1211 & USMD1212 for attachments.

But here the next technical challenge was, how can I save and read this custom attribute value back to CR during processing.

For this I have created a post exit to the Handler Class for CR Attachment CL_USMD_CR_GIL_ATTACHMENT

But why post exit, why not GeniL enhancement?

Because the standard class CL_USMD_CR_GIL_ATTACHMENT is final, we cannot provide this class as super class to our custom handler class. So created post exit for these methods to overcome this technical block.

In this post exit I have just updated my Z table for attachments and read Z table while displaying. Again, it will be applicable only to MDG Supplier Master.

Code Snippet for Post-Exit CHANGE_OBJECT

METHOD change_object.

IF zcl_oug_vm_util=>get_instance( )->check_app( ) EQ zcl_oug_vm_util=>gc_mdgs.

      IF rv_success EQ abap_true.

        DATA: ls_att_key           TYPE bss_cril_attachment_key,
              ls_att_attributes    TYPE bss_cril_attachment_attributes,
              ls_att_chg_attr      TYPE bss_cril_attachment_attributes,
              lt_attachment        TYPE usmd_ts_attachment,
              ls_attachment        TYPE usmd_s_attachment,
              ls_changed_attribute LIKE LINE OF it_changed_attributes,
              ls_attach            TYPE zou0065.

        FIELD-SYMBOLS:
          <lv_changed_attribute> TYPE any,
          <lv_attribute>         TYPE any.

        " Get the key of the changed attachment
        ls_att_key = is_key.

        " Get the changed attribute structure
        CALL METHOD iv_cont_obj->get_attributes
          IMPORTING
            es_attributes = ls_att_chg_attr.

        " Update custom table Z* to display back to UI.
        LOOP AT it_changed_attributes INTO ls_changed_attribute.
          ASSIGN COMPONENT ls_changed_attribute OF STRUCTURE ls_att_chg_attr TO <lv_changed_attribute>.
          CHECK sy-subrc = 0.
          IF ls_changed_attribute EQ 'ATTACH_TYPE'.
            ls_attach-mandt = sy-mandt.
            ls_attach-crequest = ls_att_key-cr_id.
            ls_attach-timestamp = ls_att_key-timestamp.
            ls_attach-attach_type = ls_att_chg_attr-attach_type.
            MODIFY z* FROM ls_attach.
            CLEAR ls_attach.
          ENDIF.
        ENDLOOP.

      ENDIF.
    ENDIF.

  ENDMETHOD.

Code Snippet for Post-Exit GET_ATTRIBUTES

METHOD GET_ATTRIBUTES
IF zcl_oug_vm_util=>get_instance( )->check_app( ) EQ zcl_oug_vm_util=>gc_mdgs.

      DATA ls_key TYPE bss_cril_note_key.
      DATA lt_attachments TYPE usmd_ts_attachment.
      DATA ls_attachments LIKE LINE OF lt_attachments.
      DATA ls_genil_attachment_attr TYPE bss_cril_attachment_attributes.

      ls_key = is_key.

      " Get Instance for API
      DATA(go_mdg_conv) = cl_usmd_conv_som_gov_api=>get_instance( iv_model_name = zcl_oug_vm_util=>gc_model ).

      " Get attachement attributes
      IF go_mdg_conv IS BOUND.
        TRY.
            CALL METHOD go_mdg_conv->if_usmd_conv_som_gov_cr~get_attachment_list
              EXPORTING
                if_with_content = space
              RECEIVING
                rt_attachment   = lt_attachments.
          CATCH cx_usmd_gov_api_core_error .
            RETURN.
        ENDTRY.
      ENDIF.

      READ TABLE lt_attachments INTO ls_attachments WITH KEY usmd_acreated_at = ls_key-timestamp.
      IF sy-subrc = 0.
        ls_genil_attachment_attr-created_by  = ls_attachments-usmd_acreated_by.
        ls_genil_attachment_attr-content     = ls_attachments-usmd_content.
        ls_genil_attachment_attr-explanation = ls_attachments-usmd_explanation.
        ls_genil_attachment_attr-file_size   = ls_attachments-usmd_file_size.
        ls_genil_attachment_attr-file_type   = ls_attachments-usmd_file_type.
        ls_genil_attachment_attr-language    = ls_attachments-usmd_language.
        ls_genil_attachment_attr-link        = ls_attachments-usmd_link.
        ls_genil_attachment_attr-title       = ls_attachments-usmd_title.
        ls_genil_attachment_attr-timestamp   = ls_attachments-usmd_acreated_at.
        SELECT crequest,
               attach_type
               FROM z* INTO @DATA(ls_attach_type)
               WHERE crequest = @go_mdg_conv->mv_crequest_id
               AND timestamp = @ls_genil_attachment_attr-timestamp.
        ENDSELECT.
        IF sy-subrc EQ 0.
          ls_genil_attachment_attr-attach_type = ls_attach_type-attach_type.
        ENDIF.
      ELSE.
        "??????
      ENDIF.

      iv_cont_obj->set_attributes( ls_genil_attachment_attr ).
    ENDIF.

  ENDMETHOD.

Now the Development is Completed! Let’s test the development 😊

Let’s open the change request, which is having both HR and Bank related attachments.

I logged in with user who don’t have authorization to view HR related attachments.

We can see the warning message related to HR related attachments and this particular user cannot perform any action (which means download/view) on HR attachments.

Now I logged in with user who don’t have authorization to view Bank related attachments.

Additional Content:

As I mentioned in the beginning of this post, this development should be applicate only to MDG-Supplier.

So, in my coding I always restricted this custom logic using utility class which will check whether the Change Request has been initiated from MDG Supplier.

Here is the Code Snippet for the same.

DATA : GV_APP   TYPE CHAR1,
       lv_value TYPE string,
       lv_key   TYPE string.

*Using Application Parameter
      DATA(lr_fpm) = cl_fpm=>get_instance( ).

      IF lr_fpm IS NOT INITIAL.

        CALL METHOD lr_fpm->mo_app_parameter->get_value
          EXPORTING
            iv_key   = 'OTC'
          IMPORTING
            ev_value = lv_value.

        IF lv_value IS NOT INITIAL.
          IF lv_value EQ '266'.    "266- MDG-S BO Type
            me->gv_app = 'S'.
          ELSEIF lv_value EQ '159' "159- MDG-C BO Type 
            me->gv_app = 'C'.
          ENDIF.
        ENDIF.

      ENDIF.

Conclusion: 

Thank you for reading my blog.

In this blog post I tried to cover all the development tasks. So, I hope this might be helpful for some one’s similar scenario.

Please drop your comments, valuable suggestions and if any help is required. I would be happy to assist. 😊

Thank you.

Best Regards

Mani


文章来源: https://blogs.sap.com/2023/10/20/mdg-change-request-attachments-hide-disable-attachments-in-mdg-cr-based-on-user-role/
如有侵权请联系:admin#unsafe.sh