쌓고 쌓다

[ABAP] 동적 ALV 필드 구성 및 월별 주차 계산하기 본문

SAP/ABAP

[ABAP] 동적 ALV 필드 구성 및 월별 주차 계산하기

승민아 2026. 1. 3. 15:58
반응형

사실 저번에 동적 ALV Field Catalog를 구성하는 방법에 대해

작성한 적 있지만.

 

깔끔하게 다시 이해하고자 다시 만들어 봤다.

 

목표

입력한 연도에 맞춰서

일자별을 누르면 해당 연도의 모든 일자별 ALV 필드가 나오고

 

주차별을 누르면 월별 주차와 함께 기간을 표시해 보자.

 

월별 주차 계산에 좀 어려웠는데

2025년 2026년은 월별 주차가 잘 계산되어 나오는 걸 확인했다.

 

동적으로 만든 ALV에 고정된 필드도 추가해 보고 데이터도 집어넣어보자.

 

일자에 맞는 주차에도 표시하자.

 

TOP Include

<GT_DYNAMIC> 필드 심볼에는 구성된 Field Catalog를 통해서

Internal Table을 만드는 펑션을 이용해 Internal Table을 가리킬 것이다.

 

ALV 초기화

ALV 관련 변수들의 초기화에도 다를 건 없다.

나는 필드 카탈로그를 구성하고 Display 하는 펑션 호출하는 부분은

버튼이 클릭했을 때 동작하도록 구성했기에

하단의 ALV 초기화 단계에서는 박스 친 저 부분만 구성했다.

 

일자별, 주차별 클릭 이벤트

 

CREATE_DAY_FCAT

동적 ALV라고 해서 특별히 다른 건 없다.

원하는 형식으로 필드 카탈로그를 구성해 주면 된다.

 

코드

더보기

