본문 바로가기
ABAP/소스코드

[Report] Client copy 후 번호범위 자동 조정 프로그램

by name_text 2023. 5. 24.

Client copy 후 번호범위 자동 조정 프로그램

RFC_READ_TABLE

 

SCC9를 통해 운영에서 QA로 Remote Copy 시 운영 클라이언트를 잠그지 않고 복사를 하면, 복사 후에 QA클라이언트의 번호범위 테이블의 현재값과 실제 각 테이블(COBK, MLDOC, BKPF 등등)의 마지막 번호가 불일치하는 경우가 발생합니다.

 

이럴 경우 DUPLICATE_KEY_ERROR가 발생하게 되며, SM13과 SCMP를 이용하여 하나씩 찾아서 수정하면 되긴 하지만,

저희 회사 같은 경우는 테스트를 위해 QA 클라이언트를 매월초에 카피를 하다보니 생각 이상으로 번거롭도 시간도 꽤 소요가 되었습니다.

 

클라이언트 카피 후 실행하면 소스 클라이언트 기준으로 번호범위를 일괄 조정하는 Report 프로그램을 만들었습니다.

소스코드를 보시면 알겠지만, 별 내용은 없습니다....

RFC_READ_TABLE 펑션으로 운영서버의 NRIV 테이블 데이터를 읽어와서 로컬시스템(QA)의 NRIV 테이블 데이터와 비교 후 갱신해 주는 방식입니다.

 

 

#1. ABAP 소스코드


REPORT ZCMR9003.
INCLUDE ZCM_PROGRESS.

CLASS LCL_HANDLE_EVENTS DEFINITION.
  PUBLIC SECTION.
    METHODS:
      ON_USER_COMMAND FOR EVENT ADDED_FUNCTION OF CL_SALV_EVENTS
        IMPORTING E_SALV_FUNCTION.
ENDCLASS.

CLASS LCL_HANDLE_EVENTS IMPLEMENTATION.
  METHOD ON_USER_COMMAND.
    PERFORM HANDLE_USER_COMMAND USING E_SALV_FUNCTION.
  ENDMETHOD.
ENDCLASS.

DATA: GR_EVENTS TYPE REF TO LCL_HANDLE_EVENTS.
DATA: GR_SALV   TYPE REF TO CL_SALV_TABLE.

TYPES: BEGIN OF T_NRIV.
         INCLUDE STRUCTURE NRIV.
         TYPES: NRLEVEL_LC TYPE NRIV-NRLEVEL,
                BUFFER     TYPE TNRO-BUFFER,
                NOIVBUFFER TYPE TNRO-NOIVBUFFER,
                STATUS     TYPE ICONNAME.
TYPES: END OF T_NRIV.

DATA: GT_REMOT TYPE STANDARD TABLE OF T_NRIV.

PARAMETERS P_DEST TYPE RFCDES-RFCDEST OBLIGATORY MEMORY ID RFC.
SELECTION-SCREEN SKIP.
PARAMETERS CH_DIF AS CHECKBOX DEFAULT ABAP_TRUE.

INITIALIZATION.
  PERFORM INITIALIZATION.

START-OF-SELECTION.
  PERFORM READ_NRIV_DATA.

*&---------------------------------------------------------------------*
*& Form READ_NRIV_DATA
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& -->  p1        text
*& <--  p2        text
*&---------------------------------------------------------------------*
FORM READ_NRIV_DATA .
  DATA: LT_OPTIONS TYPE STANDARD TABLE OF  RFC_DB_OPT,
        LT_FIELDS  TYPE STANDARD TABLE OF  RFC_DB_FLD,
        LT_DATA    TYPE STANDARD TABLE OF  TAB512.

  CONSTANTS LC_TABLE TYPE DD02L-TABNAME VALUE 'NRIV'.

  CLEAR GT_REMOT[].

  "운영에서는 실행 금지
  SELECT SINGLE
    CCCATEGORY
  FROM T000
  WHERE MANDT EQ @SY-MANDT
    INTO @DATA(LV_CCT).
  IF LV_CCT EQ 'P'.
    MESSAGE A000(OO) WITH '운영 클라이언트 에서는 실행할 수 없습니다'.
    EXIT.
  ENDIF.

  CALL FUNCTION 'RFC_READ_TABLE'
    DESTINATION P_DEST
    EXPORTING
      QUERY_TABLE          = LC_TABLE
