ABAP - 사용자 권한 부여 증빙 관리 프로그램__User Authorization Documentation Management

감귤은탱귤·2024년 10월 9일

ABAP - BC 프로그램

목록 보기
12/14
post-thumbnail

◾ 모듈 : BC
◾ 기능 설명 : 사용자 권한 부여 증빙 관리 (ITGC 권한부여 이력 증명)
🔰 New Syntax 사용

◾ 사용 예시 :
1. 사용자에게 사전에 ZBC_CTRL_ROLE 테이블 정의된 롤 부여 시, 해당 부여에 대한 증빙자료(URL) 를 팝업으로 요청
2. 부여한 권한 중 디버깅 수정 권한이 있을 경우, 해당 부여 이력의 증빙을 토대로 데이터 변경(SE16N_CD_KEY, SM20) 로그에 대한 자동 매핑

테이블 ZBC_CTRL_ROLE 을 통해, 증빙을 요청할 특정 롤을 설정할 수 있다.

  • 해당 테이블에 등록한 롤 중, 디버깅 수정 롤에 대해서는 TAG 에 DEBUG_EDIT 을 붙여야 데이터 변경 이력에 대한 증빙이 자동으로 매핑된다.
    (디버깅 수정 롤_TAG-DEBUG_EDIT 은 반드시 1개여야 한다.)

<수정 이력>
◾ (수정1) 2026.01.12 - SE16N_CD_KEY 데이터 셀렉트 조건 수정
◾ (수정2) 2026.03.12 - SE16N_CD_KEY 데이터 셀렉트 조건 수정2
◾ (수정2) 2026.03.12 - SM20 셀렉트 조건 수정
◾ (수정2) 2026.03.12 - 테이블 키 필드 추가 및 권한 회수 이력 로직 개선
◾ (수정2) 2026.03.12 - 권한 회수 일자, 수기 입력 기능 추가



1. 소스 코드

1-1. 메인 프로그램

***********************************************************************
* Report            : ZBC_EVID_CONTROL                                *
* Module/Sub-Module : BC                                              *
* Description       : Role Assignment Evidence Control Program        *
***********************************************************************
*                          MODIFICATION LOG                           *
*                                                                     *
* DATE       AUTHORS            DESCRIPTION                           *
* ---------- ------------------ ------------------------------------- *
* 2024.10.09  YHJ               Initial Release                       *           
* 2024.10.24  YHJ               Feature improvements                  *
* 2026.01.12  YHJ               Edit SE16N_CD_KEY Select Join         *
*                                                                     *
***********************************************************************

REPORT ZBC_EVID_CONTROL.

*----------------------------------------------------------------------*
* TYPE-POOLS
*----------------------------------------------------------------------*
TYPE-POOLS: SLIS, ICON.

*----------------------------------------------------------------------*
* TABLES
*----------------------------------------------------------------------*
TABLES: SSCRFIELDS, ZBC_EVID_DATA.

*----------------------------------------------------------------------*
* DATA
*----------------------------------------------------------------------*

DATA: BEGIN OF GT_EVID OCCURS 0,
        SEL(1)   TYPE C.
        INCLUDE STRUCTURE ZBC_EVID_DATA.
DATA: END OF GT_EVID.

DATA: BEGIN OF GT_CTRL_ROLE OCCURS 0,
        SEL(1)   TYPE C.
        INCLUDE STRUCTURE ZBC_CTRL_ROLE.
DATA: END OF GT_CTRL_ROLE.

DATA: BEGIN OF GT_SE16N OCCURS 0,
        SEL(1)        TYPE C,
        LINECOLOR(4)  TYPE C,
        EVID_URL      TYPE AGR_URL,
        TARGET_ROLE   LIKE GT_EVID-TARGET_ROLE,
        ACT_DATE      LIKE GT_EVID-ACT_DATE,
        ACT_TIME      LIKE GT_EVID-ACT_TIME,
        REVOKE_DATE   LIKE GT_EVID-REVOKE_DATE,
        REVOKE_TIME   LIKE GT_EVID-REVOKE_TIME.
        INCLUDE STRUCTURE SE16N_CD_KEY.
DATA: END OF GT_SE16N.

DATA: BEGIN OF GT_SM20 OCCURS 0,
        SEL(1)        TYPE C,
        LINECOLOR(4)  TYPE C,
        EVID_URL      TYPE AGR_URL,
        TARGET_ROLE   LIKE GT_EVID-TARGET_ROLE,
        ACT_DATE      LIKE GT_EVID-ACT_DATE,
        ACT_TIME      LIKE GT_EVID-ACT_TIME,
        REVOKE_DATE   LIKE GT_EVID-REVOKE_DATE,
        REVOKE_TIME   LIKE GT_EVID-REVOKE_TIME.
        INCLUDE TYPE RSAU_S_RESULT.
DATA: END OF GT_SM20.

DATA: FUNCTXT      TYPE SMP_DYNTXT.

DATA: GT_EVENT     TYPE SLIS_T_EVENT WITH HEADER LINE.

DATA: GV_COUNT     TYPE I,
      GV_MENU      LIKE SY-UCOMM.

*----------------------------------------------------------------------*
* SELECTION-SCREEN
*----------------------------------------------------------------------*

SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE t101.

  SELECTION-SCREEN SKIP 1.

  SELECTION-SCREEN BEGIN OF BLOCK b2 WITH FRAME TITLE t201.

    SELECT-OPTIONS: S_DATE    FOR SY-DATUM NO-EXTENSION.

  SELECTION-SCREEN END OF BLOCK b2.

  SELECTION-SCREEN SKIP 1.

  SELECTION-SCREEN BEGIN OF BLOCK b3 WITH FRAME TITLE t301.

    SELECT-OPTIONS: S_USER    FOR SY-UNAME,
                    S_AGRN    FOR ZBC_EVID_DATA-TARGET_ROLE.

    SELECTION-SCREEN SKIP 1.

    PARAMETERS: P_ACTUSR      LIKE SY-UNAME.

    SELECTION-SCREEN SKIP 1.

    PARAMETERS: P_AURL        TYPE AGR_URL.

  SELECTION-SCREEN END OF BLOCK b3.

  SELECTION-SCREEN SKIP 1.

  PARAMETERS: P_EDIT AS CHECKBOX DEFAULT ''.

SELECTION-SCREEN END OF BLOCK b1.


SELECTION-SCREEN: FUNCTION KEY 1, FUNCTION KEY 2, FUNCTION KEY 3, FUNCTION KEY 4.

AT SELECTION-SCREEN.
  PERFORM MENU_SELECT.

AT SELECTION-SCREEN OUTPUT.
  PERFORM MODIFY_SCREEN.
  CLEAR: P_EDIT.

*----------------------------------------------------------------------*
* INITIALIZATION                                                       *
*----------------------------------------------------------------------*
INITIALIZATION.

  PERFORM MENU_BAR.

  MOVE 'ITGC - SAP Data Change / Debug Evidence Control' TO t101.
  MOVE '' TO t201.
  MOVE 'Other Option' TO t301.

*----------------------------------------------------------------------*
* START-OF-SELECTION.
*----------------------------------------------------------------------*
START-OF-SELECTION.

  "### 백그라운드 수행
  IF SY-BATCH = 'X'.


  "### 프론트 수행
  ELSE.

    CLEAR: GV_MENU, GV_COUNT.
    GV_MENU = SY-UCOMM.

    PERFORM SELECT_DATA.

    PERFORM VIEW_DATA.

  ENDIF.

*----------------------------------------------------------------------*
* END-OF-SELECTION.
*----------------------------------------------------------------------*
END-OF-SELECTION.


*&---------------------------------------------------------------------*
*& ZBC_ITGC_EVID_CTRL_F01
*&---------------------------------------------------------------------*

*&---------------------------------------------------------------------*
*&      Form  MODIFY_SCREEN
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*  -->  p1        text
*  <--  p2        text
*----------------------------------------------------------------------*
FORM MODIFY_SCREEN .

  %_S_DATE_%_APP_%-TEXT   = 'Date'.

  %_S_USER_%_APP_%-TEXT   = 'Target User'.
  %_S_AGRN_%_APP_%-TEXT   = 'Target Role'.

  %_P_ACTUSR_%_APP_%-TEXT = 'Changed User'.
  %_P_AURL_%_APP_%-TEXT   = 'Evid. URL String'.

  %_P_EDIT_%_APP_%-TEXT   = ' Evid. URL Edit'.

ENDFORM.

*&---------------------------------------------------------------------*
*&      Form  MENU_BAR
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*  -->  p1        text
*  <--  p2        text
*----------------------------------------------------------------------*
FORM MENU_BAR .

  FUNCTXT-ICON_ID = ICON_ANNOTATION.
  FUNCTXT-QUICKINFO = 'FILL_BLANK_URL'.
  FUNCTXT-ICON_TEXT = 'Fill Blanked URL'.
  SSCRFIELDS-FUNCTXT_01 = FUNCTXT.

  FUNCTXT-ICON_ID = ICON_PROTOCOL.
  FUNCTXT-QUICKINFO = 'EVID_SE16N_CD'.
  FUNCTXT-ICON_TEXT = 'Evid. SE16N_CD'.
  SSCRFIELDS-FUNCTXT_02 = FUNCTXT.

  FUNCTXT-ICON_ID = ICON_PROTOCOL.
  FUNCTXT-QUICKINFO = 'EVID_SM20'.
  FUNCTXT-ICON_TEXT = 'Evid. SM20'.
  SSCRFIELDS-FUNCTXT_03 = FUNCTXT.

  FUNCTXT-ICON_ID = ICON_REPORT.
  FUNCTXT-QUICKINFO = 'CONTROL_ROLE'.
  FUNCTXT-ICON_TEXT = 'Control Role'.
  SSCRFIELDS-FUNCTXT_04 = FUNCTXT.

ENDFORM.

