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.