*     DELIMITER            = ' '
*     NO_DATA              = ' '
*     ROWSKIPS             = 0
*     ROWCOUNT             = 0
    TABLES
      OPTIONS              = LT_OPTIONS
      FIELDS               = LT_FIELDS
      DATA                 = LT_DATA
    EXCEPTIONS
      TABLE_NOT_AVAILABLE  = 1
      TABLE_WITHOUT_DATA   = 2
      OPTION_NOT_VALID     = 3
      FIELD_NOT_VALID      = 4
      NOT_AUTHORIZED       = 5
      DATA_BUFFER_EXCEEDED = 6
      OTHERS               = 7.
  IF SY-SUBRC <> 0.
    MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
            WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
  ENDIF.

  DATA: LS_REMOT LIKE LINE OF GT_REMOT,
        LT_LOCAL TYPE SORTED TABLE OF NRIV WITH UNIQUE KEY  OBJECT
                                                            SUBOBJECT
                                                            NRRANGENR
                                                            TOYEAR,
        LT_TNRO TYPE SORTED TABLE OF  TNRO WITH UNIQUE KEY  OBJECT.
  FIELD-SYMBOLS <LFS> TYPE ANY.

  "리모트 데이터 정리
  LOOP AT LT_DATA INTO DATA(LS_DATA).
    LOOP AT LT_FIELDS INTO DATA(LS_FIELDS).
      DATA(LV_FIELDNAME) = 'LS_REMOT-' && LS_FIELDS-FIELDNAME.
      ASSIGN (LV_FIELDNAME) TO <LFS>.
      IF <LFS> IS ASSIGNED.
        <LFS> = LS_DATA-WA+LS_FIELDS-OFFSET(LS_FIELDS-LENGTH).
      ENDIF.
    ENDLOOP.
    APPEND LS_REMOT TO GT_REMOT.  CLEAR LS_REMOT.
  ENDLOOP.

  "로컬 데이터 조회
  SELECT * FROM NRIV WHERE EXTERNIND EQ @SPACE INTO CORRESPONDING FIELDS OF TABLE @LT_LOCAL.

  "번호범위 오브젝트
  SELECT OBJECT, BUFFER, NOIVBUFFER FROM TNRO
    INTO CORRESPONDING FIELDS OF TABLE @LT_TNRO.

  "데이터 비교
  LOOP AT GT_REMOT INTO LS_REMOT.
    DATA(LV_TABIX) = SY-TABIX.
    READ TABLE LT_TNRO INTO DATA(LS_TNRO) WITH TABLE KEY OBJECT = LS_REMOT-OBJECT.
    IF SY-SUBRC NE 0.
      DELETE GT_REMOT INDEX LV_TABIX.
      CONTINUE.
    ENDIF.

    READ TABLE LT_LOCAL INTO DATA(LS_LOCAL) WITH TABLE KEY  OBJECT    = LS_REMOT-OBJECT
                                                            SUBOBJECT = LS_REMOT-SUBOBJECT
                                                            NRRANGENR = LS_REMOT-NRRANGENR
                                                            TOYEAR    = LS_REMOT-TOYEAR.
    IF SY-SUBRC NE 0 OR
      ( SY-SUBRC EQ 0 AND CH_DIF EQ ABAP_TRUE AND LS_REMOT-NRLEVEL <= LS_LOCAL-NRLEVEL ).
      DELETE GT_REMOT INDEX LV_TABIX.
      CONTINUE.
    ENDIF.

    LS_REMOT-NRLEVEL_LC = LS_LOCAL-NRLEVEL.
    LS_REMOT-BUFFER     = LS_TNRO-BUFFER.
    LS_REMOT-NOIVBUFFER = LS_TNRO-NOIVBUFFER.

    MODIFY GT_REMOT FROM LS_REMOT INDEX LV_TABIX.
  ENDLOOP.

  "RFC 정보
  DATA: LV_ALV_TITLE TYPE LVC_TITLE,
        LS_RFCINFO   TYPE CMPWL_SYSTEM_INFO_TYPE.
  CALL FUNCTION 'SCT4_GET_RFC_INFO'
    EXPORTING
      IV_RFC_DEST        = P_DEST
    CHANGING
      CS_SYSTEM_INFO     = LS_RFCINFO
    EXCEPTIONS
      RFC_DEST_NOT_FOUND = 1
      COMM_FAILURE       = 2
      SYST_FAILURE       = 3
      OTHERS             = 4.
  IF SY-SUBRC EQ 0.
    CONCATENATE '비교시스템:' ` ` LS_RFCINFO-SYSTEM_NAME_REMOTE '/' LS_RFCINFO-CLIENT_REMOTE
                ` ` '<->' ` `
                '로컬시스템:' ` `SY-SYSID '/' SY-MANDT
    INTO LV_ALV_TITLE.
  ENDIF.

  PERFORM CALL_SALV TABLES GT_REMOT
                    USING GR_SALV LV_ALV_TITLE.