*&---------------------------------------------------------------------*
*&      Form  MENU_SELECT
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*  -->  p1        text
*  <--  p2        text
*----------------------------------------------------------------------*
FORM MENU_SELECT .

  CLEAR: GV_MENU.
  GV_MENU = SY-UCOMM.
  
  CASE GV_MENU.

    "### FILL URL 메뉴
    "### URL 이 비어있는 항목에 증빙을 추가할 수 있도록, 수정 모드 제공
    WHEN 'FC01'.

      "### ZBC_EVID_DATA-EVID_URL 이 비어있는 데이터만 셀렉트
      PERFORM SELECT_DATA_FC01.

      "### 해당 데이터를 담은채로 VIEW 폼으로 보냄
      PERFORM VIEW_DATA.

    "### EVID_SE16N_CD 메뉴
    WHEN 'FC02'.

      "### 입력조건 S_DATE 체크
      "### SAL_DATE LOW(시작일) 값이 비어있을 경우, 실행 차단
      IF S_DATE-LOW IS INITIAL.
        MESSAGE 'Please Enter the Start Date' TYPE 'E'.
      ENDIF.

      PERFORM SELECT_DATA_SE16N.
      PERFORM VIEW_SE16N_CD.

    "### EVID_SM20 메뉴
    WHEN 'FC03'.

      PERFORM SELECT_DATA_SM20.
      PERFORM VIEW_SM20.

    "### CONTROL ROLE 메뉴
    "### ZBC_CONTROL_ROLE 테이블 - 제어 롤 목록 추가/삭제/수정
    WHEN 'FC04'.

      PERFORM VIEW_CONTROL_ROLE_TABLE.


  ENDCASE.

ENDFORM.

*------------------------------------------------------------------*
* FORM SET_PF_STATUS
*------------------------------------------------------------------*
FORM SET_PF_STATUS  USING PI_EXTAB    TYPE SLIS_T_EXTAB.

  DATA: BEGIN OF LT_EXCL OCCURS 0,
          MENU(20)        TYPE C.
  DATA: END OF LT_EXCL.

  CASE GV_MENU.

    WHEN SPACE.

      IF P_EDIT IS INITIAL.
        LT_EXCL-MENU = '&DATA_SAVE'. APPEND LT_EXCL.
      ELSE.
        LT_EXCL-MENU = 'F_ADJ'. APPEND LT_EXCL.
      ENDIF.

      SET PF-STATUS 'S110' EXCLUDING LT_EXCL.
      
    WHEN 'FC01'.

      LT_EXCL-MENU = 'F_ADJ'.   APPEND LT_EXCL.
      LT_EXCL-MENU = 'M_EDIT'.  APPEND LT_EXCL.
      LT_EXCL-MENU = 'DELE'.    APPEND LT_EXCL.
      SET PF-STATUS 'S110' EXCLUDING LT_EXCL.

    WHEN 'FC02'.

      LT_EXCL-MENU = 'F_ADJ'.      APPEND LT_EXCL.
      LT_EXCL-MENU = 'M_EDIT'.     APPEND LT_EXCL.
      LT_EXCL-MENU = '&DATA_SAVE'. APPEND LT_EXCL.
      LT_EXCL-MENU = 'DELE'.       APPEND LT_EXCL.
      SET PF-STATUS 'S110' EXCLUDING LT_EXCL.

    WHEN 'FC03'.

      LT_EXCL-MENU = 'F_ADJ'.      APPEND LT_EXCL.
      LT_EXCL-MENU = 'M_EDIT'.      APPEND LT_EXCL.
      LT_EXCL-MENU = '&DATA_SAVE'. APPEND LT_EXCL.
      LT_EXCL-MENU = 'DELE'.       APPEND LT_EXCL.
      SET PF-STATUS 'S110' EXCLUDING LT_EXCL.

    WHEN 'FC04'.

      "### Control Role 메뉴에는 자체 저장 버튼이 있으므로, SAP Std SAVE 버튼은 Inactive 처리
      IF P_EDIT IS INITIAL.
        LT_EXCL-MENU = 'SAVE'. APPEND LT_EXCL.
      ENDIF.

      SET PF-STATUS 'S100' EXCLUDING LT_EXCL.

    WHEN OTHERS.

  ENDCASE.


ENDFORM.

*------------------------------------------------------------------*
* FORM USER_COMMAND_DISP
*------------------------------------------------------------------*
FORM USER_COMMAND_DISP  USING PI_UCOMM    LIKE SY-UCOMM
                              PI_SELFIELD TYPE SLIS_SELFIELD.

  DATA: TT_EVID LIKE TABLE OF ZBC_EVID_DATA WITH HEADER LINE.

  CASE PI_UCOMM.

    "### EVID URL 증빙 저장
    WHEN '&DATA_SAVE'.

      CLEAR: TT_EVID, TT_EVID[].

      "### GV_MENU = 'FC01' 일 경우, FILL_BLANK_URL 모드에서 저장
      IF GV_MENU = 'FC01'.

        LOOP AT GT_EVID WHERE EVID_URL IS NOT INITIAL.

          MOVE-CORRESPONDING GT_EVID TO TT_EVID. APPEND TT_EVID.
          MODIFY ZBC_EVID_DATA FROM TABLE TT_EVID.

          "### FILL_BLANK_URL 모드일 시, EVID_URL 이 비어있는 항목만 출력되어야 하므로,
          "### EVID_URL 이 입력된 항목은 GT_EVID 에서 DELETE 한다.
          DELETE GT_EVID.

        ENDLOOP.

        MESSAGE 'Saved Data' TYPE 'S'.

      ELSE.

        LOOP AT GT_EVID.

          MOVE-CORRESPONDING GT_EVID TO TT_EVID. APPEND TT_EVID.
          MODIFY ZBC_EVID_DATA FROM TABLE TT_EVID.

        ENDLOOP.

        MESSAGE 'Saved Data' TYPE 'S'.

      ENDIF.

    "### ALV 더블 클릭 이벤트
    WHEN '&IC1'.

      DATA: HTTP_URL TYPE STRING.

      "### EVID_URL 필드에 대해서, 더블클릭 시, 브라우저로 URL 오픈 (기본 크롬 설정)
      "### 단 URL 수정 모드일때 및 Fill Blank URL 모드일때는 제외.
      IF PI_SELFIELD-FIELDNAME = 'EVID_URL'
         AND PI_SELFIELD-VALUE NE SPACE
         AND P_EDIT IS INITIAL
         AND GV_MENU NE 'FC01'.

        HTTP_URL = PI_SELFIELD-VALUE.

        CALL METHOD CL_GUI_FRONTEND_SERVICES=>EXECUTE
          EXPORTING
            APPLICATION = 'chrome.exe'
            PARAMETER   = HTTP_URL.

      ENDIF.

    "### 새로고침 버튼
    WHEN '&NTE'.

      CLEAR: GT_EVID, GT_EVID[].

      CASE GV_MENU.

        WHEN SPACE.
          PERFORM SELECT_DATA.

        WHEN 'FC01'.
          PERFORM SELECT_DATA_FC01.

        WHEN 'FC02'.
          PERFORM SELECT_DATA_SE16N.

        WHEN 'FC03'.
          PERFORM SELECT_DATA_SM20.

      ENDCASE.

    WHEN 'F_ADJ'.

      CLEAR: TT_EVID, TT_EVID[].

      LOOP AT GT_EVID WHERE SEL = 'X'.

        IF GT_EVID-MANUAL_EDIT IS INITIAL.
          MESSAGE '권한 회수 일자 강제 조정은 수기 입력건에 대해서만 가능합니다.' TYPE 'S' DISPLAY LIKE 'E'.

        ENDIF.


        DATA(LV_TABKEY) = |{ SY-MANDT }%{ GT_EVID-TARGET_ROLE }%{ GT_EVID-TARGET_USER }%{ GT_EVID-VAILD_FROM }%{ GT_EVID-VAILD_TO }%|.

        DATA: LT_T1 LIKE TABLE OF CDPOS WITH HEADER LINE,
              LT_T2 LIKE TABLE OF CDHDR WITH HEADER LINE.

        SELECT * INTO CORRESPONDING FIELDS OF TABLE @LT_T1
          FROM CDPOS AS A
          LEFT OUTER JOIN CDHDR AS B ON A~CHANGENR = B~CHANGENR
          WHERE A~TABKEY LIKE @LV_TABKEY
            AND B~USERNAME =  @GT_EVID-CHG_USER
            AND B~UDATE    =  @GT_EVID-ACT_DATE
            AND B~UTIME    =  @GT_EVID-ACT_TIME
            AND A~CHNGIND  = 'I'.

        READ TABLE LT_T1 INDEX 1.

        SELECT * INTO CORRESPONDING FIELDS OF TABLE @LT_T2
          FROM CDHDR AS A
          LEFT OUTER JOIN CDPOS AS B ON A~CHANGENR = B~CHANGENR
          WHERE B~TABKEY LIKE @LV_TABKEY
            AND B~CHANGENR > @LT_T1-CHANGENR
            AND B~CHNGIND  = 'D'.

        READ TABLE LT_T2 INDEX 1.

        "### Change Document 셀렉트가 정상적이라면,
        IF SY-SUBRC = 0.

          "### 만약 셀렉트한 Change Document 가 1건 이상이면, LT_CDDATA UDATE, UTIME 을 오름차순으로 정리하여,
          "### 가장 빠른 UDATE, UTIME (INDEX 1) 를 REVOKE DATE, TIME 으로 설정. (같은 유효기간의 롤을 중복으로 가질수 없기 때문)

          GT_EVID-REVOKE_DATE = LT_T2-UDATE.
          GT_EVID-REVOKE_TIME = LT_T2-UTIME.
          GT_EVID-MANUAL_EDIT = ''.

          MODIFY GT_EVID.

        ENDIF.

        MOVE-CORRESPONDING GT_EVID TO TT_EVID. APPEND TT_EVID.

      ENDLOOP.

      MODIFY ZBC_EVID_DATA FROM TABLE TT_EVID.

    WHEN 'DELE'.

      DATA: LV_CNT(4) TYPE I,
            LV_TEXT   TYPE STRING,
            LV_ANS    TYPE C.

      "### ALV 에서 선택한 항목에 대해서만 삭제 작업
      LV_CNT = REDUCE #( INIT i = 0 FOR LS IN GT_EVID
                         WHERE ( SEL = 'X' )
                         NEXT I += 1 ).
      LV_TEXT = |Sure to Delete { LV_CNT } Entry?|.

      "### 삭제 확인 팝업
      CALL FUNCTION 'POPUP_TO_CONFIRM'
        EXPORTING
          TITLEBAR      = 'DELETE ENTRY'
          TEXT_QUESTION = LV_TEXT
          TEXT_BUTTON_1 = 'YES'
          TEXT_BUTTON_2 = 'NO'
          DISPLAY_CANCEL_BUTTON = SPACE
        IMPORTING
          ANSWER = LV_ANS.

      "### ITSM 삭제 YES
      IF LV_ANS = '1'.

        LOOP AT GT_EVID WHERE SEL = 'X'.
          DELETE FROM ZBC_EVID_DATA WHERE ACT_DATE    = GT_EVID-ACT_DATE
                                 AND ACT_TIME    = GT_EVID-ACT_TIME
                                 AND TARGET_USER = GT_EVID-TARGET_USER
                                 AND TARGET_ROLE = GT_EVID-TARGET_ROLE.
        ENDLOOP.

        DELETE GT_EVID WHERE SEL = 'X'.

      ENDIF.

    WHEN 'M_EDIT'.

      DATA: LT_POPUP  LIKE SVAL OCCURS 0 WITH HEADER LINE.
      DATA: LV_RET    TYPE C.


      DATA(LV_SEL) = 0.

      LOOP AT GT_EVID WHERE SEL = 'X'.
        LV_SEL += 1.
      ENDLOOP.

      IF LV_SEL = 1.

        CLEAR: TT_EVID, TT_EVID[].

        READ TABLE GT_EVID WITH KEY SEL = 'X'.
        DATA(LV_TABIX) = SY-TABIX.

        LT_POPUP-TABNAME   = 'ZBC_EVID_DATA'.
        LT_POPUP-FIELDNAME = 'REVOKE_DATE'.
        LT_POPUP-FIELDTEXT = 'Revoke Date'.
        APPEND LT_POPUP. CLEAR LT_POPUP.

        LT_POPUP-TABNAME   = 'ZBC_EVID_DATA'.
        LT_POPUP-FIELDNAME = 'REVOKE_TIME'.
        LT_POPUP-FIELDTEXT = 'Revoke Time'.
        APPEND LT_POPUP. CLEAR LT_POPUP.

        "### 팝업 출력
        CALL FUNCTION 'POPUP_GET_VALUES'
          EXPORTING
            POPUP_TITLE       = 'Revoke Edit'
          IMPORTING
            RETURNCODE        = LV_RET
          TABLES
            FIELDS            = LT_POPUP
          EXCEPTIONS
            ERROR_IN_FIELDS   = 1
            OTHERS            = 2.

        IF LV_RET IS INITIAL.

          READ TABLE LT_POPUP WITH KEY FIELDNAME = 'REVOKE_DATE'. GT_EVID-REVOKE_DATE = LT_POPUP-VALUE.

          IF LT_POPUP-VALUE < GT_EVID-ACT_DATE.

            MESSAGE '권한 회수 날짜는 부여 날짜보다 빠를 수 없습니다.' TYPE 'S' DISPLAY LIKE 'E'.
            REJECT.

          ENDIF.


          READ TABLE LT_POPUP WITH KEY FIELDNAME = 'REVOKE_TIME'. GT_EVID-REVOKE_TIME = LT_POPUP-VALUE.

          GT_EVID-MANUAL_EDIT = 'X'.

          MODIFY GT_EVID INDEX LV_TABIX.

          MOVE-CORRESPONDING GT_EVID TO TT_EVID. APPEND TT_EVID.

          MODIFY ZBC_EVID_DATA FROM TABLE TT_EVID.

        ENDIF.

      ELSE.

        MESSAGE '수기 수정은 1건 단위로만 가능합니다.' TYPE 'S'.

      ENDIF.


  ENDCASE.

  "### ALV 리프레시 설정
  PI_SELFIELD-REFRESH = 'X'.
  PI_SELFIELD-COL_STABLE = 'X'.
  PI_SELFIELD-ROW_STABLE = 'X'.