FORM CREATE_DAY_FCAT .

  DATA LS_FCAT     TYPE LVC_S_FCAT,
         LV_LAST_DAY TYPE SY-DATUM,   " YYYYMMDD 형식으로 입력된 연도 월의 말일이 포함된 풀형식 날짜
         LV_MONTH    TYPE N LENGTH 2" MM월 - YYYMMDD에서 추출
         LV_DAY      TYPE N LENGTH 2" DD일 - YYYMMDD에서 추출

  REFRESH GT_DYNAMIC_FCAT.

  DO 12 TIMES.

    CALL FUNCTION 'RP_LAST_DAY_OF_MONTHS'
      EXPORTING
        DAY_IN            CONV SY-DATUM|{ P_YEAR }{ SY-INDEX WIDTH ALIGN RIGHT PAD '0' }01| )  " 'P_YEAR년X월01일'를 넘겨주고
      IMPORTING
        LAST_DAY_OF_MONTH LV_LAST_DAY" 'P_YEAR년X월XX일' 풀형식의 말일을 받는다

    LV_DAY LV_LAST_DAY+6(2).   " YYYYMMDD 형식에서 DD만 추출 (말일 추출)
    LV_MONTH LV_LAST_DAY+4(2)" MM만 추출
    DO LV_DAY TIMES.
      CLEAR LS_FCAT.
      LS_FCAT-FIELDNAME |{ LV_LAST_DAY+0(6}{ SY-INDEX WIDTH ALIGN RIGHT PAD '0' }|" YYYYMM01부터 해당 월의 말일까지 필드네임 할당
      LS_FCAT-COLTEXT |{ CONV ILV_LAST_DAY+4(2}/{ SY-INDEX }|" MM/DD 형식
      APPEND LS_FCAT TO GT_DYNAMIC_FCAT.
    ENDDO.

  ENDDO.

* 현재는 ALV 필드를 TABLE에 존재하는 필드로 구성하는게 아니라서 안했지만. TABLE에 존재하는 타입의 필드로 ALV를 구성하고자한다면
* 아래의 펑션을 이용해 더 심화된 코드를 작성해야한다.
* 'NAMETAB_GET' 펑션으로 TABLE의 필드정보를 가져와서 FCAT을 완전히 REF_TABLE, REF_FIELD 등 온전한 필드타입 구성을 통해
*  ALV화면에서 필드 우클릭하여 정렬등을 했을때 안정성있게 동작할 수 있게 가능.
* 'DDIF_FIELDINFO_GET' 펑션을 사용해서 테이블의 필드 타입을 가져올 수도 있음.

ENDFORM.

 

CREATE_FCAT_TO_ITAB

'CL_ALV_TABLE_CREATE=>CREATE_DYNAMIC_TABLE' 펑션을 사용하여

설정한 FieldCatalog를 가지고 적절한 Internal Table을 반환받을 수 있다.

 

Field Catalog와 데이터를 뿌려줄 Internal Table이 구성되었으니

ALV를 Display 할 수 있는 것이다.

 

코드

더보기

FORM CREATE_FCAT_TO_ITAB .

* CALL METHOD CL_ALV_TABLE_CREATE=>CREATE_DYNAMIC_TABLE 메소드를 사용하여 필드카탈로그를 통해
* 바로 internal Table을 생성할 수도 있다.

  DATA LP_TABLE TYPE REF TO DATA" 메소드 호출 결과 받을 Pointer

  UNASSIGN <GT_DYNAMIC>.

  CALL METHOD CL_ALV_TABLE_CREATE=>CREATE_DYNAMIC_TABLE
    EXPORTING
      IT_FIELDCATALOG GT_DYNAMIC_FCAT                  " Field Catalog
    IMPORTING
      EP_TABLE        LP_TABLE.

  ASSIGN LP_TABLE->TO <GT_DYNAMIC>" LT_TABLE은 주소만 가진 변수라 LOOP를 사용할 수 없다. 그래서 ASSIGN으로 필드심볼과 연결하는 것이다.


  GS_DYNAMIC_LAYOUT-CWIDTH_OPT 'A'.
  CALL METHOD GO_DYNAMIC_ALV_GRID->SET_TABLE_FOR_FIRST_DISPLAY
    EXPORTING
      IS_LAYOUT       GS_DYNAMIC_LAYOUT
    CHANGING
      IT_OUTTAB       <GT_DYNAMIC>
      IT_FIELDCATALOG GT_DYNAMIC_FCAT.
ENDFORM.

 

 

CREATE_WEEK_FCAT

 

주석으로 설명을 열심히 적어 놨기에 월별 주차를 구하는 핵심 알고리즘만 설명하자면

'월~일' 이것이 하나의 주차이다.

이 주차의 요일들이 하나의 달에 모두 포함되어 있으면

그 주차는 해당 달의 주차이지만

 

'월~일' 요일이 다른 두개의 달로 찢어져 들어가 있다면 주차의 계산을 생각해봐야 한다.

더 많은 요일을 갖는 쪽이 해당 주차를 가져간다.

즉, 목요일을 갖는 달이 해당 주차의 주인인 것이다.

 

내가 생각한 알고리즘이 모든 연도에 잘 나올지 모르겠지만

2015 2016년은 원하는 대로 잘 나오는 것을 확인했다.

 

 

코드

더보기

FORM CREATE_WEEK_FCAT .

  DATA LS_FCAT           TYPE LVC_S_FCAT,
         LV_WEEK           TYPE SCAL-WEEK,  " YYYYWW 형식의 주차
         LV_START_WEEK_MON TYPE SY-DATUM,   " YYYYWW 주차의 월요일 날짜
         LV_END_WEEK_DAY   TYPE SY-DATUM,   " YYYYWW 주차의 일요일 날짜
         LV_STACKED_WEEK   TYPE I" 누적 주차 변수. 월별 최대 주차를 구하기 위해 누적 계산용 변수. 1월 1 2 3주차 2월 1 2 3 4주차 3월 1 ... 이렇게 월이 바뀔때까지 주차 누적
         LV_STACKED_MONTH  TYPE I" 위 누적 주차변수에 월을 담당하는 변수.
  REFRESH GT_DYNAMIC_FCAT.

  " 각 월의 몇주차가 존재하는지 계산하여 필드 카탈로그 설정
  LV_STACKED_MONTH 1" 1월
  LV_STACKED_WEEK 1.  " 1주차부터 계산 시작
  DO.
    LV_WEEK |{ P_YEAR }{ SY-INDEX WIDTH ALIGN RIGHT PAD '0' }|" YYYY WW 형식에 WW를 SY-INDEX 2자리로 구성

    " YYYYWW를 넣어 LV_WEEK 주차의 시작 월요일 날짜(LV_START_WEEK_MON)를 받음
    CALL FUNCTION 'WEEK_GET_FIRST_DAY'
      EXPORTING
        WEEK         LV_WEEK
      IMPORTING
        DATE         LV_START_WEEK_MON
      EXCEPTIONS
        WEEK_INVALID 1
        OTHERS       2.
    IF SY-SUBRC <> 0.
      EXIT.
    ENDIF.

    CALL FUNCTION 'GET_WEEK_INFO_BASED_ON_DATE'
      EXPORTING
        DATE   LV_START_WEEK_MON
      IMPORTING
        SUNDAY LV_END_WEEK_DAY.

    " 월~일이 다른 달로 찢어졌을때 그 주는 누가 갖는지. 소유권의 핵심은 목요일을 어떤 달이 가져가는 것이다.
    " 목요일을 갖는 달이 해당 주차를 가져간다.
    " 즉, 월요일에서 3일을 더하면 목요일이된다. 이 목요일이 어떤 달에 속해있는지 보면 해당 주차는 누구의 달인지 정할 수 있다.
    " 월~일이 안찢어지는경우는 월~일이 하나의 월에 포함될때이다.
    " YYYYWW 주차를 넣었을때 현재 월(LV_STACKED_MONTH)과 일치하면 해당 월의 주차로 확정 지어 할당할 수 있다.
    DATA LV_ADD_RESULT TYPE SY-DATUM.
    LV_ADD_RESULT LV_START_WEEK_MON + 3.

    " 주차 확정 : 월요일과 일요일의 월이 일치할때
    IF LV_START_WEEK_MON+4(2LV_STACKED_MONTH AND LV_END_WEEK_DAY+4(2LV_STACKED_MONTH.
      LS_FCAT-FIELDNAME LV_WEEK.
      LS_FCAT-COLTEXT |{ P_YEAR+2(2}-{ LV_STACKED_MONTH WIDTH ALIGN RIGHT PAD '0' }-{ LV_STACKED_WEEK }W({ LV_START_WEEK_MON DATE USER }~{ LV_END_WEEK_DAY DATE USER })|" 26-01-1W(기간)
      APPEND LS_FCAT TO GT_DYNAMIC_FCAT.
      LV_STACKED_WEEK += 1.
    ELSE" 다른달로 찢어져있을때(월이 일치하지 않을때) 목요일을 기준으로 해당 주차의 주인을 찾아야한다.

      IF LV_ADD_RESULT+4(2LV_STACKED_MONTH" 주인이 현재 월이면 현재 주차는 현재 월의 것
        LS_FCAT-FIELDNAME LV_WEEK.
        LS_FCAT-COLTEXT |{ P_YEAR+2(2}-{ LV_STACKED_MONTH WIDTH ALIGN RIGHT PAD '0' }-{ LV_STACKED_WEEK }W({ LV_START_WEEK_MON DATE USER }~{ LV_END_WEEK_DAY DATE USER })|" 26-01-1W(기간)
        APPEND LS_FCAT TO GT_DYNAMIC_FCAT.

        " 월+1 주=1 경우도 있고 주+1만하는 경우 있음 분기쳐줘야함
        IF LV_END_WEEK_DAY+4(2LV_STACKED_MONTH.
          LV_STACKED_WEEK += 1.
        ELSE.
          LV_STACKED_MONTH += 1.
          LV_STACKED_WEEK 1.
        ENDIF.

      ELSE" 현재 주차는 다음 달의 소유이다.
        LV_STACKED_MONTH += 1.
        LV_STACKED_WEEK 1.
        LS_FCAT-FIELDNAME LV_WEEK.
        LS_FCAT-COLTEXT |{ P_YEAR+2(2}-{ LV_STACKED_MONTH WIDTH ALIGN RIGHT PAD '0' }-{ LV_STACKED_WEEK }W({ LV_START_WEEK_MON DATE USER }~{ LV_END_WEEK_DAY DATE USER })|" 26-01-1W(기간)
        APPEND LS_FCAT TO GT_DYNAMIC_FCAT.
        LV_STACKED_WEEK += 1" 다음 주차 할당을 위해 +1
      ENDIF.

    ENDIF.

  ENDDO.



ENDFORM.

 

고정된 ALV 필드 추가

PO 번호와 날짜가 ALV의 어디 일자에, 어디 주차에 포함되는지 확인하기 위해

고정된 ALV 필드를 위와같이 추가하면 된다.

꼭 동적인 ALV 필드만 구성할 수 있는 것은 아니다.

 

 

 

필드 심볼인 Internal Table에 데이터 넣기

단계별로 작성하다 보니 꼬였는데

일자별 모드일 때 'CREATE_FCAT_TO_ITAB_DAY'

주차별일 때 'CREATE_FCAT_TO_ITAB_WEEK'를 호출하도록 변경했다.

 

CREATE_FCAT_TO_ITAB_DAY (데이터 넣기)

위처럼 'EBELN', 'BEDAT' 고정 필드는 저렇게 할당했고

BEDAT 일자에 맞는 곳에 O 표시하는 코드를 작성해 봤다.

 

FIELDNAME을 YYYYMMDD 형식으로 설정했으므로

YYYYMMDD 필드에 'O' 값을 넣어주면 된다.

 

CREAT DATA, DATA REFERENCE 뭔지 모르겠다. 공부할게 또 생겼다..

 

결과가 잘 나온다.

 

CREATE_FCAT_TO_ITAB_WEEK

날짜를 넣어 반환되는 주차에 일치하는 곳에 'O' 표시를 하도록 했다.

 

 

ASSIGN COMPONENT하는 부분 CREAT DATA에 대해서 모르겠어서 공부해 봐야겠다.

반응형