ENDFORM.

*&---------------------------------------------------------------------*
*& Form CALL_SALV
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& -->  p1        text
*& <--  p2        text
*&---------------------------------------------------------------------*
FORM CALL_SALV TABLES FT_ITAB
              USING LR_SALV   TYPE REF TO CL_SALV_TABLE
                    FV_TITLE.
  DATA : LR_FUNCTIONS TYPE REF TO CL_SALV_FUNCTIONS_LIST,
         LS_FUNCTION  TYPE REF TO CL_SALV_FUNCTION,
         LR_DISPLAY   TYPE REF TO CL_SALV_DISPLAY_SETTINGS,
         LR_LAYOUT    TYPE REF TO CL_SALV_LAYOUT,
         LS_PROGRAM   TYPE SALV_S_LAYOUT_KEY,
         LR_COLUMNS   TYPE REF TO CL_SALV_COLUMNS_TABLE,
         LR_COLUMN    TYPE REF TO CL_SALV_COLUMN_TABLE,
         LS_COLOR     TYPE LVC_S_COLO,
         LR_SELECTION TYPE REF TO CL_SALV_SELECTIONS,
         LR_SORTS     TYPE REF TO CL_SALV_SORTS,
         LR_AGGR      TYPE REF TO CL_SALV_AGGREGATIONS,
         LR_FILTER    TYPE REF TO CL_SALV_FILTERS,
         LR_EVENT_TAB TYPE REF TO CL_SALV_EVENTS_TABLE.

  DATA: LV_LVC_TITLE TYPE LVC_TITLE.
  MOVE  FV_TITLE TO LV_LVC_TITLE.

  "ALV 생성
  CALL METHOD CL_SALV_TABLE=>FACTORY
    IMPORTING
      R_SALV_TABLE = LR_SALV
    CHANGING
      T_TABLE      = FT_ITAB[].

  "ALV 의 기능키 표시