ENDFORM.

*&---------------------------------------------------------------------*
*& Form SELECT_DATA
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& -->  p1        text
*& <--  p2        text
*&---------------------------------------------------------------------*
FORM SELECT_DATA .

  IF P_ACTUSR IS INITIAL. P_ACTUSR = '%'. ENDIF.
  IF P_AURL   IS INITIAL. P_AURL = '%'. ENDIF.

  CLEAR: GT_EVID, GT_EVID[].
  SELECT * INTO CORRESPONDING FIELDS OF TABLE GT_EVID
    FROM ZBC_EVID_DATA
    WHERE ACT_DATE     IN S_DATE
      AND TARGET_USER  IN S_USER
      AND TARGET_ROLE  IN S_AGRN
      AND CHG_USER     LIKE P_ACTUSR
      AND EVID_URL 	   LIKE P_AURL.

ENDFORM.

*&---------------------------------------------------------------------*
*& Form SELECT_DATA_FC01
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& -->  p1        text
*& <--  p2        text
*&---------------------------------------------------------------------*
FORM SELECT_DATA_FC01 .

  "### FC01 (FILL_BLANK_URL 메뉴) 데이터 셀렉트
  CLEAR: GT_EVID, GT_EVID[].

  SELECT * INTO CORRESPONDING FIELDS OF TABLE GT_EVID
    FROM ZBC_EVID_DATA
    WHERE EVID_URL = SPACE.

  "### SELET DATA SORT
  SORT GT_EVID BY ACT_DATE ACT_TIME TARGET_USER TARGET_ROLE.

ENDFORM.

*&---------------------------------------------------------------------*
*& Form SELECT_DATA_SE16N
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& -->  p1        text
*& <--  p2        text
*&---------------------------------------------------------------------*
FORM SELECT_DATA_SE16N .

  CLEAR: GT_SE16N, GT_SE16N[].

  "### ZBC_CTRL_ROLE 테이블의 증빙 제어  중,
  "### DEBUG_EDIT 태그가 있는 롤을 디버깅 롤로 인식하여 증빙 검색
  "### DEBUG_EDIT 태그는 모든  중에,  한개에만 존재 가능.
  SELECT SINGLE VALUE INTO @DATA(TV_DEBUG_ROLE)
    FROM ZBC_CTRL_ROLE
    WHERE ITEM = 'ROLE'
      AND TAG  = 'DEBUG_EDIT'.

  "### JOIN 조건 개선
  SELECT a~*,
         b~EVID_URL,
         b~TARGET_ROLE,
         b~ACT_DATE,
         b~ACT_TIME,
         b~REVOKE_DATE,
         b~REVOKE_TIME
    FROM SE16N_CD_KEY AS A
    LEFT OUTER JOIN ZBC_EVID_DATA AS B  ON A~UNAME = B~TARGET_USER
                                  AND ( ( ( A~SDATE = B~ACT_DATE AND A~SDATE = B~REVOKE_DATE ) AND A~STIME BETWEEN B~ACT_TIME AND B~REVOKE_TIME )
                                     OR ( ( A~SDATE > B~ACT_DATE AND A~SDATE = B~REVOKE_DATE ) AND A~STIME <= B~REVOKE_TIME )
                                     OR ( ( A~SDATE > B~ACT_DATE AND A~SDATE < B~REVOKE_DATE ) )
                                     OR ( ( A~SDATE = B~ACT_DATE AND A~SDATE < B~REVOKE_DATE ) AND A~STIME >= B~ACT_TIME ) )
                                  AND B~TARGET_ROLE = @TV_DEBUG_ROLE
    WHERE A~SDATE IN @S_DATE
    INTO CORRESPONDING FIELDS OF TABLE @GT_SE16N.

  "### EVID_URL 이 없는 필드는 노란색 하이라이트 표시
  LOOP AT GT_SE16N WHERE EVID_URL IS INITIAL.
    GT_SE16N-LINECOLOR = 'C300'.
    MODIFY GT_SE16N.
  ENDLOOP.

  SORT GT_SE16N BY SDATE STIME TAB UNAME.

ENDFORM.

