diff --git a/.abapgit.xml b/.abapgit.xml
new file mode 100644
index 0000000..7c0506a
--- /dev/null
+++ b/.abapgit.xml
@@ -0,0 +1,10 @@
+
+
+
+
+ E
+ /src/
+ PREFIX
+
+
+
diff --git a/src/package.devc.xml b/src/package.devc.xml
new file mode 100644
index 0000000..230b50a
--- /dev/null
+++ b/src/package.devc.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+ 하향식 배부 패키지
+
+
+
+
diff --git a/src/zcl_copa_topdown.clas.abap b/src/zcl_copa_topdown.clas.abap
new file mode 100644
index 0000000..4375752
--- /dev/null
+++ b/src/zcl_copa_topdown.clas.abap
@@ -0,0 +1,2031 @@
+class ZCL_COPA_TOPDOWN definition
+ public
+ create public .
+
+public section.
+
+ types:
+ tt_dfies TYPE STANDARD TABLE OF dfies WITH DEFAULT KEY .
+ types:
+ result_tb TYPE STANDARD TABLE OF zstop_result WITH EMPTY KEY .
+ types:
+ target_tb TYPE STANDARD TABLE OF zstop_target WITH EMPTY KEY .
+
+ methods CONSTRUCTOR .
+ methods GET_CUSTOM_TABLE_INFO
+ importing
+ value(ERKRS) type ERKRS
+ exporting
+ !SENDER type STRING
+ !RECEIVER type STRING .
+ methods GET_VARIANT_LIST
+ importing
+ value(ERKRS) type ERKRS
+ returning
+ value(RESULT) type FIST_FIELD_EXT
+ exceptions
+ SELECT_ERR .
+ methods SET_VARIANT_DESC
+ importing
+ value(ERKRS) type ERKRS optional
+ value(VARIANT) type COVARIANT optional
+ value(PERIO) type JAHRPER optional .
+ methods GET_SENDER_RECEIVER_DATA
+ importing
+ value(ERKRS) type ERKRS optional
+ value(VARIANT) type COVARIANT optional
+ value(PERIO) type JAHRPER optional
+ returning
+ value(RESULT) type BAPIRET2 .
+ methods GET_FIELD_CATALOG
+ importing
+ value(ERKRS) type ERKRS
+ value(PERIO) type JAHRPER
+ value(VARIANT) type COVARIANT
+ exporting
+ value(FIELDCATALOG) type TT_DFIES
+ returning
+ value(RESULT) type BAPIRET2 .
+ methods DELETE_TOPDOWN_TB_DATA
+ importing
+ value(ERKRS) type ERKRS
+ value(VARIANT) type COVARIANT
+ value(PERIO) type JAHRPER
+ value(TYPE) type ZTBLS
+ returning
+ value(RESULT) type BAPIRET2 .
+ methods EXECUTE_TOPDOWN_DISTRIBUTE
+ importing
+ value(ERKRS) type ERKRS
+ value(VARIANT) type COVARIANT
+ value(PERIO) type JAHRPER
+ value(SAVE_YN) type BOE_BOOL default 'X'
+ exporting
+ value(RT_RESULT) type RESULT_TB
+ returning
+ value(RESULT) type BAPIRET2 .
+ methods POST_ACTUAL_TOPDOWN_DOCUMENTS
+ importing
+ value(ERKRS) type ERKRS
+ value(VARIANT) type COVARIANT
+ value(PERIO) type JAHRPER
+ value(VRGAR) type RKE_VRGAR
+ !TESTRUN type TESTRUN default 'X'
+ returning
+ value(RESULT) type BAPIRET2_T .
+ methods GET_COPA_DOC_LIST
+ importing
+ value(ERKRS) type ERKRS
+ value(PERIO) type JAHRPER
+ value(VARIANT) type COVARIANT
+ value(REVERSE) type BLG_STORNO default 'X'
+ exporting
+ value(COPA_DOC_LIST) type TARGET_TB
+ returning
+ value(RESULT) type BAPIRET2 .
+ PROTECTED SECTION.
+
+private section.
+
+ types:
+ BEGIN OF ty_bpsel,
+ sort TYPE rke_lfd4,
+ fnam TYPE fieldname,
+ sign TYPE raldb_sign,
+ option TYPE raldb_opti,
+ low TYPE rke_low_l,
+ high TYPE rke_high_l,
+ END OF ty_bpsel .
+ types:
+ tt_bpsel TYPE STANDARD TABLE OF ty_bpsel WITH EMPTY KEY .
+ types:
+ BEGIN OF ty_mng_table,
+ type TYPE db2type,
+ tbname TYPE tabname,
+ text TYPE mssviewortable,
+ END OF ty_mng_table .
+ types:
+ tt_bdcdata TYPE STANDARD TABLE OF bdcdata WITH DEFAULT KEY .
+ types:
+ " 클래스내에서 필요한 기본 정보
+ BEGIN OF ty_working_info,
+ perio TYPE jahrper,
+ variant TYPE covariant,
+ END OF ty_working_info .
+ types:
+ BEGIN OF ty_key_map,
+ key_string TYPE string,
+ dist_id TYPE pbr_seqre,
+ END OF ty_key_map .
+ types:
+ tt_key_map TYPE HASHED TABLE OF ty_key_map
+ WITH UNIQUE KEY key_string .
+ types:
+ tt_dd03p TYPE STANDARD TABLE OF dd03p WITH DEFAULT KEY .
+ types TY_SENDER type ZSTOP_SENDER .
+ types TY_RECEIVER type ZSTOP_RECEIVER .
+ types TY_VARIANT type ZSTOP_VARIANT .
+ types TY_RESULT type ZSTOP_RESULT .
+ types TY_TARGET type ZSTOP_TARGET .
+ types TY_DISTINFO type ZSTOP_DISTINFO .
+ types TY_DISTRULE type ZSTOP_DISTRULE .
+ types:
+ tt_sender TYPE STANDARD TABLE OF ty_sender WITH EMPTY KEY .
+ types:
+ tt_receiver TYPE STANDARD TABLE OF ty_receiver WITH EMPTY KEY .
+ types:
+ tt_variant TYPE STANDARD TABLE OF ty_variant WITH EMPTY KEY .
+ types:
+ TT_result TYPE STANDARD TABLE OF ty_result WITH EMPTY KEY .
+ types:
+ tt_target TYPE STANDARD TABLE OF ty_target WITH EMPTY KEY .
+ types:
+ tt_fieldlist TYPE STANDARD TABLE OF bapi_copa_field WITH DEFAULT KEY .
+ types:
+ tt_copa_data TYPE STANDARD TABLE OF bapi_copa_data WITH DEFAULT KEY .
+
+ data SOURCE_STRUCT_DESC type ref to CL_ABAP_STRUCTDESCR .
+ data SOURCE_TABLE type ref to DATA .
+ data MANAGER_STRUCT_DESC type ref to CL_ABAP_STRUCTDESCR .
+ data MANAGER_TABLE type ref to DATA .
+ data VARIANT_STRUCT_DESC type ref to CL_ABAP_STRUCTDESCR .
+ data VARIANT_TABLE type ref to DATA .
+ data SENDER_STRUCT_DESC type ref to CL_ABAP_STRUCTDESCR .
+ data SENDER_TABLE type ref to DATA .
+ data RECEIVER_STRUCT_DESC type ref to CL_ABAP_STRUCTDESCR .
+ data RECEIVER_TABLE type ref to DATA .
+ data RESULT_STRUCT_DESC type ref to CL_ABAP_STRUCTDESCR .
+ data RESULT_TABLE type ref to DATA .
+ data TARGET_STRUCT_DESC type ref to CL_ABAP_STRUCTDESCR .
+ data TARGET_TABLE type ref to DATA .
+ data:
+ gt_mng_table TYPE TABLE OF ty_mng_table .
+ data MT_SENDER_KEYS type TT_KEY_MAP .
+ data:
+ gv_dist_counter TYPE n LENGTH 9 value '000000000' ##NO_TEXT.
+ data GV_TABNAME type COVAD-TABNAME .
+ data GV_MESSAGE type STRING .
+ data GV_SOURCE type TABNAME .
+ data GV_MANAGER type TABNAME .
+ data GV_VARIANT type TABNAME .
+ data GV_SENDER type TABNAME .
+ data GV_RECEIVER type TABNAME .
+ data GV_RESULT type TABNAME .
+ data GV_TARGET type TABNAME .
+ data GV_DISTINFO type TABNAME .
+ data GV_DISTRULE type TABNAME .
+ data WORKING_INFO type TY_WORKING_INFO .
+
+ methods SET_INFO
+ importing
+ value(PERIO) type JAHRPER
+ value(VARIANT) type COVARIANT .
+ methods GET_VARIANT_INFO
+ importing
+ value(ERKRS) type ERKRS optional
+ value(VARIANT) type COVARIANT optional
+ exporting
+ !COVAD type COVAD .
+ methods GET_TABNAME
+ importing
+ value(ERKRS) type ERKRS optional
+ exporting
+ !TABNAME type TABNAME .
+ methods BUILD_DYNAMIC_QUERY
+ importing
+ !IV_TYPE type C
+ !IT_BPSEL type TT_BPSEL
+ returning
+ value(RT_DATA) type TT_RECEIVER .
+ methods GENERATE_DIST_ID
+ importing
+ !IS_DATA type ANY
+ !IT_BPSEL type TT_BPSEL
+ returning
+ value(RV_DIST) type PBR_SEQRE .
+ methods BUILD_KEY_STRING
+ importing
+ !IS_DATA type ANY
+ !IT_BPSEL type TT_BPSEL
+ !IV_TYPE type C
+ returning
+ value(RV_KEY) type STRING .
+ methods SET_SOURCE_INFO
+ importing
+ value(ERKRS) type ERKRS
+ returning
+ value(RESULT) type BAPIRET2 .
+ methods GET_TB_DATA_EXIST_YN
+ importing
+ value(ERKRS) type ERKRS
+ value(VARIANT) type COVARIANT
+ value(PERIO) type JAHRPER
+ value(TYPE) type ZTBLS
+ returning
+ value(RESULT) type BAPIRET2 .
+ methods BUILD_FIELDLIST
+ importing
+ !IT_CATALOG type TT_DFIES
+ changing
+ !CT_FIELDLIST type TT_FIELDLIST .
+ methods MAP_DOCUMENT_DATA
+ importing
+ value(IT_SOURCE) type ANY TABLE
+ value(IT_CATALOG) type TT_DFIES
+ value(IV_VRGAR) type ANY
+ value(IV_REVERSE) type ABAP_BOOL
+ value(IV_BUDAT) type DAERF
+ changing
+ !CT_INPUTDATA type TT_COPA_DATA
+ !CV_INDEX type RKE_RECORD_ID .
+ methods CREATE_DYNAMIC_TABLE
+ importing
+ !IV_TABNAME type TABNAME
+ returning
+ value(RO_TABLE) type ref to DATA .
+ methods SET_AUDIT_FIELDS
+ changing
+ !CS_DATA type TY_DISTINFO .
+ methods GENERATE_DYNAMIC_NEW_SQL
+ importing
+ !IV_SELECT type STRING
+ !IV_FROM type STRING
+ !IT_WHERE type TABLE
+ !IV_GROUP type STRING
+ exporting
+ !ET_DATA type TT_RECEIVER .
+ENDCLASS.
+
+
+
+CLASS ZCL_COPA_TOPDOWN IMPLEMENTATION.
+
+
+ METHOD build_dynamic_query.
+ DATA : l_seq TYPE n VALUE 1,
+ lb_first TYPE abap_boolean VALUE 'X'.
+
+ TYPES : BEGIN OF ty_where,
+ seq TYPE n LENGTH 2,
+ condition TYPE string,
+ END OF ty_where.
+ DATA : lt_where TYPE TABLE OF ty_where,
+ ls_where TYPE ty_where.
+
+ DATA: lv_select TYPE string,
+ lv_from TYPE string,
+ lv_group TYPE string,
+ lv_sql TYPE string.
+
+ DATA: lv_condition TYPE string,
+ lv_seq TYPE pu12_seqnr VALUE '0'. "데이타 키(seq)
+
+ FIELD-SYMBOLS: TYPE ty_bpsel.
+ lv_from = gv_source.
+
+ " 필수 필드 추가 (rec_waers) 통화키
+ lv_select = |{ lv_select } t1~REC_WAERS AS rec_waers, |.
+ lv_group = |{ lv_group } REC_WAERS, |.
+
+* WHERE 조건
+ "통화유형 필드 필수
+ ls_where = VALUE #( seq = 0
+ condition = |t1~PALEDGER = '01'| "경영단위 통화 데이타 사용
+ ).
+ APPEND ls_where TO lt_where.
+
+ "기간/연도 필드 필수
+ ls_where = VALUE #( seq = 1
+ condition = |AND t1~perio = '{ working_info-perio }'|
+ ).
+ APPEND ls_where TO lt_where.
+
+ CASE iv_type.
+ WHEN 'S'. " 센더 쿼리 구성
+ "동일 필드(FNAM)가 2개 이상인 필드명 추출(OR 연산자 생성 목적)
+ TYPES: BEGIN OF ty_cnt,
+ fnam TYPE fieldname,
+ cnt TYPE i,
+ END OF ty_cnt.
+
+ DATA: lt_grp TYPE TABLE OF ty_cnt,
+ lt_OR TYPE TABLE OF fieldname.
+
+ lt_grp = VALUE #(
+ FOR GROUPS group OF row IN it_bpsel WHERE ( sort = '0200' )
+ GROUP BY ( fnam = row-fnam )
+ ( fnam = group-fnam
+ cnt = REDUCE i( INIT x = 0 FOR r IN GROUP group NEXT x = x + 1 ) )
+ ).
+
+ lt_OR = VALUE #( FOR or IN lt_grp WHERE ( cnt > 1 ) ( or-fnam ) ).
+
+ " SELECT 절 구성 (SORT=0270, LOW=X)
+ LOOP AT it_bpsel ASSIGNING WHERE sort = '0270' AND low = 'X'.
+ lv_select = |{ lv_select } t1~{ -fnam },|.
+ lv_group = |{ lv_group }{ -fnam },|.
+ ENDLOOP.
+
+ " SUM 필드 추가 (SORT=0300, LOW=X)
+ LOOP AT it_bpsel ASSIGNING WHERE sort = '0300' AND low = 'X'.
+ lv_select = |{ lv_select } SUM( t1~{ -fnam } ) AS { -fnam },|.
+ ENDLOOP.
+
+ " WHERE 조건 (SORT=200) - 단일조건 AND ...AND 연결
+ LOOP AT it_bpsel ASSIGNING WHERE sort = '0200'.
+ CLEAR : ls_where, lv_condition.
+
+ cl_abap_dyn_prg=>check_column_name( -fnam ).
+ IF -low <> '*' AND -high <> '*'.
+
+ " lt_OR에 -fnam이 있는 경우 제외
+ READ TABLE lt_OR WITH TABLE KEY table_line = -fnam TRANSPORTING NO FIELDS.
+ IF sy-subrc = 0.
+ CONTINUE.
+ ENDIF.
+
+ l_seq += 1.
+
+ CASE -option.
+ WHEN 'BT'.
+ lv_condition = |AND t1~{ -fnam } BETWEEN '{ -low }' AND '{ -high }'|.
+ WHEN 'EQ'.
+ lv_condition = |AND t1~{ -fnam } = '{ -low }'|.
+ ENDCASE.
+
+ ls_where-seq = l_seq. "SQL의 where조건의 순서
+ ls_where-condition = lv_condition.
+ APPEND ls_where TO lt_where.
+ ENDIF.
+ ENDLOOP.
+
+ " WHERE 조건 (SORT=200) - 다중조건 AND ( a OR b ...)
+ CLEAR : ls_where, lv_condition.
+ LOOP AT it_bpsel ASSIGNING WHERE sort = '0200'.
+
+ cl_abap_dyn_prg=>check_column_name( -fnam ).
+ IF -low <> '*' AND -high <> '*'.
+
+ " lt_OR에 -fnam이 있는 경우 제외
+ READ TABLE lt_OR WITH TABLE KEY table_line = -fnam TRANSPORTING NO FIELDS.
+ IF sy-subrc NE 0.
+ CONTINUE.
+ ENDIF.
+
+ AT NEW fnam.
+ CLEAR : ls_where, lv_condition.
+ lb_first = 'X'. "첫번째 item으로 설정
+ l_seq += 1.
+ lv_condition = |AND ( |.
+ ls_where-seq = l_seq. "SQL의 where조건의 순서
+ ENDAT.
+
+ IF lb_first = 'X'.
+ CASE -option.
+ WHEN 'BT'.
+ lv_condition = lv_condition && |t1~{ -fnam } BETWEEN '{ -low }' AND '{ -high }'|.
+ WHEN 'EQ'.
+ lv_condition = lv_condition && |t1~{ -fnam } = '{ -low }'|.
+ ENDCASE.
+ ELSE.
+ CASE -option.
+ WHEN 'BT'.
+ lv_condition = lv_condition && | OR t1~{ -fnam } BETWEEN '{ -low }' AND '{ -high }'|.
+ WHEN 'EQ'.
+ lv_condition = lv_condition && | OR t1~{ -fnam } = '{ -low }'|.
+ ENDCASE.
+ ENDIF.
+ CLEAR : lb_first.
+
+ AT END OF fnam.
+ lv_condition = lv_condition && | )|.
+
+ ls_where-condition = lv_condition.
+ APPEND ls_where TO lt_where.
+ CLEAR : ls_where, lv_condition.
+ ENDAT.
+
+ ENDIF.
+ ENDLOOP.
+
+
+
+ WHEN 'R'. " 리시버 쿼리 구성
+ " SELECT 절 (SORT=270/201, LOW=X)
+ LOOP AT it_bpsel ASSIGNING WHERE ( sort = '0270' OR sort = '0201' ) AND low = 'X'.
+ lv_select = |{ lv_select } t1~{ -fnam },|.
+ lv_group = |{ lv_group }{ -fnam },|.
+ ENDLOOP.
+
+ " SUM 필드 추가 (SORT=100, FNAM=WKOFNAM, LOW=X)
+ LOOP AT it_bpsel ASSIGNING WHERE sort = '0100' AND fnam = 'WKOFNAM'. " ★ 수정
+ lv_select = |{ lv_select } SUM( t1~{ -low } ) AS { -low },|.
+ ENDLOOP.
+
+* " WHERE 조건 (SORT=0272 → SORT=0274 → SORT=0273 매핑)
+ DATA : it_0274 TYPE TABLE OF ty_bpsel,
+ it_0273 TYPE TABLE OF ty_bpsel.
+
+
+ FIELD-SYMBOLS: TYPE ty_bpsel,
+ TYPE ty_bpsel,
+ TYPE ty_bpsel.
+
+ it_0274 = VALUE #( FOR wa IN it_bpsel WHERE ( sort = '0274' ) ( wa ) ).
+ it_0273 = VALUE #( FOR wa IN it_bpsel WHERE ( sort = '0273' ) ( wa ) ).
+
+ SORT it_0274 BY fnam low.
+ SORT it_0273 BY option fnam.
+
+ "where 조건을 만들어야 하는 필드조건(들)
+ LOOP AT it_bpsel ASSIGNING WHERE sort = '0272'.
+ lb_first = 'X'. "첫번째 item으로 설정
+ LOOP AT it_0274 ASSIGNING WHERE low = -fnam.
+ AT NEW fnam.
+ CLEAR : ls_where, lv_condition.
+ l_seq += 1.
+ lv_condition = | AND ( |.
+ ls_where-seq = l_seq. "SQL의 where조건의 순서
+ ENDAT.
+
+ LOOP AT it_0273 ASSIGNING WHERE fnam = -high.
+ IF lb_first = 'X'.
+ "첫번째 인 경우
+ CASE -option.
+ WHEN 'BT'.
+ lv_condition = lv_condition && |t1~{ -fnam } BETWEEN '{ -low }' AND '{ -high }'|.
+ WHEN 'EQ'.
+ lv_condition = lv_condition && |t1~{ -fnam } = '{ -low }'|.
+ ENDCASE.
+ ELSE.
+ "2번째 이상인 경우 (OR 연산자 필요)
+ CASE -option.
+ WHEN 'BT'.
+ lv_condition = lv_condition && | OR t1~{ -fnam } BETWEEN '{ -low }' AND '{ -high }'|.
+ WHEN 'EQ'.
+ lv_condition = lv_condition && | OR t1~{ -fnam } = '{ -low }'|.
+ ENDCASE.
+ ENDIF.
+
+ CLEAR lb_first. "이후에 들어오는 경우는 OR 연결로 처리할 후속 순번.
+ ENDLOOP.
+
+ AT END OF fnam.
+ lv_condition = lv_condition && |)|.
+
+ ls_where-condition = lv_condition.
+ APPEND ls_where TO lt_where.
+ ENDAT.
+
+ ENDLOOP.
+
+ ENDLOOP.
+
+
+ ENDCASE.
+
+ " 최종 쿼리 정리
+ lv_select = replace( val = lv_select sub = ',' with = '' occ = -1 ).
+ lv_group = replace( val = lv_group sub = ',' with = '' occ = -1 ).
+
+ " 동적 SQL 실행
+ generate_dynamic_new_sql(
+ EXPORTING
+ iv_select = lv_select
+ iv_from = lv_from
+ it_where = lt_where
+ iv_group = lv_group
+ IMPORTING
+ et_data = rt_data
+ ).
+
+ " DIST_ID 처리
+ CASE iv_type.
+ WHEN 'S'.
+ LOOP AT rt_data ASSIGNING FIELD-SYMBOL().
+ -perio = working_info-perio.
+ -gjahr = working_info-perio(4).
+ -perde = working_info-perio+4(3).
+ -variant = working_info-variant.
+
+ -dist_id = generate_dist_id(
+ is_data =
+ it_bpsel = it_bpsel
+ ).
+ INSERT VALUE #(
+ key_string = build_key_string(
+ is_data =
+ it_bpsel = it_bpsel
+ iv_type = 'S'
+ )
+ dist_id = -dist_id
+ ) INTO TABLE mt_sender_keys.
+ ENDLOOP.
+
+ WHEN 'R'.
+ LOOP AT rt_data ASSIGNING FIELD-SYMBOL().
+ lv_seq = lv_seq + 1.
+ -perio = working_info-perio.
+ -gjahr = working_info-perio(4).
+ -perde = working_info-perio+4(3).
+ -variant = working_info-variant.
+ -seq = lv_seq.
+ DATA(lv_receiver_key) = build_key_string(
+ is_data =
+ it_bpsel = it_bpsel
+ iv_type = 'R'
+ ).
+ IF line_exists( mt_sender_keys[ key_string = lv_receiver_key ] ).
+ -dist_id = mt_sender_keys[ key_string = lv_receiver_key ]-dist_id.
+ ELSE.
+ -dist_id = '999999999'.
+ ENDIF.
+ ENDLOOP.
+ ENDCASE.
+ ENDMETHOD.
+
+
+ METHOD build_fieldlist.
+ " 필드리스트 생성 로직
+ APPEND VALUE #( fieldname = 'VRGAR' ) TO ct_fieldlist.
+ APPEND VALUE #( fieldname = 'BELNR_SENDER' ) TO ct_fieldlist.
+ APPEND VALUE #( fieldname = 'POSNR_SENDER' ) TO ct_fieldlist.
+ LOOP AT it_catalog INTO DATA(ls_catalog).
+ APPEND VALUE #( fieldname = ls_catalog-fieldname ) TO ct_fieldlist.
+ ENDLOOP.
+endmethod.
+
+
+ METHOD build_key_string.
+ LOOP AT CAST cl_abap_structdescr( cl_abap_structdescr=>describe_by_data( is_data ) )->components
+ ASSIGNING FIELD-SYMBOL().
+ ASSIGN COMPONENT -name OF STRUCTURE is_data TO FIELD-SYMBOL().
+
+ CASE iv_type.
+ WHEN 'S'. " 센더: SORT=0270 + LOW=X (SUM 필드 제외)
+ READ TABLE it_bpsel TRANSPORTING NO FIELDS
+ WITH KEY fnam = -name
+ sort = '0270'
+ low = 'X'.
+ IF sy-subrc = 0 AND NOT -name CS 'SUM'.
+ rv_key = |{ rv_key }{ }|.
+ ENDIF.
+
+ WHEN 'R'. " 리시버: ★★★ SENDER와 동일한 SORT=270 필드만 사용 ★★★
+ READ TABLE it_bpsel TRANSPORTING NO FIELDS
+ WITH KEY fnam = -name
+ sort = '0270' " ← 201 제외
+ low = 'X'.
+ IF sy-subrc = 0.
+ rv_key = |{ rv_key }{ }|.
+ ENDIF.
+ ENDCASE.
+ ENDLOOP.
+ ENDMETHOD.
+
+
+METHOD constructor.
+
+ DATA: lv_tabname TYPE tabname.
+
+ " 환경정보에서 관리 테이블명 조회
+ CALL FUNCTION 'ZTOPDOWN_ENV'
+ IMPORTING
+ tb_name = lv_tabname.
+
+ " 관리 테이블 정보 로딩
+ SELECT type,
+ tbname,
+ text
+ FROM (lv_tabname)
+ INTO CORRESPONDING FIELDS OF TABLE @gt_mng_table.
+
+ LOOP AT gt_mng_table INTO DATA(ls_table).
+ CASE ls_table-type.
+ WHEN '1'. gv_manager = ls_table-tbname.
+ WHEN '2'. gv_variant = ls_table-tbname.
+ WHEN '3'. gv_sender = ls_table-tbname.
+ WHEN '4'. gv_receiver = ls_table-tbname.
+ WHEN '5'. gv_result = ls_table-tbname.
+ WHEN '6'. gv_target = ls_table-tbname.
+ WHEN '7'. gv_distinfo = ls_table-tbname.
+ WHEN '8'. gv_distrule = ls_table-tbname.
+ ENDCASE.
+ ENDLOOP.
+
+ " 동적 테이블 구조 생성 및 인스턴스 할당 (RETURNING 사용)
+ manager_table = me->create_dynamic_table( gv_manager ).
+ variant_table = me->create_dynamic_table( gv_variant ).
+ sender_table = me->create_dynamic_table( gv_sender ).
+ receiver_table = me->create_dynamic_table( gv_receiver ).
+ result_table = me->create_dynamic_table( gv_result ).
+* target_table = me->create_dynamic_table( gv_target ). " 필요시 활성화
+
+ENDMETHOD.
+
+
+METHOD create_dynamic_table.
+ DATA: lo_struct_desc TYPE REF TO cl_abap_structdescr,
+ lo_table_desc TYPE REF TO cl_abap_tabledescr.
+
+ TRY.
+ lo_struct_desc ?= cl_abap_structdescr=>describe_by_name( iv_tabname ).
+ lo_table_desc = cl_abap_tabledescr=>create(
+ p_line_type = lo_struct_desc
+ p_table_kind = cl_abap_tabledescr=>tablekind_std
+ ).
+ CREATE DATA ro_table TYPE HANDLE lo_table_desc.
+ CATCH cx_sy_create_data_error INTO DATA(lx_error).
+ MESSAGE lx_error->get_text( ) TYPE 'E'.
+ ENDTRY.
+ENDMETHOD.
+
+
+METHOD delete_topdown_tb_data.
+
+ DATA: lv_tabname TYPE tabname,
+ l_check TYPE c,
+ l_exist TYPE bapiret2.
+
+ " 1. 필수 파라미터 체크
+ IF erkrs IS INITIAL OR perio IS INITIAL OR variant IS INITIAL OR type IS INITIAL.
+ gv_message = TEXT-012.
+ result = VALUE #( type = 'E' id = 'FAIL' number = '012' message = gv_message ).
+ RETURN.
+ ENDIF.
+
+ " 2. 삭제 대상 테이블 결정
+ CASE type.
+* WHEN '1'. "CBO테이블관리
+ WHEN '2'. lv_tabname = gv_variant.
+ WHEN '3'. lv_tabname = gv_sender.
+ WHEN '4'. lv_tabname = gv_receiver.
+ WHEN '5'. lv_tabname = gv_result.
+ WHEN '6'. lv_tabname = gv_target.
+ WHEN '7'. lv_tabname = gv_distinfo.
+* WHEN '8'. lv_tabname = gv_distrule. "cbo 조건 데이타 삭제 불가. 별도 관리화면에서...
+ WHEN OTHERS.
+ gv_message = TEXT-019.
+ result = VALUE #( type = 'E' id = 'FAIL' number = '019' message = gv_message ).
+ RETURN.
+ ENDCASE.
+
+ " 3. 전표 발행 상태 체크
+ SELECT SINGLE post INTO @l_check FROM (gv_variant)
+ WHERE perio = @perio AND variant = @variant.
+
+ IF l_check = 'X'.
+ gv_message = TEXT-018.
+ result = VALUE #( type = 'E' id = 'FAIL' number = '018' message = gv_message ).
+ RETURN.
+ ENDIF.
+
+ " 4. 데이터 존재 여부 확인
+ CALL METHOD me->get_tb_data_exist_yn
+ EXPORTING
+ erkrs = erkrs
+ variant = variant
+ perio = perio
+ type = type
+ RECEIVING
+ result = l_exist.
+
+ IF l_exist-type = 'E'.
+ gv_message = TEXT-007.
+ result = VALUE #( type = 'E' id = 'FAIL' number = '007' message = gv_message ).
+ RETURN.
+ ENDIF.
+
+ " 5. 데이터 삭제
+ IF type = '2' OR type = '3' OR type = '4' OR type = '5' OR type = '6'.
+ DELETE FROM (lv_tabname)
+ WHERE variant = @variant AND perio = @perio.
+
+ ELSEIF type = '7' OR type = '8'.
+ DELETE FROM (lv_tabname)
+ WHERE erkrs = @erkrs AND variant = @variant AND perio = @perio.
+
+ ENDIF.
+
+
+ IF sy-subrc <> 0.
+ ROLLBACK WORK.
+ gv_message = TEXT-017.
+ result = VALUE #( type = 'E' id = 'FAIL' number = '017' message = gv_message ).
+ RETURN.
+ ENDIF.
+
+ " 6. 상태 플래그 초기화
+ CASE type.
+ WHEN '3'.
+ UPDATE (gv_variant)
+ SET sender = ''
+ WHERE perio = @perio AND variant = @variant.
+ WHEN '4'.
+ UPDATE (gv_variant)
+ SET receiver = ''
+ WHERE perio = @perio AND variant = @variant.
+ WHEN '5'.
+ UPDATE (gv_variant)
+ SET proc_dist = ''
+ WHERE perio = @perio AND variant = @variant.
+ ENDCASE.
+
+ IF sy-subrc <> 0.
+ ROLLBACK WORK.
+ gv_message = TEXT-017.
+ result = VALUE #( type = 'E' id = 'FAIL' number = '017' message = gv_message ).
+ RETURN.
+ ENDIF.
+
+ COMMIT WORK.
+
+ gv_message = TEXT-016.
+ result = VALUE #( type = 'S' id = 'SUCCESS' number = '016' message = gv_message ).
+
+ENDMETHOD.
+
+
+ METHOD execute_topdown_distribute.
+ TYPES : BEGIN OF ty_dist.
+ INCLUDE TYPE ty_receiver.
+ TYPES: srec_waers TYPE waers,
+ send_tot TYPE wzgxxx9,
+ rrec_waers TYPE waers,
+ skf_val TYPE wzgxxx9,
+ skf_sum TYPE wzgxxx9,
+ END OF ty_dist.
+ DATA : lt_data TYPE TABLE OF ty_dist.
+
+ DATA: lt_source TYPE TABLE OF string,
+ lv_prog TYPE progname,
+ lv_sender_val TYPE fieldname,
+ lv_receiver_val TYPE fieldname.
+
+ DATA : lt_field TYPE TABLE OF dfies.
+
+ DATA : l_dist_value TYPE wzgxxx9,
+ l_dist_id_sum TYPE wzgxxx9,
+ l_dist_done_sum TYPE wzgxxx9,
+ l_diff_val TYPE wzgxxx9.
+ DATA : l_last_record_yn TYPE boe_bool.
+ DATA : lt_result TYPE tt_result,
+ ls_result TYPE ty_result.
+
+ DATA : l_check TYPE c,
+ ans TYPE c LENGTH 8.
+
+ " 1. 필수 파라미터 체크
+ IF erkrs IS INITIAL OR perio IS INITIAL OR variant IS INITIAL.
+ gv_message = TEXT-012.
+ result = VALUE #( type = 'E' id = 'FAIL' number = '012' message = gv_message ).
+ RETURN.
+ ENDIF.
+
+ " 2. 전표 발행 상태 체크
+ SELECT SINGLE post INTO @l_check FROM (gv_variant)
+ WHERE perio = @perio AND variant = @variant.
+
+ IF l_check = 'X'.
+ gv_message = TEXT-018.
+ result = VALUE #( type = 'E' id = 'FAIL' number = '018' message = gv_message ).
+ RETURN.
+ ENDIF.
+
+ " 3. 이전 배부 수행 결과가 있을 경우, 삭제 후 재 처리 안내.
+ CLEAR : l_check.
+ SELECT SINGLE proc_dist INTO @l_check FROM (gv_variant)
+ WHERE perio = @perio AND variant = @variant.
+
+ IF l_check = 'X'.
+ CALL FUNCTION 'POPUP_TO_CONFIRM'
+ EXPORTING
+ titlebar = 'Title POPUP_TO_CONFIRM'
+ text_question = TEXT-006
+ text_button_1 = 'OK'
+ icon_button_1 = 'ICON_CHECKED'
+ text_button_2 = 'NO'
+ icon_button_2 = 'ICON_NO'
+ display_cancel_button = ' '
+ popup_type = 'ICON_MESSAGE_ERROR'
+ IMPORTING
+ answer = ans.
+
+ IF ans = 2.
+ RETURN.
+ ELSE. "이전 데이타 삭제.
+ CALL METHOD me->delete_topdown_tb_data
+ EXPORTING
+ erkrs = erkrs
+ variant = variant
+ perio = perio
+ type = '5'
+ RECEIVING
+ result = result.
+
+ IF result-type = 'E'.
+ gv_message = TEXT-017.
+ result = VALUE #( type = 'E' id = 'FAIL' number = '017' message = gv_message ).
+ RETURN.
+ ENDIF.
+ ENDIF.
+ ENDIF.
+
+ ASSIGN ls_result TO FIELD-SYMBOL().
+
+* variant별로 실사용 하는 필드 카탈로그 정보 가져오기.
+ CALL METHOD me->get_field_catalog
+ EXPORTING
+ erkrs = erkrs
+ perio = perio
+ variant = variant
+ IMPORTING
+ fieldcatalog = lt_field
+ RECEIVING
+ result = result.
+
+* 카탈로그 중에서, 센더와 리시버의 값필드 확인
+ LOOP AT lt_field INTO DATA(ls_field) WHERE inttype IS NOT INITIAL.
+ CASE ls_field-inttype.
+ WHEN 'T'. "리시버 값필드(배부 기준필드)
+ lv_receiver_val = ls_field-fieldname.
+ WHEN 'C'. "센더 값필드(배부 할 금액 필드)
+ lv_sender_val = ls_field-fieldname.
+ ENDCASE.
+ ENDLOOP.
+
+
+* 배부 수행 데이타 생성.
+* 다중 테이블 조인시 동적 쿼리 안되어..부득이 서브루틴풀로 구현.
+ APPEND `REPORT ZDYNAMIC_QUERY.` TO lt_source.
+ APPEND `FORM select_query CHANGING lt_data TYPE ANY TABLE.` TO lt_source.
+ APPEND | SELECT | TO lt_source.
+
+ LOOP AT lt_field INTO DATA(ls_field_select) WHERE inttype IS INITIAL.
+ APPEND | q~{ ls_field_select-fieldname }, | TO lt_source.
+ ENDLOOP.
+
+ APPEND | p~rec_waers as srec_waers, | TO lt_source.
+ APPEND | p~{ lv_sender_val } as send_tot, | TO lt_source.
+ APPEND | q~rec_waers as rrec_waers, | TO lt_source.
+ APPEND | q~{ lv_receiver_val } as skf_val, | TO lt_source.
+ APPEND | SUM( q~{ lv_receiver_val } ) OVER( PARTITION BY p~dist_id ) AS skf_sum | TO lt_source.
+ APPEND | FROM { gv_sender } AS p | TO lt_source.
+ APPEND | LEFT OUTER JOIN { gv_receiver } AS q | TO lt_source.
+ APPEND | ON p~perio = q~perio | TO lt_source.
+ APPEND | AND p~variant = q~variant | TO lt_source.
+ APPEND | AND p~dist_id = q~dist_id | TO lt_source.
+ APPEND | WHERE p~perio = '{ perio }' | TO lt_source.
+ APPEND | AND p~variant = '{ variant }' | TO lt_source.
+ APPEND | INTO CORRESPONDING FIELDS OF TABLE @lt_data. | TO lt_source.
+ APPEND `ENDFORM.` TO lt_source.
+
+* " 서브루틴 풀 생성
+ GENERATE SUBROUTINE POOL lt_source NAME lv_prog.
+ IF sy-subrc = 0.
+ TRY.
+ " CHANGING 파라미터를 통해 데이터 전달
+ PERFORM select_query IN PROGRAM (lv_prog) CHANGING lt_data.
+ MESSAGE |{ lines( lt_data ) }건 데이터 수신 완료| TYPE 'S'.
+
+ CATCH cx_sy_dyn_call_error INTO DATA(lx_error).
+ MESSAGE |동적 호출 오류: { lx_error->get_text( ) }| TYPE 'E'.
+ CLEANUP.
+ " 예외 발생 시에도 서브루틴 풀 정리
+ DELETE REPORT lv_prog.
+ ENDTRY.
+
+ " 서브루틴 풀 삭제 (메모리에서 제거)
+ DELETE REPORT lv_prog.
+ IF sy-subrc = 0.
+ MESSAGE |동적 프로그램 { lv_prog } 삭제 완료| TYPE 'S'.
+ ELSE.
+ MESSAGE |동적 프로그램 { lv_prog } 삭제 실패 - 이미 삭제됨| TYPE 'S'.
+ ENDIF.
+ ELSE.
+ MESSAGE |서브루틴 풀 생성 실패: { sy-subrc }| TYPE 'E'.
+ ENDIF.
+
+ " 메모리 정리 (혹시 모를 잔여 데이터 정리)
+ CLEAR: lt_source.
+
+* 배부 작업 시작 - Record별로 배부하기 용이하게 하기 위하여 위 서브루틴 풀 사용하여 쿼리 수행
+* 레코드 데이타 항목으로 배부 수행 가능.
+
+ SORT lt_data BY dist_id seq.
+ LOOP AT lt_data INTO DATA(ls_data).
+ AT NEW dist_id.
+ CLEAR : l_dist_id_sum, l_dist_done_sum, l_diff_val, l_last_record_yn .
+ ENDAT.
+
+ CLEAR : l_dist_value.
+ MOVE-CORRESPONDING ls_data TO .
+ l_dist_id_sum = ls_data-send_tot.
+
+ "현재 리시버에 할당할 배부 금액 계산
+ l_dist_value = ls_data-send_tot * ( ls_data-skf_val / ls_data-skf_sum ).
+
+ "DIST_ID 별로 실제 배부된 금액 누적(추후 단수 차이 보정용)
+ l_dist_done_sum = l_dist_done_sum + l_dist_value.
+
+ AT END OF dist_id.
+ "마지막 레코드인 경우 flag 체크 - 단수차이 조정 대상.
+ l_last_record_yn = 'X'.
+ ENDAT.
+
+ IF l_last_record_yn = 'X'.
+ l_diff_val = l_dist_id_sum - l_dist_done_sum.
+ ENDIF.
+
+ -rec_waers = ls_data-srec_waers.
+
+* 배부 결과 값은 센더의 값필드 항목으로 리시버 데이타에 저장.
+ ASSIGN COMPONENT lv_sender_val OF STRUCTURE TO FIELD-SYMBOL().
+ = l_dist_value + l_diff_val.
+
+ APPEND ls_result TO lt_result.
+ ENDLOOP.
+
+ "결과 저장
+ IF save_yn = 'X'.
+ INSERT (gv_result) FROM TABLE lt_result.
+ IF sy-subrc NE 0.
+ ROLLBACK WORK.
+ ENDIF.
+
+ UPDATE (gv_variant)
+ SET proc_dist = 'X'
+ WHERE perio = perio
+ AND variant = variant.
+ IF sy-subrc NE 0.
+ ROLLBACK WORK.
+ ENDIF.
+
+ COMMIT WORK.
+ ENDIF.
+
+ rt_result[] = lt_result[].
+
+
+ " 성공 메시지 추가
+ gv_message = TEXT-016.
+ result = VALUE #(
+ type = 'S'
+ id = 'SUCCESS'
+ number = '016'
+ message = gv_message ).
+ ENDMETHOD.
+
+
+ METHOD generate_dist_id.
+ DATA(lv_key) = build_key_string(
+ is_data = is_data
+ it_bpsel = it_bpsel
+ iv_type = 'S' " 센더용 키 생성
+ ).
+
+ " 기존 키 존재 시 재사용
+ IF line_exists( mt_sender_keys[ key_string = lv_key ] ).
+ rv_dist = mt_sender_keys[ key_string = lv_key ]-dist_id.
+ ELSE.
+ ADD 1 TO gv_dist_counter.
+ rv_dist = gv_dist_counter.
+ ENDIF.
+ ENDMETHOD.
+
+
+ METHOD generate_dynamic_new_sql.
+
+ DATA: lt_source TYPE TABLE OF string,
+ lv_prog TYPE progname,
+ lt_data TYPE tt_receiver.
+
+ FIELD-SYMBOLS: TYPE any,
+ TYPE any.
+
+ " 임시 프로그램 소스 생성
+ APPEND `REPORT ZDYNAMIC_QUERY.` TO lt_source.
+ APPEND `FORM execute_query CHANGING ct_result TYPE ANY TABLE.` TO lt_source.
+ APPEND ` DATA: lt_data TYPE table of ZSTOP_RECEIVER.` TO lt_source.
+ APPEND | SELECT { iv_select }| TO lt_source.
+ APPEND | FROM { iv_from } AS t1| TO lt_source.
+
+
+ IF it_where[] IS NOT INITIAL.
+ APPEND | WHERE | TO lt_source.
+
+ LOOP AT it_where ASSIGNING .
+ ASSIGN COMPONENT 'CONDITION' OF STRUCTURE TO .
+ IF sy-subrc = 0.
+ APPEND TO lt_source.
+ ENDIF.
+ ENDLOOP.
+ ENDIF.
+
+
+ IF iv_group IS NOT INITIAL.
+ APPEND | GROUP BY { iv_group }| TO lt_source.
+ ENDIF.
+ APPEND | INTO CORRESPONDING FIELDS OF TABLE @lt_data.| TO lt_source.
+* APPEND | INTO TABLE @data(lt_data).| TO lt_source.
+ APPEND ` ct_result = lt_data.` TO lt_source.
+ APPEND `ENDFORM.` TO lt_source.
+
+ " 서브루틴 풀 생성
+ GENERATE SUBROUTINE POOL lt_source NAME lv_prog.
+ IF sy-subrc = 0.
+ TRY.
+ " CHANGING 파라미터를 통해 데이터 전달
+ PERFORM execute_query IN PROGRAM (lv_prog) CHANGING lt_data.
+
+ et_data = lt_data.
+ MESSAGE |{ lines( et_data ) }건 데이터 수신 완료| TYPE 'S'.
+
+ CATCH cx_sy_dyn_call_error INTO DATA(lx_error).
+ MESSAGE |동적 호출 오류: { lx_error->get_text( ) }| TYPE 'E'.
+
+ CLEANUP.
+ " 예외 발생 시에도 서브루틴 풀 정리
+ DELETE REPORT lv_prog.
+ ENDTRY.
+
+ " 서브루틴 풀 삭제 (메모리에서 제거)
+ DELETE REPORT lv_prog.
+ IF sy-subrc = 0.
+ MESSAGE |동적 프로그램 { lv_prog } 삭제 완료| TYPE 'S'.
+ ELSE.
+ MESSAGE |동적 프로그램 { lv_prog } 삭제 실패 - 이미 삭제됨| TYPE 'S'.
+ ENDIF.
+
+ ELSE.
+ MESSAGE |서브루틴 풀 생성 실패: { sy-subrc }| TYPE 'E'.
+ ENDIF.
+
+ " 메모리 정리 (혹시 모를 잔여 데이터 정리)
+ CLEAR: lt_data, lt_source.
+
+ ENDMETHOD.
+
+
+ METHOD get_copa_doc_list.
+ DATA : l_check TYPE c.
+
+ DATA: lt_source TYPE TABLE OF string,
+ lv_prog TYPE progname,
+ lv_sender_val TYPE fieldname,
+ lv_receiver_val TYPE fieldname.
+
+ DATA : lt_data TYPE TABLE OF ty_target,
+ lt_field TYPE TABLE OF dfies.
+
+ DATA : ls_doc TYPE ty_target.
+
+ " 필수 파라미터 점검
+ IF erkrs IS INITIAL OR perio IS INITIAL OR variant IS INITIAL.
+ gv_message = TEXT-012.
+ result = VALUE #( type = 'E' id = 'FAIL' number = '012' message = gv_message ).
+ RETURN.
+ ENDIF.
+
+ "Source 테이블 정보 세팅
+ me->get_tabname( EXPORTING erkrs = erkrs IMPORTING tabname = gv_source ).
+
+ " 전표 발행 상태 체크
+ SELECT SINGLE post INTO @l_check FROM (gv_variant)
+ WHERE perio = @perio AND variant = @variant.
+
+ IF l_check NE 'X'.
+ gv_message = TEXT-023.
+ result = VALUE #( type = 'E' id = 'FAIL' number = '023' message = gv_message ).
+ RETURN.
+ ENDIF.
+
+
+* variant별로 실사용 하는 필드 카탈로그 정보 가져오기.
+ me->get_field_catalog( EXPORTING erkrs = erkrs
+ perio = perio
+ variant = variant
+ IMPORTING fieldcatalog = lt_field
+ RECEIVING result = result ).
+
+* 카탈로그 중에서, 센더와 리시버의 값필드 확인
+ LOOP AT lt_field INTO DATA(ls_field) WHERE inttype IS NOT INITIAL.
+ CASE ls_field-inttype.
+ WHEN 'T'. "리시버 값필드(배부 기준필드)
+ lv_receiver_val = ls_field-fieldname.
+ WHEN 'C'. "센더 값필드(배부 할 금액 필드)
+ lv_sender_val = ls_field-fieldname.
+ ENDCASE.
+ ENDLOOP.
+
+* 배부 수행 데이타 생성.
+* 다중 테이블 조인시 동적 쿼리 안되어..부득이 서브루틴풀로 구현.
+ APPEND `REPORT ZDYNAMIC_QUERY.` TO lt_source.
+ APPEND `FORM select_query CHANGING lt_data TYPE ANY TABLE.` TO lt_source.
+ APPEND | SELECT | TO lt_source.
+
+ APPEND | p~vrgar, | TO lt_source.
+ APPEND | p~belnr, | TO lt_source.
+ APPEND | q~belnr AS STO_BELNR, | TO lt_source. "원본전표에 역분개 전표 번호를 위치(standard 전표 상태와 반대로 표기)
+ APPEND | p~belnr_sender, | TO lt_source.
+ APPEND | p~posnr_sender, | TO lt_source.
+
+ LOOP AT lt_field INTO DATA(ls_field_select) WHERE inttype IS INITIAL.
+ "CO-PA 전표 항목이 아닌 필드는 제외.
+ CHECK ls_field_select-fieldname NE 'VARIANT' AND ls_field_select-fieldname NE 'DIST_ID' AND ls_field_select-fieldname NE 'SEQ'.
+ APPEND | p~{ ls_field_select-fieldname }, | TO lt_source.
+ ENDLOOP.
+
+ APPEND | p~{ lv_sender_val } | TO lt_source.
+ APPEND | FROM { gv_source } AS p | TO lt_source.
+ APPEND | LEFT OUTER JOIN { gv_source } AS q | TO lt_source.
+ APPEND | ON p~paledger = q~paledger | TO lt_source.
+ APPEND | AND p~perio = q~perio | TO lt_source.
+ APPEND | AND p~belnr = q~sto_belnr | TO lt_source.
+ APPEND | WHERE p~paledger = '01' | TO lt_source.
+ APPEND | AND p~perio = '{ perio }' | TO lt_source.
+ APPEND | AND p~sto_belnr = ' ' | TO lt_source.
+ APPEND | AND p~belnr_sender = '{ variant }' | TO lt_source.
+
+ IF reverse = 'X'.
+ APPEND | AND ( q~belnr is null OR q~belnr is initial ) | TO lt_source.
+ ENDIF.
+ APPEND | INTO CORRESPONDING FIELDS OF TABLE @lt_data. | TO lt_source.
+ APPEND `ENDFORM.` TO lt_source.
+
+
+* " 서브루틴 풀 생성
+ GENERATE SUBROUTINE POOL lt_source NAME lv_prog.
+ IF sy-subrc = 0.
+ TRY.
+ PERFORM select_query IN PROGRAM (lv_prog) CHANGING lt_data.
+ MESSAGE |{ lines( lt_data ) }건 데이터 수신 완료| TYPE 'S'.
+ CATCH cx_sy_dyn_call_error INTO DATA(lx_error).
+ MESSAGE |동적 호출 오류: { lx_error->get_text( ) }| TYPE 'E'.
+ ENDTRY.
+ DELETE REPORT lv_prog. "무조건 정리
+ ENDIF.
+
+ " 메모리 정리 (혹시 모를 잔여 데이터 정리)
+ CLEAR: lt_source.
+
+ "조회 전표가 없는 경우
+ IF lt_data[] IS INITIAL.
+ gv_message = TEXT-024.
+ result = VALUE #( type = 'E' id = 'FAIL' number = '024' message = gv_message ).
+ RETURN.
+ ENDIF.
+
+ LOOP AT lt_data INTO DATA(ls_data).
+ MOVE-CORRESPONDING ls_data TO ls_doc.
+ ls_doc-variant = ls_data-belnr_sender.
+ ls_doc-dist_id = ls_data-posnr_sender.
+
+ APPEND ls_doc TO copa_doc_list.
+ ENDLOOP.
+ ENDMETHOD.
+
+
+ METHOD get_custom_table_info.
+ DATA : result TYPE bapiret2.
+
+ IF erkrs IS INITIAL .
+ gv_message = TEXT-012.
+ MESSAGE gv_message TYPE 'E'.
+ ENDIF.
+
+* 현재 상태의 정보를 전역 변수에 업데이트.
+* CALL METHOD me->get_package_info
+* EXPORTING
+* erkrs = erkrs
+* RECEIVING
+* result = result.
+
+ sender = gv_sender.
+ receiver = gv_receiver.
+ ENDMETHOD.
+
+
+METHOD get_field_catalog.
+
+ CONSTANTS : lc_sender TYPE tabname VALUE 'SENDER',
+ lc_receiver TYPE tabname VALUE 'RECEIVER'.
+
+ TYPES : BEGIN OF ty_bpsel,
+ sort TYPE rke_lfd4,
+ fnam TYPE fieldname,
+ low TYPE rke_low_l,
+ END OF ty_bpsel.
+
+ DATA : lt_dfies TYPE STANDARD TABLE OF dfies,
+ lv_position TYPE tabfdpos VALUE '0000',
+ it_bpsel TYPE STANDARD TABLE OF ty_bpsel,
+ ls_fieldcatalog TYPE dfies.
+
+ " 1. 필수 파라미터 체크
+ IF erkrs IS INITIAL OR perio IS INITIAL OR variant IS INITIAL.
+ gv_message = TEXT-012.
+ result = VALUE #( type = 'E' id = 'FAIL' number = '012' message = gv_message ).
+ RETURN.
+ ENDIF.
+
+ " 2. 조건정보 조회
+ SELECT sort, fnam, low
+ FROM (gv_distinfo)
+ WHERE perio = @perio
+ AND variant = @variant
+ INTO TABLE @it_bpsel.
+
+ IF it_bpsel IS INITIAL.
+ gv_message = TEXT-007.
+ result = VALUE #( type = 'E' id = 'FAIL' number = '007' message = gv_message ).
+ RETURN.
+ ENDIF.
+
+ " 3. 조건별 필드 카탈로그 생성 (최신 구문 활용)
+ LOOP AT it_bpsel INTO DATA(ls_bpsel).
+
+ IF ls_bpsel-sort = '0270' AND ls_bpsel-low = 'X'.
+ fieldcatalog = VALUE #( BASE fieldcatalog
+ ( fieldname = ls_bpsel-fnam tabname = lc_sender ) ).
+ ENDIF.
+
+ IF ls_bpsel-sort = '0300' AND ls_bpsel-low = 'X'.
+ fieldcatalog = VALUE #( BASE fieldcatalog
+ ( fieldname = ls_bpsel-fnam tabname = lc_sender inttype = 'C' ) ).
+ ENDIF.
+
+ IF ( ls_bpsel-sort = '0270' OR ls_bpsel-sort = '0201' ) AND ls_bpsel-low = 'X'.
+ fieldcatalog = VALUE #( BASE fieldcatalog
+ ( fieldname = ls_bpsel-fnam tabname = lc_receiver ) ).
+ ENDIF.
+
+ IF ls_bpsel-sort = '0100' AND ls_bpsel-fnam = 'WKOFNAM'.
+ fieldcatalog = VALUE #( BASE fieldcatalog
+ ( fieldname = ls_bpsel-low tabname = lc_receiver inttype = 'T' ) ).
+ ENDIF.
+
+ ENDLOOP.
+
+ " 4. 추가 필수 필드 일괄 추가 (배열 LOOP 활용)
+ DATA lt_required_fields TYPE STANDARD TABLE OF fieldname WITH EMPTY KEY.
+ lt_required_fields = VALUE #( ( 'PERIO' ) ( 'GJAHR' ) ( 'PERDE' ) ( 'VARIANT' ) ( 'DIST_ID' ) ( 'SEQ' ) ( 'REC_WAERS' ) ).
+
+ LOOP AT lt_required_fields INTO DATA(lv_field).
+ CLEAR ls_fieldcatalog.
+ ls_fieldcatalog-fieldname = lv_field.
+ ls_fieldcatalog-tabname = COND #( WHEN lv_field = 'SEQ' THEN lc_receiver ELSE lc_sender ).
+ APPEND ls_fieldcatalog TO fieldcatalog.
+ ENDLOOP.
+
+ " 5. 중복 제거 및 정렬
+ SORT fieldcatalog BY fieldname tabname DESCENDING. "센더/리시버 중복된 필드인 경우, sender(공통) 를 남기기 위해..
+ DELETE ADJACENT DUPLICATES FROM fieldcatalog COMPARING fieldname INTTYPE.
+
+ " 6. DB 테이블 기준 정렬 순서 재정의
+ CALL FUNCTION 'DDIF_FIELDINFO_GET'
+ EXPORTING
+ tabname = gv_receiver
+ TABLES
+ dfies_tab = lt_dfies
+ EXCEPTIONS
+ not_found = 1
+ OTHERS = 2.
+
+ IF sy-subrc = 0.
+ SORT lt_dfies BY position.
+ LOOP AT lt_dfies INTO DATA(ls_dfies).
+ READ TABLE fieldcatalog ASSIGNING FIELD-SYMBOL() WITH KEY fieldname = ls_dfies-fieldname.
+ IF sy-subrc = 0.
+ lv_position += 1.
+ -position = lv_position.
+ ENDIF.
+ ENDLOOP.
+ ENDIF.
+
+ SORT fieldcatalog BY position.
+
+ " 7. 성공 메시지
+ gv_message = TEXT-016.
+ result = VALUE #( type = 'S' id = 'SUCCESS' number = '016' message = gv_message ).
+
+ENDMETHOD.
+
+
+ METHOD get_sender_receiver_data.
+
+ DATA: ls_sender TYPE ty_sender,
+ lt_sender TYPE TABLE OF ty_sender,
+ lt_sender_buff TYPE TABLE OF ty_receiver, "동적쿼리 수행 구조체는 리시버 구조로 수행.
+ lt_receiver TYPE TABLE OF ty_receiver.
+ DATA : l_check TYPE bapiret2.
+ DATA : it_bpsel TYPE zcl_copa_topdown=>tt_bpsel.
+
+ CLEAR: gv_dist_counter.
+ CALL METHOD me->set_source_info
+ EXPORTING
+ erkrs = erkrs
+ RECEIVING
+ result = result.
+
+ " 공용 정보 세팅
+ set_info(
+ perio = perio
+ variant = variant
+ ).
+
+ "이전 처리 내역 확인 ===================================================================
+ CALL METHOD me->get_tb_data_exist_yn
+ EXPORTING
+ erkrs = erkrs
+ variant = variant
+ perio = perio
+ type = '3' "센더 테이블
+ RECEIVING
+ result = l_check.
+
+ IF l_check-type = 'S'.
+ " 센더 데이타가 이미 존재하는 경우.
+ " 실패 메시지 추가
+ gv_message = TEXT-020.
+ result = VALUE #( type = 'E' id = 'FAIL' number = '020' message = gv_message ).
+ RETURN.
+ ENDIF.
+
+ CALL METHOD me->get_tb_data_exist_yn
+ EXPORTING
+ erkrs = erkrs
+ variant = variant
+ perio = perio
+ type = '4' "리시버 테이블
+ RECEIVING
+ result = l_check.
+
+ IF l_check-type = 'S'.
+ " 리시버 데이타가 이미 존재하는 경우.
+ " 실패 메시지 추가
+ gv_message = TEXT-020.
+ result = VALUE #( type = 'E' id = 'FAIL' number = '020' message = gv_message ).
+ RETURN.
+ ENDIF.
+
+ " ========================================================================================
+
+ SELECT sort,
+ fnam,
+ sign,
+ optionn AS option,
+ low,
+ high
+ FROM (gv_distinfo)
+ WHERE perio = @perio
+ AND variant = @variant
+ INTO TABLE @it_bpsel.
+
+ IF it_bpsel IS INITIAL.
+ gv_message = TEXT-007.
+ MESSAGE gv_message TYPE 'E'.
+ ENDIF.
+
+ " 센더 데이터 추출 및 DIST_ID 생성
+ lt_sender_buff = build_dynamic_query(
+ iv_type = 'S'
+ it_bpsel = it_bpsel
+ ).
+
+ LOOP AT lt_sender_buff INTO DATA(ls_buff).
+ MOVE-CORRESPONDING ls_buff TO ls_sender.
+ APPEND ls_sender TO lt_sender.
+ ENDLOOP.
+
+ " 리시버 데이터 추출 및 DIST_ID 매핑
+ lt_receiver = build_dynamic_query(
+ iv_type = 'R'
+ it_bpsel = it_bpsel
+ ).
+
+ " 데이터 저장
+ INSERT (gv_sender) FROM TABLE lt_sender.
+ IF sy-subrc NE 0.
+ ROLLBACK WORK.
+ RETURN.
+ ENDIF.
+
+ INSERT (gv_receiver) FROM TABLE lt_receiver.
+ IF sy-subrc NE 0.
+ ROLLBACK WORK.
+ RETURN.
+ ENDIF.
+
+ UPDATE (gv_variant)
+ SET sender = 'X'
+ receiver = 'X'
+ WHERE perio = perio
+ AND variant = variant.
+ IF sy-subrc NE 0.
+ ROLLBACK WORK.
+ ENDIF.
+
+ COMMIT WORK.
+ " 성공 메시지 추가
+ gv_message = TEXT-016.
+ result = VALUE #( type = 'S' id = 'SUCCESS' number = '016' message = gv_message ).
+ ENDMETHOD.
+
+
+ METHOD get_tabname.
+ CONCATENATE 'CE1' erkrs INTO tabname.
+ ENDMETHOD.
+
+
+ METHOD get_tb_data_exist_yn.
+ DATA : l_check TYPE c,
+ lv_tabname TYPE tabname.
+
+
+ IF erkrs IS INITIAL OR perio IS INITIAL OR variant IS INITIAL OR type IS INITIAL.
+ " 실패 메시지 추가
+ gv_message = TEXT-012.
+ result = VALUE #( type = 'E' id = 'FAIL' number = '012' message = gv_message ).
+ RETURN.
+ ENDIF.
+
+ CASE type.
+* WHEN '1'. "CBO테이블관리
+ WHEN '2'. "배부 기준 정보(월별)
+ lv_tabname = gv_variant.
+ WHEN '3'. "센더 데이타
+ lv_tabname = gv_sender.
+ WHEN '4'. "배부 기준 데이타
+ lv_tabname = gv_receiver.
+ WHEN '5'. "배부 결과 데이타
+ lv_tabname = gv_result.
+ WHEN '6'. "전표 발행 대상 데이타
+ lv_tabname = gv_target.
+ WHEN '7'. "배부 기준 세부 정보 테이블
+ lv_tabname = gv_distinfo.
+ WHEN '8'. "배부 조건 Customizing
+ lv_tabname = gv_distrule.
+ WHEN OTHERS.
+ " 실패 메시지 추가
+ gv_message = TEXT-019.
+ result = VALUE #( type = 'E' id = 'FAIL' number = '019' message = gv_message ).
+ RETURN.
+ ENDCASE.
+
+ IF type = '2' OR type = '3' OR type = '4' OR type = '5' OR type = '6'.
+ SELECT SINGLE 'X'
+ INTO @l_check
+ FROM (lv_tabname)
+ WHERE variant = @variant
+ AND perio = @perio.
+ ELSEIF type = '7' OR type = '8'.
+ SELECT SINGLE 'X'
+ INTO @l_check
+ FROM (lv_tabname)
+ WHERE erkrs = @erkrs
+ AND variant = @variant
+ AND perio = @perio.
+ ENDIF.
+
+ IF l_check = 'X'.
+ " 데이타가 존재함.
+ result = VALUE #(
+ type = 'S'
+ id = 'SUCCESS'
+ number = '000'
+ message = '데이타 조회 완료' ).
+ ELSE.
+ " 데이타가 존재하지 않음.
+ result = VALUE #(
+ type = 'E'
+ id = 'FAIL'
+ number = '000'
+ message = '데이타 없음' ).
+
+ ENDIF.
+
+ ENDMETHOD.
+
+
+ METHOD get_variant_info.
+
+ DATA : lv_tabname TYPE tabname.
+
+ CALL METHOD me->get_tabname
+ EXPORTING
+ erkrs = erkrs
+ IMPORTING
+ tabname = lv_tabname.
+
+ SELECT SINGLE
+ applclass,
+ subclass,
+ tabname,
+ func,
+ variant
+ FROM covad
+ WHERE variant = @variant
+ AND tabname = @lv_tabname
+ INTO CORRESPONDING FIELDS OF @covad.
+
+
+ ENDMETHOD.
+
+
+ METHOD get_variant_list.
+ DATA : l_tabname TYPE string.
+
+ IF erkrs IS INITIAL.
+ gv_message = TEXT-001.
+ MESSAGE gv_message TYPE 'E'.
+ ENDIF.
+
+ CONCATENATE 'CE1' erkrs INTO l_tabname.
+
+
+ SELECT 'KE28' AS report,
+ p~Variant AS variant,
+ q~vtext AS fieldname
+ FROM covad AS p
+ LEFT OUTER JOIN covat AS q
+ ON q~spras = @sy-langu
+ AND q~applclass = p~applclass
+ AND q~subclass = p~subclass
+ AND q~tabname = p~tabname
+ AND q~func = p~func
+ AND q~variant = p~variant
+ WHERE p~applclass = 'KE'
+ AND p~subclass = '02'
+ AND p~tabname = @l_tabname
+ AND p~func = 'GITD'
+ INTO CORRESPONDING FIELDS OF TABLE @result
+ .
+
+ IF sy-subrc <> 0.
+ RAISE select_err.
+ ENDIF.
+ ENDMETHOD.
+
+
+ METHOD map_document_data.
+ DATA : l_currency_value TYPE bapicurr_d.
+
+
+ FIELD-SYMBOLS: TYPE any, TYPE any, TYPE any.
+
+
+
+
+
+ LOOP AT it_source ASSIGNING .
+ ASSIGN COMPONENT 'REC_WAERS' OF STRUCTURE TO .
+ APPEND VALUE #(
+ record_id = cv_index
+ fieldname = 'VRGAR'
+ value = iv_vrgar
+ ) TO ct_inputdata.
+
+ LOOP AT it_catalog INTO DATA(ls_catalog).
+ ASSIGN COMPONENT ls_catalog-fieldname OF STRUCTURE TO .
+ IF sy-subrc = 0.
+ IF ls_catalog-inttype IS NOT INITIAL. "값필드 인 경우.
+ " 통화키를 적용하여, 금액을 형변환 시켜야 함.
+ CLEAR : l_currency_value.
+ CALL FUNCTION 'BAPI_CURRENCY_CONV_TO_EXTERNAL'
+ EXPORTING
+ currency =
+ amount_internal =
+ IMPORTING
+ amount_external = l_currency_value.
+
+ APPEND VALUE #(
+ record_id = cv_index
+ fieldname = ls_catalog-fieldname
+* value = COND #( WHEN iv_reverse = abap_true THEN * -1 ELSE )
+ value = COND #( WHEN iv_reverse = abap_true THEN l_currency_value * -1 ELSE l_currency_value )
+ currency =
+ ) TO ct_inputdata.
+ ELSE.
+ CASE ls_catalog-fieldname.
+ WHEN 'VARIANT'.
+ APPEND VALUE #(
+ record_id = cv_index
+ fieldname = 'BELNR_SENDER'
+ value =
+ ) TO ct_inputdata.
+ WHEN 'DIST_ID'.
+ APPEND VALUE #(
+ record_id = cv_index
+ fieldname = 'POSNR_SENDER'
+ value = substring( val = off = strlen( ) - 6 len = 6 )
+ ) TO ct_inputdata.
+ WHEN 'BUDAT'.
+ APPEND VALUE #(
+ record_id = cv_index
+ fieldname = 'BUDAT'
+ value = iv_budat
+ ) TO ct_inputdata.
+ WHEN OTHERS.
+ APPEND VALUE #(
+ record_id = cv_index
+ fieldname = ls_catalog-fieldname
+ value =
+ ) TO ct_inputdata.
+ ENDCASE.
+ ENDIF.
+ ENDIF.
+ ENDLOOP.
+ cv_index = cv_index + 1.
+ ENDLOOP.
+
+ ENDMETHOD.
+
+
+METHOD post_actual_topdown_documents.
+
+ CONSTANTS: c_index_init TYPE rke_record_id VALUE '000001'.
+
+ DATA: lt_inputdata TYPE TABLE OF bapi_copa_data,
+ lt_fieldlist TYPE TABLE OF bapi_copa_field,
+ ls_return TYPE bapiret2,
+ lv_index TYPE rke_record_id VALUE c_index_init.
+
+ DATA: lt_catalog TYPE tt_dfies,
+ lr_sender TYPE REF TO data,
+ lr_result TYPE REF TO data.
+
+ DATA: l_waers TYPE rke_rec_waers,
+ lv_exists TYPE abap_bool.
+
+ DATA : lv_first_day TYPE sy-datum, "전기일자를 위한 기간/년도의 1일
+ lv_budat TYPE sy-datum. "전기일자
+
+ FIELD-SYMBOLS: TYPE ANY TABLE,
+ TYPE any,
+ TYPE ANY TABLE,
+ TYPE any.
+
+ " 필수 파라미터 점검
+ IF erkrs IS INITIAL OR perio IS INITIAL OR variant IS INITIAL OR vrgar IS INITIAL.
+ gv_message = TEXT-012.
+ ls_return = VALUE #( type = 'E' id = 'FAIL' number = '012' message = gv_message ).
+ APPEND ls_return TO result.
+ RETURN.
+ ENDIF.
+
+ " 레코드 유형 점검 (EXISTS 쿼리)
+ SELECT SINGLE @abap_true FROM tvga WHERE vrgar = @vrgar INTO @lv_exists.
+ IF lv_exists = abap_false.
+ gv_message = TEXT-021.
+ ls_return = VALUE #( type = 'E' id = 'FAIL' number = '021' message = gv_message ).
+ APPEND ls_return TO result.
+ RETURN.
+ ENDIF.
+
+ " 전표 발행 상태 체크
+ CLEAR : lv_exists.
+ SELECT SINGLE post FROM (gv_variant)
+ WHERE perio = @perio AND variant = @variant
+ INTO @lv_exists .
+
+ IF sy-subrc NE 0.
+ gv_message = TEXT-007.
+ ls_return = VALUE #( type = 'E' id = 'FAIL' number = '007' message = gv_message ).
+ APPEND ls_return TO result.
+ RETURN.
+ ELSEIF lv_exists = 'X'.
+ gv_message = TEXT-018.
+ ls_return = VALUE #( type = 'E' id = 'FAIL' number = '018' message = gv_message ).
+ APPEND ls_return TO result.
+ RETURN.
+ ENDIF.
+
+ " 1. 동적 테이블 생성 및 할당
+ CREATE DATA lr_sender TYPE TABLE OF (gv_sender).
+ ASSIGN lr_sender->* TO .
+ CREATE DATA lr_result TYPE TABLE OF (gv_result).
+ ASSIGN lr_result->* TO .
+
+ " 2. 필드 카탈로그 가져오기
+ CALL METHOD me->get_field_catalog
+ EXPORTING
+ erkrs = erkrs
+ perio = perio
+ variant = variant
+ IMPORTING
+ fieldcatalog = lt_catalog
+ RECEIVING
+ result = ls_return.
+
+ IF ls_return-type = 'E'.
+ APPEND ls_return TO result.
+ RETURN.
+ ENDIF.
+
+ DELETE lt_catalog WHERE fieldname = 'SEQ' OR inttype = 'T'.
+
+ "전표 발행을 위한 전기일 필드 추가.
+ APPEND VALUE #( tabname = 'RECEIVER' fieldname = 'BUDAT' position = '0000') TO lt_catalog.
+
+ "전기일자는 기간/년월의 마지막 일자
+ CONCATENATE perio(4) perio+5(2) '01' INTO lv_first_day.
+
+ CALL FUNCTION 'RP_LAST_DAY_OF_MONTHS'
+ EXPORTING
+ day_in = lv_first_day
+ IMPORTING
+ last_day_of_month = lv_budat.
+ IF sy-subrc <> 0.
+* Implement suitable error handling here
+ ENDIF.
+
+ " 3. 필드리스트 생성(PA 전표 생성 BAPI용 필드리스트)
+ CALL METHOD me->build_fieldlist
+ EXPORTING
+ it_catalog = lt_catalog
+ CHANGING
+ ct_fieldlist = lt_fieldlist.
+
+ " 4. 센더 데이터 조회
+ SELECT *
+ FROM (gv_sender)
+ WHERE variant = @variant
+ AND perio = @perio
+ INTO TABLE @.
+
+ " 5. 입력 데이터 매핑 (private 메소드 활용)
+ CALL METHOD me->map_document_data
+ EXPORTING
+ it_source =
+ it_catalog = lt_catalog
+ iv_vrgar = vrgar
+ iv_reverse = abap_true
+ iv_budat = lv_budat
+ CHANGING
+ ct_inputdata = lt_inputdata
+ cv_index = lv_index.
+
+ " 6. 리시버 데이터 조회
+ SELECT *
+ FROM (gv_result)
+ WHERE variant = @variant
+ AND perio = @perio
+ INTO TABLE @.
+
+ " 7. 리시버 입력 데이터 매핑
+ CALL METHOD me->map_document_data
+ EXPORTING
+ it_source =
+ it_catalog = lt_catalog
+ iv_vrgar = vrgar
+ iv_reverse = abap_false
+ iv_budat = lv_budat
+ CHANGING
+ ct_inputdata = lt_inputdata
+ cv_index = lv_index.
+
+ " 8. 불필요 필드 제거
+ DELETE lt_fieldlist WHERE fieldname = 'VARIANT' OR fieldname = 'DIST_ID'.
+
+ " 9. BAPI 호출
+ CALL FUNCTION 'BAPI_COPAACTUALS_POSTCOSTDATA'
+ EXPORTING
+ operatingconcern = erkrs
+ testrun = testrun
+ TABLES
+ inputdata = lt_inputdata
+ fieldlist = lt_fieldlist
+ return = result.
+
+ " 10. 결과 처리
+ LOOP AT result INTO DATA(ls_bapi_result) WHERE type CA 'EA'.
+ WRITE: / '오류:', ls_bapi_result-message.
+ RETURN.
+ ENDLOOP.
+
+ IF sy-subrc <> 0 AND testrun = space.
+ UPDATE (gv_variant)
+ SET post = 'X'
+ WHERE perio = @perio AND variant = @variant.
+
+ CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
+ EXPORTING
+ wait = 'X'.
+ ENDIF.
+
+ENDMETHOD.
+
+
+ METHOD set_audit_fields.
+ cs_data-cdate = sy-datum.
+ cs_data-ctime = sy-uzeit.
+ cs_data-cname = sy-uname.
+ cs_data-udate = sy-datum.
+ cs_data-utime = sy-uzeit.
+ cs_data-uname = sy-uname.
+ ENDMETHOD.
+
+
+ METHOD set_info.
+ working_info-perio = perio.
+ working_info-variant = variant.
+ ENDMETHOD.
+
+
+ METHOD set_source_info.
+
+ IF erkrs IS INITIAL .
+ gv_message = TEXT-012.
+ MESSAGE gv_message TYPE 'E'.
+ ENDIF.
+
+ gv_source = |CE1{ erkrs }|.
+
+ source_struct_desc ?= cl_abap_typedescr=>describe_by_name( gv_source ).
+ " 버퍼 테이블 생성
+ DATA(lo_source_type) = cl_abap_tabledescr=>create(
+ p_line_type = source_struct_desc
+ p_table_kind = cl_abap_tabledescr=>tablekind_std
+ ).
+ CREATE DATA source_table TYPE HANDLE lo_source_type.
+
+
+ IF sy-subrc NE 0.
+ " 오류 메시지 추가
+ gv_message = TEXT-022.
+ result = VALUE #(
+ type = 'E'
+ id = 'FAIL'
+ number = '022'
+ message = gv_message ).
+ RETURN.
+ ELSE.
+ " 성공 메시지 추가
+ gv_message = TEXT-013.
+ result = VALUE #(
+ type = 'S'
+ id = 'SUCCESS'
+ number = '013'
+ message = gv_message ).
+ ENDIF.
+
+
+
+ ENDMETHOD.
+
+
+METHOD set_variant_desc.
+
+ DATA: lt_bpsel TYPE kepp_t_sel1,
+ et_bpsel TYPE kepp_s_bpsel,
+ ls_distinfo TYPE ty_distinfo,
+ lt_distinfo TYPE TABLE OF ty_distinfo,
+ lt_distrule TYPE SORTED TABLE OF ty_distrule
+ WITH UNIQUE KEY erkrs applclass subclass tabname func variant sort fnam sign optionn low,
+ ls_covad TYPE covad,
+ lt_fnam TYPE kepp_t_fnam,
+ ans TYPE c LENGTH 8.
+
+ " 1. 변형 정보 조회
+ CALL METHOD me->get_variant_info
+ EXPORTING
+ erkrs = erkrs
+ variant = variant
+ IMPORTING
+ covad = ls_covad.
+
+ IF ls_covad IS INITIAL.
+ gv_message = TEXT-003.
+ MESSAGE gv_message TYPE 'E'.
+ ENDIF.
+
+ " 2. 표준 변형 세팅 정보(KE28)
+ CALL FUNCTION 'RKE_BP_VARIANT_READ_DIRECT'
+ EXPORTING
+ i_applclass = ls_covad-applclass
+ i_subclass = ls_covad-subclass
+ i_tabname = ls_covad-tabname
+ i_func = ls_covad-func
+ i_variant = variant
+ IMPORTING
+ es_bpsel = et_bpsel
+ TABLES
+ et_fnam = lt_fnam
+ EXCEPTIONS
+ not_found = 1
+ OTHERS = 2.
+ IF sy-subrc <> 0.
+ " 적절한 에러 처리 필요
+ RETURN.
+ ENDIF.
+
+ lt_bpsel[] = et_bpsel-t_sel1[].
+
+ " 3. 등록된 CBO 조건 데이터 정보 (Standard 조건보다 우선)
+ SELECT *
+ FROM (gv_distrule)
+ WHERE erkrs = @erkrs
+ AND perfrom <= @perio
+ AND perto >= @perio
+ AND variant = @variant
+ INTO CORRESPONDING FIELDS OF TABLE @lt_distrule.
+
+ " 4. 배부 기준 정보 중복 여부 확인 및 사용자 확인
+ SELECT 1
+ FROM (gv_distinfo)
+ WHERE erkrs = @erkrs
+ AND perio = @perio
+ AND variant = @variant
+ INTO TABLE @DATA(l_chk)
+ UP TO 1 ROWS.
+
+ IF l_chk IS NOT INITIAL.
+ CALL FUNCTION 'POPUP_TO_CONFIRM'
+ EXPORTING
+ titlebar = 'Title POPUP_TO_CONFIRM'
+ text_question = TEXT-006
+ text_button_1 = 'OK'
+ icon_button_1 = 'ICON_CHECKED'
+ text_button_2 = 'NO'
+ icon_button_2 = 'ICON_NO'
+ display_cancel_button = ' '
+ popup_type = 'ICON_MESSAGE_ERROR'
+ IMPORTING
+ answer = ans.
+
+ IF ans = 2.
+ RETURN.
+ ENDIF.
+ ENDIF.
+
+ " 5. 배부 기준 정보 저장 (CBO 우선, 없으면 표준)
+ LOOP AT lt_bpsel INTO DATA(ls_data).
+ READ TABLE lt_distrule WITH KEY
+ erkrs = erkrs
+ applclass = ls_covad-applclass
+ subclass = ls_covad-subclass
+ tabname = ls_covad-tabname
+ func = ls_covad-func
+ variant = ls_covad-variant
+ sort = ls_data-sort
+ fnam = ls_data-fnam
+ TRANSPORTING NO FIELDS
+ BINARY SEARCH.
+
+ IF sy-subrc = 0.
+ LOOP AT lt_distrule INTO DATA(ls_cbo_rule) WHERE erkrs = erkrs
+ AND applclass = ls_covad-applclass
+ AND subclass = ls_covad-subclass
+ AND tabname = ls_covad-tabname
+ AND func = ls_covad-func
+ AND variant = ls_covad-variant
+ AND sort = ls_data-sort
+ AND fnam = ls_data-fnam.
+ MOVE-CORRESPONDING ls_cbo_rule TO ls_distinfo.
+ me->set_audit_fields( CHANGING cs_data = ls_distinfo ).
+ APPEND ls_distinfo TO lt_distinfo.
+ ENDLOOP.
+ ELSE.
+ MOVE-CORRESPONDING ls_data TO ls_distinfo.
+ ls_distinfo-erkrs = erkrs.
+ ls_distinfo-perio = perio.
+ ls_distinfo-applclass = ls_covad-applclass.
+ ls_distinfo-subclass = ls_covad-subclass.
+ ls_distinfo-tabname = ls_covad-tabname.
+ ls_distinfo-func = ls_covad-func.
+ ls_distinfo-variant = ls_covad-variant.
+ ls_distinfo-optionn = ls_data-option.
+
+ IF ls_distinfo-fnam EQ 'BPERIO'
+ OR ls_distinfo-fnam EQ 'REBPERIO'
+ OR ls_distinfo-fnam EQ 'REVPERIO'
+ OR ls_distinfo-fnam EQ 'VPERIO'.
+ ls_distinfo-low = perio.
+ ENDIF.
+ ENDIF.
+
+ me->set_audit_fields( CHANGING cs_data = ls_distinfo ).
+ APPEND ls_distinfo TO lt_distinfo.
+ ENDLOOP.
+
+ " 6. 기존 데이터 삭제 후 신규 데이터 저장
+ DELETE FROM (gv_distinfo) WHERE erkrs = @erkrs
+ AND perio = @perio
+ AND variant = @variant.
+
+ MODIFY (gv_distinfo) FROM TABLE lt_distinfo.
+
+ " 7. 결과 처리
+ IF sy-subrc = 0.
+ COMMIT WORK.
+ gv_message = TEXT-004.
+ MESSAGE gv_message TYPE 'S'.
+ ELSE.
+ ROLLBACK WORK.
+ gv_message = TEXT-005.
+ MESSAGE gv_message TYPE 'E'.
+ ENDIF.
+
+ENDMETHOD.
+ENDCLASS.