*  LR_FUNCTIONS = LR_SALV->GET_FUNCTIONS( ).
**  LR_FUNCTIONS->SET_DEFAULT( ).
*  LR_FUNCTIONS->SET_ALL( ).
  LR_SALV->SET_SCREEN_STATUS(
    PFSTATUS      =  'SALV_STATUS'
    REPORT        =  SY-REPID
    SET_FUNCTIONS = LR_SALV->C_FUNCTIONS_ALL ).

  "ALV 선택 모드 설정
  LR_SELECTION = LR_SALV->GET_SELECTIONS( ).
  LR_SELECTION->SET_SELECTION_MODE( IF_SALV_C_SELECTION_MODE=>ROW_COLUMN ).

  "ALV의 레이아웃 셋팅(줄무늬 패턴, 헤더 텍스트 등)
  LR_DISPLAY = LR_SALV->GET_DISPLAY_SETTINGS( ).
  LR_DISPLAY->SET_STRIPED_PATTERN( CL_SALV_DISPLAY_SETTINGS=>TRUE ).
  LR_DISPLAY->SET_LIST_HEADER( LV_LVC_TITLE ).

  "ALV의 레이아웃 저장 기능 활성화
  LR_LAYOUT = LR_SALV->GET_LAYOUT( ).
  LS_PROGRAM-REPORT = SY-REPID.
  LS_PROGRAM-HANDLE = SY-DYNNR.
  LR_LAYOUT->SET_KEY( LS_PROGRAM ).
  LR_LAYOUT->SET_DEFAULT( ABAP_TRUE ).
  LR_LAYOUT->SET_SAVE_RESTRICTION( CL_SALV_LAYOUT=>RESTRICT_NONE ). "기본값 및 사용자 레이아웃 제한 없음

  "ALV 열(필드카타로그) 설정
  LR_COLUMNS = LR_SALV->GET_COLUMNS( ).
  LR_COLUMNS->SET_OPTIMIZE( ABAP_TRUE ).    "열 너비 최적화
  LR_COLUMN ?= LR_COLUMNS->GET_COLUMN( 'NRLEVEL' ).
  LR_COLUMN->SET_LONG_TEXT( '비교시스템-' && LR_COLUMN->GET_LONG_TEXT( ) ).
  LR_COLUMN->SET_MEDIUM_TEXT( '비교시스템-' && LR_COLUMN->GET_MEDIUM_TEXT( ) ).
  LR_COLUMN->SET_SHORT_TEXT( '비교시스템-' && LR_COLUMN->GET_SHORT_TEXT( ) ).
  LS_COLOR = VALUE #( COL = 3 INT = 0 INV = 0 ).
  LR_COLUMN->SET_COLOR( LS_COLOR ).

  LR_COLUMN ?= LR_COLUMNS->GET_COLUMN( 'NRLEVEL_LC' ).
  LR_COLUMN->SET_LONG_TEXT( '로컬시스템-' && LR_COLUMN->GET_LONG_TEXT( ) ).
  LR_COLUMN->SET_MEDIUM_TEXT( '로컬시스템-' && LR_COLUMN->GET_MEDIUM_TEXT( ) ).
  LR_COLUMN->SET_SHORT_TEXT( '로컬시스템-' && LR_COLUMN->GET_SHORT_TEXT( ) ).
  LS_COLOR = VALUE #( COL = 5 INT = 0 INV = 0 ).
  LR_COLUMN->SET_COLOR( LS_COLOR ).

  LR_COLUMN ?= LR_COLUMNS->GET_COLUMN( 'STATUS' ).
  LR_COLUMN->SET_LONG_TEXT( '처리상태' ).
  LR_COLUMN->SET_MEDIUM_TEXT( '처리상태' ).
  LR_COLUMN->SET_SHORT_TEXT( '처리상태' ).

  LR_COLUMN ?= LR_COLUMNS->GET_COLUMN( 'EXTERNIND' ).
  LR_COLUMN->SET_TECHNICAL( 'X' ).
  LR_COLUMN ?= LR_COLUMNS->GET_COLUMN( 'BUFFER' ).
  LR_COLUMN->SET_TECHNICAL( 'X' ).
  LR_COLUMN ?= LR_COLUMNS->GET_COLUMN( 'NOIVBUFFER' ).
  LR_COLUMN->SET_TECHNICAL( 'X' ).

  "ALV 정렬
  LR_SORTS = LR_SALV->GET_SORTS( ).
  LR_SORTS->ADD_SORT( 'OBJECT' ).

  "ALV 이벤트
  LR_EVENT_TAB = LR_SALV->GET_EVENT( ).
  CREATE OBJECT GR_EVENTS.
  SET HANDLER GR_EVENTS->ON_USER_COMMAND FOR LR_EVENT_TAB.

  "ALV 표시
  LR_SALV->DISPLAY( ).