*&---------------------------------------------------------------------*
*& Form SELECT_DATA_SM20
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& -->  p1        text
*& <--  p2        text
*&---------------------------------------------------------------------*
FORM SELECT_DATA_SM20 .

  DATA: S_ITAB      TYPE TABLE OF RSPARAMS WITH HEADER LINE.

  DATA: TT_SM20     TYPE RSAU_T_RESULT  WITH HEADER LINE,
        LR_DATA     TYPE REF TO DATA.

  DATA: LT_EVID     LIKE TABLE OF ZBC_EVID_DATA WITH HEADER LINE.


  FIELD-SYMBOLS : <FS_TABLE> TYPE ANY TABLE,
                  <FS_LINE>  TYPE ANY.

  CL_SALV_BS_RUNTIME_INFO=>SET( EXPORTING DISPLAY  = ABAP_FALSE
                                          METADATA = ABAP_FALSE
                                          DATA     = ABAP_TRUE ).

  S_ITAB-SELNAME = 'EVENTS'.
  S_ITAB-SIGN = 'I'.
  S_ITAB-OPTION = 'EQ'.
  S_ITAB-LOW = 'CUL'.
  APPEND S_ITAB. CLEAR: S_ITAB.

  S_ITAB-SELNAME = 'TCODE'.
  S_ITAB-SIGN = 'I'.
  S_ITAB-OPTION = 'NE'.
  S_ITAB-LOW = 'SE16N'.
  APPEND S_ITAB. CLEAR: S_ITAB.

  "### SAL_DATE HIGH(종료일) 이 없을 경우 시작일과 같도록 강제 설정
  IF S_DATE-HIGH IS INITIAL.
    S_DATE-HIGH = S_DATE-LOW.
  ENDIF.

  "### SAL_DATE LOW(시작일) 값이 비어있을 경우, 실행 차단
  IF S_DATE-LOW IS INITIAL.
    MESSAGE 'Please Enter the Start Date' TYPE 'E'.
  ENDIF.

  "### ABAP MEMORY 를 사용하여 데이터 가져오기
  SUBMIT RSAU_READ_LOG WITH STRTDATE = S_DATE-LOW
                       WITH ENDDATE  = S_DATE-HIGH
                       WITH P_SELE = 1
                       WITH SELECTION-TABLE S_ITAB
                       AND RETURN.

  TRY.

      CL_SALV_BS_RUNTIME_INFO=>GET_DATA_REF( IMPORTING R_DATA = LR_DATA ).
      ASSIGN LR_DATA->* TO <FS_TABLE>.

    CATCH CX_SALV_BS_SC_RUNTIME_INFO.

      MESSAGE 'Unable to retrieve ALV data' TYPE 'E'.

  ENDTRY.

  CL_SALV_BS_RUNTIME_INFO=>CLEAR_ALL( ).


  "### Field Symbols 데이터를 LT_SM20 인터널 테이블로 옮겨 담기
  LOOP AT <FS_TABLE> ASSIGNING <FS_LINE>.
    MOVE-CORRESPONDING  <FS_LINE> TO TT_SM20.
    APPEND TT_SM20. CLEAR TT_SM20.
  ENDLOOP.


  "### ZBC_CTRL_ROLE 테이블의 증빙 제어 롤 중,
  "### DEBUG_EDIT 태그가 있는 롤을 디버깅 롤로 인식하여 증빙 검색
  "### DEBUG_EDIT 태그는 모든 롤 중에, 단 한개에만 존재 가능.
  SELECT SINGLE VALUE INTO @DATA(TV_DEBUG_ROLE)
    FROM ZBC_CTRL_ROLE
    WHERE ITEM = 'ROLE'
      AND TAG  = 'DEBUG_EDIT'.


  "### LT_SM20 테이블 매핑을 위해 ZBC_EVID_DATA 테이블 로드
  SELECT * INTO CORRESPONDING FIELDS OF TABLE @LT_EVID
    FROM ZBC_EVID_DATA
    WHERE ACT_DATE IN @S_DATE
      AND TARGET_ROLE = @TV_DEBUG_ROLE.


  "### 데이터 옮겨담기 전, GT_SM20 테이블 클리어
  CLEAR: GT_SM20, GT_SM20[].

  "### TT_SM20 데이터를 GT_SM20(ALV 테이블)로 옮겨 담기
  LOOP AT TT_SM20.

    MOVE-CORRESPONDING TT_SM20 TO GT_SM20.

    "### ZBC_EVID_DATA 테이블 데이터를 LT_EVID 테이블에 매핑
    LOOP AT LT_EVID WHERE TARGET_USER = TT_SM20-SLGUSER AND ( ACT_TIME < TT_SM20-SAL_TIME AND REVOKE_TIME > TT_SM20-SAL_TIME ).

      GT_SM20-EVID_URL    = LT_EVID-EVID_URL.
      GT_SM20-TARGET_ROLE = LT_EVID-TARGET_ROLE.
      GT_SM20-ACT_DATE    = LT_EVID-ACT_DATE.
      GT_SM20-ACT_TIME    = LT_EVID-ACT_TIME.
      GT_SM20-REVOKE_DATE = LT_EVID-REVOKE_DATE.
      GT_SM20-REVOKE_TIME = LT_EVID-REVOKE_TIME.

    ENDLOOP.

    "### EVID_URL 이 없는 필드는 노란색 하이라이트 표시
    IF GT_SM20-EVID_URL IS INITIAL.
      GT_SM20-LINECOLOR = 'C300'.
    ENDIF.

    APPEND GT_SM20. CLEAR GT_SM20.

  ENDLOOP.

ENDFORM.

*&---------------------------------------------------------------------*
*& Form VIEW_DATA
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& -->  p1        text
*& <--  p2        text
*&---------------------------------------------------------------------*
FORM VIEW_DATA .

  DATA: L_POS       TYPE I VALUE 0.

  DATA: LT_FIELDCAT TYPE SLIS_T_FIELDCAT_ALV WITH HEADER LINE,
        LT_LAYOUT   TYPE SLIS_LAYOUT_ALV.

  "### Build Field Catalog
  L_POS = L_POS + 1.
  LT_FIELDCAT-COL_POS     = L_POS.
  LT_FIELDCAT-FIELDNAME   = 'ACT_DATE'.
  LT_FIELDCAT-SELTEXT_M   = 'Grant Date'.
  LT_FIELDCAT-KEY         = 'X'.
  LT_FIELDCAT-OUTPUTLEN   = 8.
  APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

  L_POS = L_POS + 1.
  LT_FIELDCAT-COL_POS     = L_POS.
  LT_FIELDCAT-FIELDNAME   = 'ACT_TIME'.
  LT_FIELDCAT-SELTEXT_M   = 'Grant Time'.
  LT_FIELDCAT-KEY         = 'X'.
  LT_FIELDCAT-OUTPUTLEN   = 8.
  APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

  L_POS = L_POS + 1.
  LT_FIELDCAT-COL_POS     = L_POS.
  LT_FIELDCAT-FIELDNAME   = 'TARGET_USER'.
  LT_FIELDCAT-SELTEXT_M   = 'Target User'.
  LT_FIELDCAT-KEY         = 'X'.
  LT_FIELDCAT-OUTPUTLEN   = 12.
  APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

  L_POS = L_POS + 1.
  LT_FIELDCAT-COL_POS     = L_POS.
  LT_FIELDCAT-FIELDNAME   = 'TARGET_ROLE'.
  LT_FIELDCAT-SELTEXT_M   = 'Target Role'.
  LT_FIELDCAT-OUTPUTLEN   = 20.
  APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

  L_POS = L_POS + 1.
  LT_FIELDCAT-COL_POS     = L_POS.
  LT_FIELDCAT-FIELDNAME   = 'CHG_USER'.
  LT_FIELDCAT-SELTEXT_M   = 'Changed User'.
  LT_FIELDCAT-OUTPUTLEN   = 12.
  APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

  L_POS = L_POS + 1.
  LT_FIELDCAT-COL_POS     = L_POS.
  LT_FIELDCAT-FIELDNAME   = 'EVID_URL'.
  LT_FIELDCAT-SELTEXT_M   = 'Evid. URL'.
  LT_FIELDCAT-OUTPUTLEN   = 80.
  LT_FIELDCAT-HOTSPOT     = 'X'.
  LT_FIELDCAT-LOWERCASE   = 'X'.
  LT_FIELDCAT-EMPHASIZE   = 'C500'.
  "### 미등록 URL 입력 모드라면, URL 필드가 수정가능하게 EDIT 오픈
  IF SY-UCOMM = 'FC01' OR P_EDIT = 'X'.
    LT_FIELDCAT-EDIT        = 'X'.
    LT_FIELDCAT-EMPHASIZE   = ''.
    LT_FIELDCAT-HOTSPOT     = ''.
  ENDIF.
  APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

  L_POS = L_POS + 1.
  LT_FIELDCAT-COL_POS     = L_POS.
  LT_FIELDCAT-FIELDNAME   = 'REVOKE_DATE'.
  LT_FIELDCAT-SELTEXT_M   = 'Revoke Date'.
  LT_FIELDCAT-OUTPUTLEN   = 8.
  APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

  L_POS = L_POS + 1.
  LT_FIELDCAT-COL_POS     = L_POS.
  LT_FIELDCAT-FIELDNAME   = 'REVOKE_TIME'.
  LT_FIELDCAT-SELTEXT_M   = 'Revoke Time'.
  LT_FIELDCAT-OUTPUTLEN   = 8.
  APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

  L_POS = L_POS + 1.
  LT_FIELDCAT-COL_POS     = L_POS.
  LT_FIELDCAT-FIELDNAME   = 'MANUAL_EDIT'.
  LT_FIELDCAT-SELTEXT_M   = 'Flag'.
  LT_FIELDCAT-OUTPUTLEN   = 4.
  APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

  L_POS = L_POS + 1.
  LT_FIELDCAT-COL_POS     = L_POS.
  LT_FIELDCAT-FIELDNAME   = 'VAILD_FROM'.
  LT_FIELDCAT-SELTEXT_M   = 'From'.
  LT_FIELDCAT-OUTPUTLEN   = 10.
  APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

  L_POS = L_POS + 1.
  LT_FIELDCAT-COL_POS     = L_POS.
  LT_FIELDCAT-FIELDNAME   = 'VAILD_TO'.
  LT_FIELDCAT-SELTEXT_M   = 'To'.
  LT_FIELDCAT-OUTPUTLEN   = 10.
  APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

  "### ALV Layout 설정
  LT_LAYOUT-BOX_FIELDNAME = 'SEL'.
*  LT_LAYOUT-INFO_FIELDNAME = 'LINECOLOR'.
  IF SY-UCOMM IS INITIAL AND P_EDIT IS INITIAL. LT_LAYOUT-COLWIDTH_OPTIMIZE = 'X'. ENDIF.
*  LT_LAYOUT-ZEBRA = 'X'.
  LT_LAYOUT-BOX_TABNAME = 'GT_EVID'.


  "### 위에 설정된 Field Catalog  Layout  사용하여 ALV 리스트 출력 펑션 
  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
    EXPORTING
      I_CALLBACK_PROGRAM       = SY-REPID
      I_CALLBACK_USER_COMMAND  = 'USER_COMMAND_DISP'
      I_CALLBACK_PF_STATUS_SET = 'SET_PF_STATUS'
      "I_GRID_TITLE             = GV_ALV_HEADER
      "I_CALLBACK_TOP_OF_PAGE   = 'TOP-OF-PAGE'
      IT_EVENTS                = GT_EVENT[]
      IT_FIELDCAT              = LT_FIELDCAT[]
      IS_LAYOUT                = LT_LAYOUT
      "I_SAVE = 'A'
    TABLES
      T_OUTTAB = GT_EVID
    EXCEPTIONS
      PROGRAM_ERROR   = 1
      OTHERS          = 2.

ENDFORM.

*&---------------------------------------------------------------------*
*& Form VIEW_CONTROL_ROLE_TABLE
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& -->  p1        text
*& <--  p2        text
*&---------------------------------------------------------------------*
FORM VIEW_CONTROL_ROLE_TABLE .

  DATA: L_POS       TYPE I VALUE 0.

  DATA: LT_FIELDCAT TYPE SLIS_T_FIELDCAT_ALV WITH HEADER LINE,
        LT_LAYOUT   TYPE SLIS_LAYOUT_ALV.


  CLEAR: GT_CTRL_ROLE, GT_CTRL_ROLE[].
  SELECT * INTO CORRESPONDING FIELDS OF TABLE GT_CTRL_ROLE
    FROM ZBC_CTRL_ROLE.

  SORT GT_CTRL_ROLE BY ITEM VALUE.

  "### Build Field Catalog
  L_POS = L_POS + 1.
  LT_FIELDCAT-COL_POS     = L_POS.
  LT_FIELDCAT-FIELDNAME   = 'ITEM'.
  LT_FIELDCAT-SELTEXT_M   = 'ITEM'.
  LT_FIELDCAT-KEY         = 'X'.
  LT_FIELDCAT-OUTPUTLEN   = 10.
  APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

  L_POS = L_POS + 1.
  LT_FIELDCAT-COL_POS     = L_POS.
  LT_FIELDCAT-FIELDNAME   = 'VALUE'.
  LT_FIELDCAT-SELTEXT_M   = 'VALUE'.
  LT_FIELDCAT-KEY         = 'X'.
  LT_FIELDCAT-OUTPUTLEN   = 20.
  APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

  L_POS = L_POS + 1.
  LT_FIELDCAT-COL_POS     = L_POS.
  LT_FIELDCAT-FIELDNAME   = 'TAG'.
  LT_FIELDCAT-SELTEXT_M   = 'Tag'.
  LT_FIELDCAT-OUTPUTLEN   = 15.
  IF SY-UCOMM = 'FC04' AND P_EDIT = 'X'.
    LT_FIELDCAT-EDIT        = 'X'.
  ENDIF.
  APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

  L_POS = L_POS + 1.
  LT_FIELDCAT-COL_POS     = L_POS.
  LT_FIELDCAT-FIELDNAME   = 'TEXT'.
  LT_FIELDCAT-SELTEXT_M   = 'Short Desc'.
  LT_FIELDCAT-OUTPUTLEN   = 50.
  IF SY-UCOMM = 'FC04' AND P_EDIT = 'X'.
    LT_FIELDCAT-EDIT        = 'X'.
  ENDIF.
  APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.


  "### ALV Layout 설정
  LT_LAYOUT-BOX_FIELDNAME = 'SEL'.
*  LT_LAYOUT-INFO_FIELDNAME = 'LINECOLOR'.
*  LT_LAYOUT-COLWIDTH_OPTIMIZE = 'X'.
*  LT_LAYOUT-ZEBRA = 'X'.
  LT_LAYOUT-BOX_TABNAME = 'GT_CTRL_ROLE'.


  "### 위에 설정된 Field Catalog  Layout  사용하여 ALV 리스트 출력 펑션 
  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
    EXPORTING
      I_CALLBACK_PROGRAM       = SY-REPID
      I_CALLBACK_USER_COMMAND  = 'USER_COMMAND_CTRL_ROLE'
      I_CALLBACK_PF_STATUS_SET = 'SET_PF_STATUS'
      "I_GRID_TITLE             = GV_ALV_HEADER
      "I_CALLBACK_TOP_OF_PAGE   = 'TOP-OF-PAGE'
      "IT_EXCLUDING             = LT_EXCL[]
      "IT_EVENTS                = LT_EVENT[]
      IT_FIELDCAT              = LT_FIELDCAT[]
      IS_LAYOUT                = LT_LAYOUT
      "I_SAVE = 'A'
    TABLES
      T_OUTTAB = GT_CTRL_ROLE
    EXCEPTIONS
      PROGRAM_ERROR   = 1
      OTHERS          = 2.


ENDFORM.

*------------------------------------------------------------------*
* FORM USER_COMMAND_CTRL_ROLE
*------------------------------------------------------------------*
FORM USER_COMMAND_CTRL_ROLE  USING PI_UCOMM    LIKE SY-UCOMM
                                   PI_SELFIELD TYPE SLIS_SELFIELD.

  CASE PI_UCOMM.

    "### ITEM 신규 추가
    WHEN 'ADD_ITEM'.

      "### 팝업을 통해 신규 ITEM 정보를 받아온다.
      DATA: LT_POPUP  LIKE SVAL OCCURS 0 WITH HEADER LINE.
      DATA: LT_ADD    LIKE TABLE OF ZBC_CTRL_ROLE WITH HEADER LINE.
      DATA: LT_LOC    LIKE TABLE OF ZBC_CTRL_ROLE WITH HEADER LINE.
      DATA: LV_RET    TYPE C.

      LT_POPUP-TABNAME   = 'ZBC_CTRL_ROLE'.
      LT_POPUP-FIELDNAME = 'ITEM'.
      LT_POPUP-FIELDTEXT = 'ITEM'.
      LT_POPUP-FIELD_OBL = 'X'.
      LT_POPUP-VALUE = 'ROLE'.
      APPEND LT_POPUP. CLEAR LT_POPUP.

      LT_POPUP-TABNAME   = 'ZBC_CTRL_ROLE'.
      LT_POPUP-FIELDNAME = 'VALUE'.
      LT_POPUP-FIELDTEXT = 'VALUE'.
      LT_POPUP-FIELD_OBL = 'X'.
      APPEND LT_POPUP. CLEAR LT_POPUP.

      LT_POPUP-TABNAME   = 'ZBC_CTRL_ROLE'.
      LT_POPUP-FIELDNAME = 'TAG'.
      LT_POPUP-FIELDTEXT = 'Tag'.
      APPEND LT_POPUP. CLEAR LT_POPUP.

      LT_POPUP-TABNAME   = 'ZBC_CTRL_ROLE'.
      LT_POPUP-FIELDNAME = 'TEXT'.
      LT_POPUP-FIELDTEXT = 'Short Desc'.
      APPEND LT_POPUP. CLEAR LT_POPUP.

      "### 팝업 출력
      CALL FUNCTION 'POPUP_GET_VALUES'
        EXPORTING
          POPUP_TITLE       = 'Add ITEM'
        IMPORTING
          RETURNCODE        = LV_RET
        TABLES
          FIELDS            = LT_POPUP
        EXCEPTIONS
          ERROR_IN_FIELDS   = 1
          OTHERS            = 2.

      "### 데이터를 정상적으로 입력하고, POPUP Confirm  눌렀다면, 저장
      IF LV_RET IS INITIAL.

        LT_ADD-MANDT = SY-MANDT.
        READ TABLE LT_POPUP WITH KEY FIELDNAME = 'ITEM'.  LT_ADD-ITEM  = LT_POPUP-VALUE.
        READ TABLE LT_POPUP WITH KEY FIELDNAME = 'VALUE'. LT_ADD-VALUE = LT_POPUP-VALUE.
        READ TABLE LT_POPUP WITH KEY FIELDNAME = 'TAG'.   LT_ADD-TAG   = LT_POPUP-VALUE.
        READ TABLE LT_POPUP WITH KEY FIELDNAME = 'TEXT'.  LT_ADD-TEXT  = LT_POPUP-VALUE.
        APPEND LT_ADD.


        "### 태그 중, DEBUG_EDIT 태그는 유일한 태그이다.
        "### 따라서, 이미 DEBUG_EDIT 태그가 붙은 롤이 있다면,  이상 DEBUG_EDIT 태그를 붙일  없다.
        IF LT_ADD-TAG = 'DEBUG_EDIT'.
          READ TABLE GT_CTRL_ROLE WITH KEY TAG = 'DEBUG_EDIT'.
          IF SY-SUBRC = 0.
            MESSAGE |DEBUG_EDIT Role already Exists| TYPE 'E'.
            EXIT.
          ENDIF.
        ENDIF.

        "### 입력한 아이템이 ROLE 이라면, 실제 해당 ROLE  있는지 유효성 체크
        IF LT_ADD-ITEM = 'ROLE'.

          SELECT SINGLE AGR_NAME INTO @DATA(TV_AGR)
            FROM AGR_DEFINE
            WHERE AGR_NAME = @LT_ADD-VALUE.

          "### 해당 ROLE  없다면 EXIT.
          IF SY-SUBRC <> 0.
            MESSAGE |{ LT_ADD-VALUE } Role does not exist.| TYPE 'E'.
            EXIT.
          ENDIF.

        ENDIF.

        "### 최종적으로 기존 아이템과 중복값 체크
        READ TABLE GT_CTRL_ROLE WITH KEY MANDT = LT_ADD-MANDT
                                         ITEM  = LT_ADD-ITEM
                                         VALUE = LT_ADD-VALUE.

        "### 셀렉트 데이터가 없다면, 신규값이므로 테이블에 MODI, 인터널테이블에 APPEND
        IF SY-SUBRC <> 0.
          MODIFY ZBC_CTRL_ROLE FROM TABLE LT_ADD.
          MOVE-CORRESPONDING LT_ADD TO GT_CTRL_ROLE. APPEND GT_CTRL_ROLE.

          SORT GT_CTRL_ROLE.

          MESSAGE 'Saved ITEM' TYPE 'S'.

        ELSE.
          MESSAGE 'This ITEM already Exists.' TYPE 'E'.

        ENDIF.

      ENDIF.

    "### ITEM 삭제
    WHEN 'DEL_ITEM'.

      DATA: LV_CNT(3) TYPE I,
            LV_TEXT   TYPE STRING,
            LV_ANS    TYPE C.

      "### ALV 에서 선택한 항목에 대해서만 삭제 작업
      LV_CNT = REDUCE #( INIT i = 0 FOR LS IN GT_CTRL_ROLE
                         WHERE ( SEL = 'X' )
                         NEXT I += 1 ).
      LV_TEXT = |Sure to Delete { LV_CNT } item?|.

      "### 삭제 확인 팝업
      CALL FUNCTION 'POPUP_TO_CONFIRM'
        EXPORTING
          TITLEBAR      = 'DELETE ITEM'
          TEXT_QUESTION = LV_TEXT
          TEXT_BUTTON_1 = 'YES'
          TEXT_BUTTON_2 = 'NO'
          DISPLAY_CANCEL_BUTTON = SPACE
        IMPORTING
          ANSWER = LV_ANS.

      "### ITSM 삭제 YES
      IF LV_ANS = '1'.

        LOOP AT GT_CTRL_ROLE WHERE SEL = 'X'.
          DELETE FROM ZBC_CTRL_ROLE WHERE ITEM  = GT_CTRL_ROLE-ITEM
                                      AND VALUE = GT_CTRL_ROLE-VALUE.
        ENDLOOP.

        DELETE GT_CTRL_ROLE WHERE SEL = 'X'.

      ENDIF.

    WHEN 'SAVE'.

      DATA: TT_CTRL_ROLE LIKE TABLE OF ZBC_CTRL_ROLE WITH HEADER LINE.
      DATA: P_REF         TYPE REF TO CL_GUI_ALV_GRID.
      DATA: P_EDITED(1)   TYPE C.

      CLEAR: TT_CTRL_ROLE, TT_CTRL_ROLE[].

      "### ALV 에 프론트로 입력된 값을 인터널 테이블로 로드
      CALL FUNCTION 'GET_GLOBALS_FROM_SLVC_FULLSCR'
        IMPORTING
          E_GRID = P_REF.

     "### ALV 에서 프론트로 입력된 값이 정상적으로 변경되었는지 확인 후, 인터널 테이블로 로드
      CALL METHOD P_REF->CHECK_CHANGED_DATA
        IMPORTING
          E_VALID   = P_EDITED.

      "### 변경된 사항이 있다면, 데이터 저장 프로세스
      IF P_EDITED = 'X'.

        LOOP AT GT_CTRL_ROLE.

          MOVE-CORRESPONDING GT_CTRL_ROLE TO TT_CTRL_ROLE. APPEND TT_CTRL_ROLE.
          MODIFY ZBC_CTRL_ROLE FROM TABLE TT_CTRL_ROLE.

        ENDLOOP.

        MESSAGE 'Saved Data' TYPE 'S'.

      ENDIF.

  ENDCASE.

  "### ALV 리프레시 설정
  PI_SELFIELD-REFRESH = 'X'.
  PI_SELFIELD-COL_STABLE = 'X'.
  PI_SELFIELD-ROW_STABLE = 'X'.