ENDFORM.
*&---------------------------------------------------------------------*
*& Form HANDLE_USER_COMMAND
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*&      --> E_SALV_FUNCTION
*&---------------------------------------------------------------------*
FORM HANDLE_USER_COMMAND  USING  I_UCOMM TYPE SALV_DE_FUNCTION.
  CASE I_UCOMM.
    WHEN 'ADJUST'.
      PERFORM ADJUST_LAST_NUMBER.

  ENDCASE.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form ADJUST_LAST_NUMBER
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& -->  p1        text
*& <--  p2        text
*&---------------------------------------------------------------------*
FORM ADJUST_LAST_NUMBER .
  DATA: LR_SELECTIONS TYPE REF TO CL_SALV_SELECTIONS.
  DATA: LT_ROWS   TYPE SALV_T_ROW.
  DATA: LV_NUMBER TYPE NRIV-NRLEVEL,
        LV_QUANTITY TYPE INRI-QUANTITY.

  DATA: LT_ERROR_IV TYPE STANDARD TABLE OF  INRIV,
        LT_INTERVAL TYPE STANDARD TABLE OF  INRIV,
        LS_INTERVAL LIKE LINE OF LT_INTERVAL.

  LR_SELECTIONS = GR_SALV->GET_SELECTIONS( ).
  LT_ROWS = LR_SELECTIONS->GET_SELECTED_ROWS( ).

  IF LT_ROWS[] IS INITIAL.
    MESSAGE I006(0K).
    EXIT.
  ENDIF.

  PERFORM INITIAL_PROGRESS_VARIANT.
  G_PROGRESS_TOTAL = LINES( LT_ROWS ).

  LOOP AT LT_ROWS INTO DATA(LS_ROWS).
    READ TABLE GT_REMOT INTO DATA(LS_REMOT) INDEX LS_ROWS.
    IF SY-SUBRC NE 0.
      CONTINUE.
    ENDIF.

    DATA(LV_TXT) = LS_REMOT-OBJECT && ` ` && '번호 조정중...'.
    PERFORM SET_PROGRESS_WITH_PERCENT USING LV_TXT.

    IF LS_REMOT-STATUS IS NOT INITIAL OR LS_REMOT-NRLEVEL <= LS_REMOT-NRLEVEL_LC.
      CONTINUE.
    ENDIF.

    CLEAR : LT_ERROR_IV, LT_INTERVAL.
    MOVE-CORRESPONDING LS_REMOT TO LS_INTERVAL.
    LS_INTERVAL-PROCIND = 'U'.
    APPEND LS_INTERVAL TO LT_INTERVAL.

    CALL FUNCTION 'NUMBER_RANGE_INTERVAL_UPDATE'
      EXPORTING
        OBJECT                    = LS_REMOT-OBJECT
*       CHECK_AT_ALL_EVENTS       = ' '
        SUBOBJECT                 = LS_REMOT-SUBOBJECT
*       CALLED_FROM_AIM           =
*       CLIENT_AIM                =
*       INIT_ACT                  = ' '
*     IMPORTING
*       ERROR                     =
*       ERROR_OCCURED             =
*       WARNING_OCCURED           =
      TABLES
        ERROR_IV                  = LT_ERROR_IV
        INTERVAL                  = LT_INTERVAL
      EXCEPTIONS
        OBJECT_NOT_FOUND          = 1
        OTHERS                    = 2
              .
    IF SY-SUBRC NE 0.
      CONTINUE.
    ENDIF.
    CALL FUNCTION 'NUMBER_RANGE_UPDATE_CLOSE'
      EXPORTING
        OBJECT                       = LS_REMOT-OBJECT
*       INTERVALS                    =
*       CALLED_FROM_AIM              =
*       CLIENT_AIM                   =
*       CHDO_RAP                     =
*       COMMIT                       =
      EXCEPTIONS
        NO_CHANGES_MADE              = 1
        OBJECT_NOT_INITIALIZED       = 2
        OTHERS                       = 3
              .
    IF SY-SUBRC EQ 0.
      COMMIT WORK AND WAIT.
    ELSEIF SY-SUBRC > 1.
      CONTINUE.
    ENDIF.

    LS_REMOT-NRLEVEL_LC = LS_REMOT-NRLEVEL.
    LS_REMOT-STATUS = ICON_OKAY.
    MODIFY GT_REMOT FROM LS_REMOT INDEX LS_ROWS.
  ENDLOOP.

  GR_SALV->REFRESH( ).

  MESSAGE S018(00).
ENDFORM.
*&---------------------------------------------------------------------*
*& Form INITIALIZATION
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& -->  p1        text
*& <--  p2        text
*&---------------------------------------------------------------------*
FORM INITIALIZATION .
  DATA LV_RFC TYPE RFCDES-RFCDEST.
  GET PARAMETER ID 'RFC' FIELD LV_RFC.
  IF LV_RFC IS INITIAL.
    P_DEST = 'PS4'.
  ENDIF.
ENDFORM.

#2. GUI Status

댓글