ENDFORM.

*&---------------------------------------------------------------------*
*& Form VIEW_SE16N_CD
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& -->  p1        text
*& <--  p2        text
*&---------------------------------------------------------------------*
FORM VIEW_SE16N_CD .

  DATA: L_POS       TYPE I VALUE 0.

  DATA: LT_FIELDCAT TYPE SLIS_T_FIELDCAT_ALV WITH HEADER LINE,
        LT_LAYOUT   TYPE SLIS_LAYOUT_ALV.

  "### ALV Header 출력 용, 엔트리 카운트
  CLEAR: GV_COUNT.
  GV_COUNT = LINES( GT_SE16N ).

  IF LT_SE16N[] IS NOT INITIAL.

    "### Build Field Catalog
    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'MANDT'.
    LT_FIELDCAT-SELTEXT_M   = 'MANDT'.
    LT_FIELDCAT-KEY         = 'X'.
    LT_FIELDCAT-OUTPUTLEN   = 4.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'ID'.
    LT_FIELDCAT-SELTEXT_M   = 'ID'.
    LT_FIELDCAT-KEY         = 'X'.
    LT_FIELDCAT-OUTPUTLEN   = 20.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'TAB'.
    LT_FIELDCAT-SELTEXT_M   = 'TAB'.
    LT_FIELDCAT-OUTPUTLEN   = 15.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'UNAME'.
    LT_FIELDCAT-SELTEXT_M   = 'UNAME'.
    LT_FIELDCAT-OUTPUTLEN   = 10.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'SDATE'.
    LT_FIELDCAT-SELTEXT_M   = 'SDATE'.
    LT_FIELDCAT-OUTPUTLEN   = 8.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'STIME'.
    LT_FIELDCAT-SELTEXT_M   = 'STIME'.
    LT_FIELDCAT-OUTPUTLEN   = 8.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'CLNTDEP'.
    LT_FIELDCAT-SELTEXT_M   = 'CLNTDEP'.
    LT_FIELDCAT-OUTPUTLEN   = 3.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'INDX_GUID'.
    LT_FIELDCAT-SELTEXT_M   = 'INDX_GUID'.
    LT_FIELDCAT-OUTPUTLEN   = 3.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'EVID_URL'.
    LT_FIELDCAT-SELTEXT_M   = 'EVID URL'.
    LT_FIELDCAT-HOTSPOT     = 'X'.
    LT_FIELDCAT-OUTPUTLEN   = 50.
    LT_FIELDCAT-EMPHASIZE   = 'C500'.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'TARGET_ROLE'.
    LT_FIELDCAT-SELTEXT_M   = 'Role'.
    LT_FIELDCAT-KEY         = 'X'.
    LT_FIELDCAT-OUTPUTLEN   = 25.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'ACT_DATE'.
    LT_FIELDCAT-SELTEXT_M   = 'Grant Date'.
    LT_FIELDCAT-KEY         = 'X'.
    LT_FIELDCAT-OUTPUTLEN   = 8.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'ACT_TIME'.
    LT_FIELDCAT-SELTEXT_M   = 'Grant Time'.
    LT_FIELDCAT-KEY         = 'X'.
    LT_FIELDCAT-OUTPUTLEN   = 8.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'REVOKE_DATE'.
    LT_FIELDCAT-SELTEXT_M   = 'Revoke Date'.
    LT_FIELDCAT-KEY         = 'X'.
    LT_FIELDCAT-OUTPUTLEN   = 8.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'REVOKE_TIME'.
    LT_FIELDCAT-SELTEXT_M   = 'Revoke Time'.
    LT_FIELDCAT-KEY         = 'X'.
    LT_FIELDCAT-OUTPUTLEN   = 8.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.


    "### ALV Layout 설정
    LT_LAYOUT-BOX_FIELDNAME = 'SEL'.
    LT_LAYOUT-INFO_FIELDNAME = 'LINECOLOR'.
    LT_LAYOUT-COLWIDTH_OPTIMIZE = 'X'.
*    LT_LAYOUT-ZEBRA = 'X'.
    LT_LAYOUT-BOX_TABNAME = 'GT_SE16N'.


    "### 위에 설정된 Field Catalog  Layout  사용하여 ALV 리스트 출력 펑션 
    CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
      EXPORTING
        I_CALLBACK_PROGRAM       = SY-REPID
        I_CALLBACK_USER_COMMAND  = 'USER_COMMAND_DISP'
        I_CALLBACK_PF_STATUS_SET = 'SET_PF_STATUS'
        "I_GRID_TITLE             = GV_ALV_HEADER
        I_CALLBACK_TOP_OF_PAGE   = 'TOP-OF-PAGE'
        I_HTML_HEIGHT_TOP        = 6
        "IT_EXCLUDING             = LT_EXCL[]
        "IT_EVENTS                = LT_EVENT[]
        IT_FIELDCAT              = LT_FIELDCAT[]
        IS_LAYOUT                = LT_LAYOUT
        "I_SAVE = 'A'
      TABLES
        T_OUTTAB = GT_SE16N
      EXCEPTIONS
        PROGRAM_ERROR   = 1
        OTHERS          = 2.

  ELSE.

    MESSAGE 'No Data' TYPE 'S'.

  ENDIF.

ENDFORM.

*&---------------------------------------------------------------------*
*& Form VIEW_SM20
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& -->  p1        text
*& <--  p2        text
*&---------------------------------------------------------------------*
FORM VIEW_SM20 .

  DATA: L_POS       TYPE I VALUE 0.

  DATA: LT_FIELDCAT TYPE SLIS_T_FIELDCAT_ALV WITH HEADER LINE,
        LT_LAYOUT   TYPE SLIS_LAYOUT_ALV.

  "### ALV Header 출력 용, 엔트리 카운트
  CLEAR: GV_COUNT.
  GV_COUNT = LINES( GT_SM20 ).

  IF LT_DATA[] IS NOT INITIAL.

    "### Build Field Catalog
    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'SID'.
    LT_FIELDCAT-SELTEXT_M   = 'System'.
    LT_FIELDCAT-KEY         = 'X'.
    LT_FIELDCAT-OUTPUTLEN   = 4.
    LT_FIELDCAT-JUST        = 'C'.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'INSTANCE'.
    LT_FIELDCAT-SELTEXT_M   = 'SERVER'.
    LT_FIELDCAT-OUTPUTLEN   = 20.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'SAL_DATE'.
    LT_FIELDCAT-SELTEXT_M   = 'DATE'.
    LT_FIELDCAT-OUTPUTLEN   = 10.
    LT_FIELDCAT-JUST        = 'C'.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'SAL_TIME'.
    LT_FIELDCAT-SELTEXT_M   = 'TIME'.
    LT_FIELDCAT-OUTPUTLEN   = 10.
    LT_FIELDCAT-JUST        = 'C'.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'SLGMAND'.
    LT_FIELDCAT-SELTEXT_M   = 'Client'.
    LT_FIELDCAT-OUTPUTLEN   = 4.
    LT_FIELDCAT-JUST        = 'C'.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'MSG'.
    LT_FIELDCAT-SELTEXT_M   = 'MSG ID'.
    LT_FIELDCAT-OUTPUTLEN   = 4.
    LT_FIELDCAT-JUST        = 'C'.
    LT_FIELDCAT-EMPHASIZE   = 'C600'.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'SLGUSER'.
    LT_FIELDCAT-SELTEXT_M   = 'USER'.
    LT_FIELDCAT-OUTPUTLEN   = 12.
    LT_FIELDCAT-JUST        = 'C'.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'SLGLTRM2'.
    LT_FIELDCAT-SELTEXT_M   = 'Terminal'.
    LT_FIELDCAT-OUTPUTLEN   = 10.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'TERM_IPV6'.
    LT_FIELDCAT-SELTEXT_M   = 'IP'.
    LT_FIELDCAT-OUTPUTLEN   = 10.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'SLGTC'.
    LT_FIELDCAT-SELTEXT_M   = 'Tcode'.
    LT_FIELDCAT-OUTPUTLEN   = 10.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'SLGREPNA'.
    LT_FIELDCAT-SELTEXT_M   = 'Program'.
    LT_FIELDCAT-OUTPUTLEN   = 10.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'PARAM3'.
    LT_FIELDCAT-SELTEXT_M   = 'Log'.
    LT_FIELDCAT-OUTPUTLEN   = 10.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'EVID_URL'.
    LT_FIELDCAT-SELTEXT_M   = 'EVID URL'.
    LT_FIELDCAT-HOTSPOT     = 'X'.
    LT_FIELDCAT-OUTPUTLEN   = 50.
    LT_FIELDCAT-EMPHASIZE   = 'C500'.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'TARGET_ROLE'.
    LT_FIELDCAT-SELTEXT_M   = 'Role'.
    LT_FIELDCAT-KEY         = 'X'.
    LT_FIELDCAT-OUTPUTLEN   = 25.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'ACT_DATE'.
    LT_FIELDCAT-SELTEXT_M   = 'Grant Date'.
    LT_FIELDCAT-KEY         = 'X'.
    LT_FIELDCAT-OUTPUTLEN   = 8.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'ACT_TIME'.
    LT_FIELDCAT-SELTEXT_M   = 'Grant Time'.
    LT_FIELDCAT-KEY         = 'X'.
    LT_FIELDCAT-OUTPUTLEN   = 8.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'REVOKE_DATE'.
    LT_FIELDCAT-SELTEXT_M   = 'Revoke Date'.
    LT_FIELDCAT-KEY         = 'X'.
    LT_FIELDCAT-OUTPUTLEN   = 8.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.

    L_POS = L_POS + 1.
    LT_FIELDCAT-COL_POS     = L_POS.
    LT_FIELDCAT-FIELDNAME   = 'REVOKE_TIME'.
    LT_FIELDCAT-SELTEXT_M   = 'Revoke Time'.
    LT_FIELDCAT-KEY         = 'X'.
    LT_FIELDCAT-OUTPUTLEN   = 8.
    APPEND LT_FIELDCAT. CLEAR  LT_FIELDCAT.


    "### ALV Layout 설정
    LT_LAYOUT-BOX_FIELDNAME = 'SEL'.
    LT_LAYOUT-INFO_FIELDNAME = 'LINECOLOR'.
    LT_LAYOUT-COLWIDTH_OPTIMIZE = 'X'.
*    LT_LAYOUT-ZEBRA = 'X'.
*    LT_LAYOUT_CTAB_FNAME = 'CELLTAB'.
    LT_LAYOUT-BOX_TABNAME = 'GT_SM20'.


    CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
      EXPORTING
        I_CALLBACK_PROGRAM       = SY-REPID
        I_CALLBACK_USER_COMMAND  = 'USER_COMMAND_DISP'
        I_CALLBACK_PF_STATUS_SET = 'SET_PF_STATUS'
        "I_GRID_TITLE             = GV_ALV_HEADER
        I_CALLBACK_TOP_OF_PAGE   = 'TOP-OF-PAGE'
        I_HTML_HEIGHT_TOP        = 5
        IT_FIELDCAT              = LT_FIELDCAT[]
        IS_LAYOUT                = LT_LAYOUT
        "I_SAVE = 'A'
      TABLES
        T_OUTTAB = GT_SM20.

  ELSE.

    MESSAGE 'No Data' TYPE 'S'.

  ENDIF.

ENDFORM.

*-------------------------------------------------------------------*
* Form  TOP-OF-PAGE                                                 *
*-------------------------------------------------------------------*
* ALV Report Header                                                 *
*-------------------------------------------------------------------*
FORM TOP-OF-PAGE.

*ALV Header declarations
  DATA: LT_HEADER  TYPE SLIS_T_LISTHEADER,
        LS_HEADER  TYPE SLIS_LISTHEADER.

  "### 여백 라인 삽입
*  WA_HEADER-TYP  = 'S'.
*  WA_HEADER-INFO = ''.
*  APPEND WA_HEADER TO T_HEADER.
*  CLEAR WA_HEADER.

  IF S_DATE IS NOT INITIAL.

    IF S_DATE-HIGH IS INITIAL OR S_DATE-LOW = S_DATE-HIGH.

      LS_HEADER-TYP  = 'S'.
      LS_HEADER-INFO = |Date : { S_DATE-LOW+0(4) }.{ S_DATE-LOW+4(2) }.{ S_DATE-LOW+6(2) }|.

    ELSE.

      LS_HEADER-TYP  = 'S'.
      LS_HEADER-INFO = |Date : { S_DATE-LOW+0(4) }.{ S_DATE-LOW+4(2) }.{ S_DATE-LOW+6(2) } ~ { S_DATE-HIGH+0(4) }.{ S_DATE-HIGH+4(2) }.{ S_DATE-HIGH+6(2) }|.

    ENDIF.

    APPEND LS_HEADER TO LT_HEADER.
    CLEAR: LS_HEADER.

    LS_HEADER-TYP  = 'S'.
    LS_HEADER-INFO = |Count : { GV_COUNT }|.

    APPEND LS_HEADER TO LT_HEADER.
    CLEAR: LS_HEADER.


  ENDIF.

  CALL FUNCTION 'REUSE_ALV_COMMENTARY_WRITE'
    EXPORTING
      IT_LIST_COMMENTARY = LT_HEADER
      I_ALV_FORM         = 'X'.

ENDFORM.                    "TOP-OF-PAGE.


1-2. IF_BADI_IDENTITY_UPDATE~SAVE (BAdI)

해당 BAdI 에 대한 정보는 다음 Notes 를 참고하기 바란다.

  • SAP Notes 1750161 - User administration: Saving additional information (BAdI BADI_IDENTITY_UPDATE)

Enhancement Spot 확인

Tcode : SE18
BAdI Name : BADI_IDENTITY_UPDATE
-> 상단에서 Enhancement Spot - SUID_IDENTITY 확인

Tcode : SE19
-> Create Implementation
-> New BAdI
-> Enhancement Spot : SUID_IDENTITY 입력 후, Create

-> Enhancement Implementation : ZBC_USER_SAVE (자유 입력 가능)
-> Short Text : SAP User Save BAdI (자유 입력 가능)

-> BAdI Implementation : ZCL_IDENTITY_UPDATE (자유 입력 가능)
-> Implementation Class : ZCL_IP_IDENTITY_UPDATE (자유 입력 가능)
-> BAdI Definition : BADI_IDENTITY_UPDATE

-> 왼쪽 메뉴트리의 방금 생성한 BAdI 밑에 Implementation Class 더블클릭
-> 해당 Implementing Class 에 속한 Method 들을 확인할 수 있다.
-> 여기서 ~SAVE 메소드를 더블클릭하여 오픈한 다음, 아래 소스 코드 입력

method IF_BADI_IDENTITY_UPDATE~SAVE.

  "### SAP NOTES 1750161 - User administration: Saving additional information (BAdI BADI_IDENTITY_UPDATE)

  "### 롤 관련 업데이트 사항이 있을시, (프로파일 부여/조정은 SPACE 값)
  IF IT_BADI_IDENTITY_ROLES IS NOT INITIAL.

    DATA: LT_CTRL_ROLE          TYPE TABLE OF ZBC_CTRL_ROLE
          LS_CTRL_ROLE          LIKE LINE OF LT_CTRL_ROLE.

    DATA: LT_POPUP          TYPE TABLE OF SVAL,
          LS_POPUP          LIKE LINE  OF LT_POPUP.

    DATA: LS_ROLE           TYPE LINE OF SUID_TT_BADI_ROLES,
          LS_ROLE_ACT       TYPE LINE OF SUID_TT_AGR_USERS,
          LS_ROLE_BEF       TYPE LINE OF SUID_TT_AGR_USERS,
          LS_ROLE_DEL       TYPE LINE OF SUID_TT_AGR_USERS.

    DATA: LT_ROLE_ACT       TYPE TABLE OF AGR_USERS,
          LT_ROLE_BEF       TYPE TABLE OF AGR_USERS,
          LT_ROLE_DEL       TYPE TABLE OF AGR_USERS.

    DATA: LV_RET            TYPE C,
          LV_CNT            TYPE N.

    DATA: LT_EVID          TYPE TABLE OF ZBC_EVID_DATA,
          LS_EVID          LIKE LINE  OF LT_EVID


    "### 권한 증빙 제어 롤 리스트 셀렉트
    SELECT * INTO CORRESPONDING FIELDS OF TABLE LT_CTRL_ROLE
      FROM ZBC_CTRL_ROLE.


    "### 부여하는 권한 중, 권한 증빙 제어 롤이 있는 확인
    LOOP AT IT_BADI_IDENTITY_ROLES INTO LS_ROLE.

      "### 기초 데이터 준비
      LT_ROLE_BEF[] = LS_ROLE-BEFORE_IMAGE[].
      LT_ROLE_ACT[] = LS_ROLE-ACTUAL[].

      LT_ROLE_DEL[]  = LT_ROLE_BEF[].


      "### 기존(BEF) 롤 리스트에서 신규(ACT) 롤 리스트를 비교하여, 삭제된 롤 리스트 생성.
      LOOP AT LT_ROLE_ACT INTO LS_ROLE_ACT.

        DELETE LT_ROLE_DEL WHERE AGR_NAME   = LS_ROLE_ACT-AGR_NAME
                             AND UNAME      = LS_ROLE_ACT-UNAME
                             AND FROM_DAT   = LS_ROLE_ACT-FROM_DAT
                             AND TO_DAT     = LS_ROLE_ACT-TO_DAT
                             AND CHANGE_DAT = LS_ROLE_ACT-CHANGE_DAT
                             AND CHANGE_TIM = LS_ROLE_ACT-CHANGE_TIM.

      ENDLOOP.


      "### 사전 설정된 증빙 제어 롤 리스트 가져오기
      LOOP AT LT_CTRL_ROLE INTO LS_CTRL_ROLE WHERE ITEM = 'ROLE'.

        "### 사용자에게 부여하는 롤 중에, 권한 증빙 제어 롤이 있다면, EVID URL 증빙 요구
        LOOP AT LT_ROLE_ACT INTO LS_ROLE_ACT WHERE AGR_NAME = LS_CTRL_ROLE-VALUE.

          "### 권한 증빙 제어 롤 중,
          "### 기존에 제어 롤을 보유하고 있고, 수정 사항이 없다면, 바이패스하도록 설정.
          READ TABLE LT_ROLE_BEF INTO LS_ROLE_BEF WITH KEY AGR_NAME   = LS_ROLE_ACT-AGR_NAME
                                                           UNAME      = LS_ROLE_ACT-UNAME
                                                           FROM_DAT   = LS_ROLE_ACT-FROM_DAT
                                                           TO_DAT     = LS_ROLE_ACT-TO_DAT
                                                           CHANGE_DAT = LS_ROLE_ACT-CHANGE_DAT
                                                           CHANGE_TIM = LS_ROLE_ACT-CHANGE_TIM.

          IF SY-SUBRC = 0.

            CONTINUE.

          ENDIF.

          "### 권한 부여 증빙 팝업 설정
          "### 디버깅 수정권한 부여 증빙 URL 입력
          CLEAR: LT_POPUP, LS_POPUP. REFRESH: LT_POPUP.

          "### => 권한 부여 대상 SAP ID
          LS_POPUP-TABNAME   = 'USR02'.
          LS_POPUP-FIELDNAME = 'BNAME'.
          LS_POPUP-FIELDTEXT = 'Target User'.
          LS_POPUP-FIELD_ATTR = '03'.
          LS_POPUP-VALUE = LS_ROLE_ACT-UNAME.
          APPEND LS_POPUP TO LT_POPUP. CLEAR: LS_POPUP.

          "### => 권한 부여 대상 롤
          LS_POPUP-TABNAME   = 'AGR_DEFINE'.
          LS_POPUP-FIELDNAME = 'AGR_NAME'.
          LS_POPUP-FIELDTEXT = 'Target Role'.
          LS_POPUP-FIELD_ATTR = '03'.
          LS_POPUP-VALUE = LS_ROLE_ACT-AGR_NAME.
          APPEND LS_POPUP TO LT_POPUP. CLEAR: LS_POPUP.

          "### => 권한 부여 대상 롤 유효기간 시작일
          LS_POPUP-TABNAME   = 'AGR_USERS'.
          LS_POPUP-FIELDNAME = 'FROM_DAT'.
          LS_POPUP-FIELDTEXT = 'Vaild From'.
          LS_POPUP-FIELD_ATTR = '03'.
          LS_POPUP-VALUE = LS_ROLE_ACT-FROM_DAT.
          APPEND LS_POPUP TO LT_POPUP. CLEAR: LS_POPUP.

          "### => 권한 부여 대상 롤 유효기간 종료일
          LS_POPUP-TABNAME   = 'AGR_USERS'.
          LS_POPUP-FIELDNAME = 'TO_DAT'.
          LS_POPUP-FIELDTEXT = 'Vaild To'.
          LS_POPUP-FIELD_ATTR = '03'.
          LS_POPUP-VALUE = LS_ROLE_ACT-TO_DAT.
          APPEND LS_POPUP TO LT_POPUP. CLEAR: LS_POPUP.

          "### => 증빙 URL
          LS_POPUP-TABNAME   = 'IWURL'.
          LS_POPUP-FIELDNAME = 'URL'.
          LS_POPUP-FIELDTEXT = 'Evid. URL'.
          APPEND LS_POPUP TO LT_POPUP. CLEAR: LS_POPUP.

          "### 팝업 출력
          CALL FUNCTION 'POPUP_GET_VALUES'
            EXPORTING
              POPUP_TITLE       = 'Evidence of Role Assignment'
            IMPORTING
              RETURNCODE        = LV_RET
            TABLES
              FIELDS            = LT_POPUP
            EXCEPTIONS
              ERROR_IN_FIELDS   = 1
              OTHERS            = 2.

          "### 해당 BAdI 특성 상, 유효값 설정을 할 수 없기 때문에, 취소, 공백 입력도 허용
          "### == SAP Notes 1750161 내용 ==
          "### = The save process can no longer be canceled. The output of messages of the type E, A, or X is therefore not permitted.
          "### = You can no longer change the user data that is to be saved.
          "### = A COMMIT WORK or ROLLBACK WORK must not be executed.

          "### 팝업 응답 중, URL 필드 읽기
          READ TABLE LT_POPUP[] INTO LS_POPUP WITH KEY FIELDNAME = 'URL'.

          "### 해당 데이터를 종합하여, LT_EVID 테이블에 저장
          CLEAR: LT_EVID, LT_EVID[], LS_EVID.
          LS_EVID-MANDT         = SY-MANDT.
          LS_EVID-ACT_DATE      = LS_ROLE_ACT-CHANGE_DAT.
          LS_EVID-ACT_TIME      = LS_ROLE_ACT-CHANGE_TIM.
          LS_EVID-TARGET_USER   = LS_ROLE_ACT-UNAME.
          LS_EVID-TARGET_ROLE   = LS_ROLE_ACT-AGR_NAME.
          LS_EVID-VAILD_FROM    = LS_ROLE_ACT-FROM_DAT.
          LS_EVID-VAILD_TO      = LS_ROLE_ACT-TO_DAT.
          LS_EVID-CHG_USER      = IS_BADI_TIMESTAMP-UNAME.
          LS_EVID-EVID_URL      = LS_POPUP-VALUE.
          APPEND LS_EVID TO LT_EVID. CLEAR: LS_EVID.

          "### LT_EVID 데이터를 ZBC_EVID_DATA 테이블에 MODI
          MODIFY ZBC_EVID_DATA FROM TABLE LT_EVID.

        ENDLOOP.

        "### 관한 증빙 제어 롤 회수 시, 회수 일자 기록 로직
        CLEAR: LS_ROLE_BEF, LS_ROLE_ACT.

        "### 삭제된 롤 리스트에 대해, 회수 일자 기록
        LOOP AT LT_ROLE_DEL INTO LS_ROLE_DEL WHERE AGR_NAME = LS_CTRL_ROLE-VALUE.

          SELECT * INTO CORRESPONDING FIELDS OF TABLE LT_EVID
            FROM ZBC_EVID_DATA
            WHERE ACT_DATE    = LS_ROLE_DEL-CHANGE_DAT
              AND ACT_TIME    = LS_ROLE_DEL-CHANGE_TIM
              AND TARGET_USER = LS_ROLE_DEL-UNAME
              AND TARGET_ROLE = LS_ROLE_DEL-AGR_NAME
              AND VAILD_FROM  = LS_ROLE_DEL-FROM_DAT
              AND VAILD_TO    = LS_ROLE_DEL-TO_DAT.

          IF SY-SUBRC = 0.

            READ TABLE LT_EVID INTO LS_EVID INDEX 1.
            LS_EVID-REVOKE_DATE = IS_BADI_TIMESTAMP-DATUM.
            LS_EVID-REVOKE_TIME = IS_BADI_TIMESTAMP-UZEIT.
            APPEND LS_EVID TO LT_EVID. CLEAR LS_EVID.

            "### 회수 일자/시간이 기록된 데이터를 ZBC_EVID_DATA 테이블에 MODIFY
            MODIFY ZBC_EVID_DATA FROM TABLE LT_EVID.


          ENDIF.

        ENDLOOP.

      ENDLOOP.

    ENDLOOP.

  ENDIF.

endmethod.



2. ABAP Dictionary

2-1. Table ZBC_EVID_DATA

FieldKeyInitVData ElementDTypeLenDesc
MANDTXXMANDT
ACT_DATEXXDATUM
ACT_TIMEXXUZEIT
TARGET_USERXXBNAME
TARGET_ROLEXXAGR_NAME
VAILD_FROMXXDATUM
VAILD_TOXXDATUM
CHG_USERBNAME
EVID_URLAGR_URL
REVOKE_DATEDATUM
REVOKE_TIMEUZEIT
MANUAL_EDITCHAR1수기 입력 플래그

2-2. Table ZBC_CTRL_ROLE

FieldKeyInitVData ElementDTypeLenDesc
MANDTXXMANDT
ITEMXXCHAR20
VALUEXXCHAR30
TAGCHAR20
TEXTCHAR50

2-3. GUI Status

2-3-1. GUI Status Name : S100

◾ Application Toolbar

  • ADD_ITEM
    -> Function Text : ADD_ITEM
    -> Icon Name : ICON_CREATE
    -> Icon Text / Info. Text : ADD ITEM

  • DEL_ITEM
    -> Function Text : DEL_ITEM
    -> Icon Name : ICON_DELETE
    -> Icon Text / Info. Text : DELETE ITEM

2-3-2. GUI Status Name : S110

◾ Application Toolbar

  • &ETA
    -> Function Text : 세부사항
    -> Icon Name : ICON_SELECT_DETAIL

  • 분리자 라인 (Edit -> Insert -> separator line)

  • &ALL
    -> Function Text : 모두 선택
    -> Icon Name : ICON_SELECT_ALL

  • &SAL
    -> Function Text : 모두 선택 해제
    -> Icon Name : ICON_DESELECT_ALL

  • 분리자 라인

  • &OUP
    -> Function Text : 오름차순 정렬
    -> Icon Name : ICON_SORT_UP

  • &ODN
    -> Function Text : 내림차순 정렬
    -> Icon Name : ICON_SORT_DOWN

  • &ILT
    -> Function Text : 필터 설정
    -> Icon Name : ICON_FILTER

  • 분리자 라인

  • &XXL
    -> Function Text : 스프레드시트
    -> Icon Name : ICON_XXL

  • %PC
    -> Function Text : 로컬 파일
    -> Icon Name : ICON_EXPORT

  • 분리자 라인

  • &NTE
    -> Function Text : 새로 고침
    -> Icon Name : ICON_REFRESH

  • 분리자 라인

  • F_ADJ
    -> Function Text : F_ADJ
    -> Icon Name : ICON_INTENSIFY_CRITICAL
    -> Icon Text / Info. Text : Revoke Adjust

  • M_EDIT
    -> Function Text : M_EDIT
    -> Icon Name : ICON_ANNOTATION
    -> Icon Text / Info. Text : Revoke Edit

  • 분리자 라인

  • DELE
    -> Function Text : DELE
    -> Icon Name : ICON_DELETE
    -> Icon Text / Info. Text : DELETE

profile
SAP BC (2019 ~ )

0개의 댓글