이번엔 엑셀업로드로 PO 만드는 샘플입니다.
PO만다는 소스는 너무나도 많죠~
각 프로젝트마다 조금씩 요구사항이 추가로 있어서 약간의 기능이 추가된다고 보면 됩니다.
주석은 최대한 달아 놓았으니 참조하시면 됩니다.
실행화면입니다.
엑셀업로드 플랫릿입니다.
이번엔 필드가 좀 많죠~;; 자세한건 소스를 등록할테니..참조하세요
이제 코딩 들어갑니다.
*&---------------------------------------------------------------------*
*& Report ZMMC2000
*&---------------------------------------------------------------------*
REPORT zmmc2000g MESSAGE-ID zmm1. " 프로그램 이름(zmmc2000g)과 사용할 메시지 클래스(zmm1)를 선언
*-----------------------------------------------------------------------
* INCLUDE (소스코드 모듈화)
*-----------------------------------------------------------------------
INCLUDE zmmc2000g_top. " 전역 변수 선언
INCLUDE zmmc2000g_wrd. " 작업 영역(Work Area) 선언
INCLUDE zmmc2000g_f01. " 서브루틴(FORM) 모음
INCLUDE zmmc2000g_o01. " 화면 출력(PBO) 로직
INCLUDE zmmc2000g_i01. " 화면 입력(PAI) 로직
*-----------------------------------------------------------------------
* INITIALIZATION (프로그램 최초 실행 시)
*-----------------------------------------------------------------------
INITIALIZATION.
PERFORM init. " 변수 및 화면 필드 초기화
*-----------------------------------------------------------------------
* AT SELECTION-SCREEN ON VALUE-REQUEST (F4 키 입력 시)
*-----------------------------------------------------------------------
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_path.
PERFORM f4_filename. " 파일 경로(p_path)에 대한 파일 선택창 호출
*-----------------------------------------------------------------------
* AT SELECTION-SCREEN (화면 값 입력 후)
*-----------------------------------------------------------------------
AT SELECTION-SCREEN.
PERFORM user_command_1000. " 화면 입력값 유효성 검증
*-----------------------------------------------------------------------
* START-OF-SELECTION (메인 로직 실행)
*-----------------------------------------------------------------------
START-OF-SELECTION.
" 파일 경로가 비어있는지 체크
IF p_path IS INITIAL.
MESSAGE s001(zmm1) DISPLAY LIKE 'E'
WITH 'Please select the file you want to upload.'.
RETURN.
ENDIF.
PERFORM get_data. " 파일 데이터 읽기 및 가공
*-----------------------------------------------------------------------
* END-OF-SELECTION (결과 출력)
*-----------------------------------------------------------------------
END-OF-SELECTION.
CALL SCREEN 100. " 처리 결과를 100번 화면에 표시
선언 (TOP) 인클루드 파일
*&---------------------------------------------------------------------*
*& Include ZMMC2000_TOP
*&---------------------------------------------------------------------*
*----------------------------------------------------------------------*
* TABLES: ABAP Dictionary 테이블의 Work Area 선언 (구식 선언 방식)
*----------------------------------------------------------------------*
TABLES: sscrfields, "선택 화면 제어용 구조체
ekko. "구매 오더 헤더
*----------------------------------------------------------------------*
* DATA: 변수, 구조체(Work Area), 인터널 테이블 선언
*----------------------------------------------------------------------*
"== 변수 선언 =========================================================
DATA: gv_functxt TYPE smp_dyntxt. "선택 화면 버튼 텍스트용 변수
"== 구조체(Work Area) 선언 ============================================
" 1. 엑셀 업로드 데이터를 담는 구조체
DATA: BEGIN OF gs_data,
ebeln LIKE ekko-ebeln, "Old 구매문서 번호
ebelp LIKE ekpo-ebelp, "Old 구매문서 품목
lifnr_ECC LIKE ekko-lifnr, "공급처_ECC
lifnr LIKE ekko-lifnr, "공급처
bedat LIKE ekko-bedat, "문서일
zterm LIKE ekko-zterm, "지급조건
inco1 LIKE ekko-inco1, "인코텀스1
inco2 LIKE ekko-inco2, "인코텀스2
wkurs LIKE ekko-wkurs, "환율
ekgrp_ECC LIKE ekko-ekgrp, "구매그룹_ECC
ekgrp LIKE ekko-ekgrp, "구매그룹
waers_ECC LIKE ekko-waers, "통화_ECC
waers LIKE ekko-waers, "통화
knttp LIKE ekpo-knttp, "계정지정범주
pstyp LIKE ekpo-pstyp, "품목범주
matnr_ECC LIKE ekpo-matnr, "자재_ECC
matnr LIKE ekpo-matnr, "자재
matkl LIKE ekpo-matkl, "자재그룹
txz01 LIKE ekpo-txz01, "품목내역
menge(17), "수량
meins LIKE ekpo-meins, "단위
netpr(17), "단가
peinh LIKE ekpo-peinh, "가격단위
zta1 LIKE konp-kbetr, "관세
zfr1 LIKE konp-kbetr, "운임
zfr2 LIKE konp-kbetr, "기타비용1
zfr9 LIKE konp-kbetr, "기타비용2
werks_ECC LIKE ekpo-werks, "플랜트_ECC
werks LIKE ekpo-werks, "플랜트
lgort LIKE ekpo-lgort, "저장위치
mwskz LIKE ekpo-mwskz, "세금코드
xersy LIKE ekpo-xersy, "ERS(대금 자동 정산)
insmk LIKE ekpo-insmk, "재고유형
webre LIKE ekpo-webre, "입고기준 송장처리
repos LIKE ekpo-repos, "송장수령
bstae LIKE ekpo-bstae, "납품확인제어키
eindt LIKE eket-eindt, "납품일
sakto LIKE ekkn-sakto, "G/L 계정
kostl_ECC LIKE ekkn-kostl, "코스트센터_ECC
kostl LIKE ekkn-kostl, "코스트센터
anln1 LIKE ekkn-anln1, "자산번호
aufnr LIKE ekkn-aufnr, "오더번호
ablad LIKE ekkn-ablad, "하역 지점
retpo LIKE ekpo-retpo, "반품 품목
uebto LIKE ekpo-uebto, "납품초과 허용 한도
untto LIKE ekpo-untto, "납품미달 허용 한도
END OF gs_data.
" 2. 데이터 처리 중간 단계용 구조체 (gs_data 와 유사)
DATA: BEGIN OF gs_data2.
INCLUDE STRUCTURE gs_data AS data2 RENAMING WITH SUFFIX _2.
END OF gs_data2.
" 3. ALV 결과 표시용 구조체
DATA: BEGIN OF gs_itab,
icon LIKE icon-id, "상태 아이콘
message(220), "처리 메시지
pokey LIKE zmmt0751-pokey, "PO Key (헤더-품목 조합)
ebeln_new LIKE ekko-ebeln, "New 구매문서 번호
ebelp_new LIKE ekpo-ebelp, "New 구매문서 품목
END OF gs_itab.
" gs_itab 구조체에 gs_data 구조체를 포함시켜 필드 확장
DATA: BEGIN OF gs_itab_final.
INCLUDE STRUCTURE gs_itab.
INCLUDE STRUCTURE gs_data.
END OF gs_itab_final.
" 4. 로그 메시지 저장용 구조체
DATA: BEGIN OF gs_log,
pokey LIKE zmmt0751-pokey,
icon LIKE icon-id,
message(220),
END OF gs_log.
"== 인터널 테이블 선언 =================================================
DATA: gt_data LIKE TABLE OF gs_data, "업로드 데이터 저장 테이블
gt_data2 LIKE TABLE OF gs_data2, "중간 데이터 저장 테이블
gt_itab LIKE TABLE OF gs_itab_final, "최종 결과 표시용 테이블
gt_log LIKE TABLE OF gs_log, "로그 메시지 저장 테이블
gt_result LIKE zmmt0751, "PO 생성 결과 저장 테이블
gt_code LIKE zmig_mm_code OCCURS 0 WITH HEADER LINE. "코드 변환 정보 테이블
*----------------------------------------------------------------------*
* ALV (ABAP List Viewer) 관련 객체 및 데이터 선언
* 화면에 데이터를 그리드 형태로 보여주기 위해 사용
*----------------------------------------------------------------------*
TYPE-POOLS: kkblo. "ALV에서 사용하는 타입 그룹
"== ALV 공통 변수 =====================================================
DATA: gs_stbl TYPE lvc_s_stbl, "ALV 안정성 옵션
gt_excluding TYPE ui_functions. "ALV 툴바 제외 버튼 리스트
"== ALV 1 (메인 그리드) ===============================================
CLASS lcl_event_receiver DEFINITION DEFERRED.
DATA: grid TYPE REF TO cl_gui_alv_grid, "ALV 그리드 객체
g_custom_container TYPE REF TO cl_gui_custom_container, "화면의 컨테이너 객체
event_receiver TYPE REF TO lcl_event_receiver, "ALV 이벤트 핸들러 클래스
gs_layout TYPE lvc_s_layo, "ALV 레이아웃
gt_fieldcat TYPE lvc_t_fcat, "필드 카탈로그 (컬럼 정의)
gt_sort TYPE lvc_t_sort, "정렬 기준
gs_variant TYPE disvariant, "ALV 레이아웃 Variant
gt_styl TYPE lvc_t_styl. "셀 스타일 테이블
"== ALV 2 (로그 또는 상세 정보 그리드) =================================
CLASS lcl_event_receiver2 DEFINITION DEFERRED.
DATA: grid2 TYPE REF TO cl_gui_alv_grid,
g_custom_container2 TYPE REF TO cl_gui_custom_container,
event_receiver2 TYPE REF TO lcl_event_receiver2,
gs_layout2 TYPE lvc_s_layo,
gt_fieldcat2 TYPE lvc_t_fcat,
gt_sort2 TYPE lvc_t_sort,
gs_variant2 TYPE disvariant.
"== 화면 분할(Splitter) 및 여러 ALV 동시 사용을 위한 변수 ==============
DATA: g_splitter TYPE REF TO cl_gui_splitter_container, "화면 분할 객체
g_container TYPE REF TO cl_gui_container, "분할된 상위 컨테이너
g_container2 TYPE REF TO cl_gui_container. "분할된 하위 컨테이너
*----------------------------------------------------------------------*
* CLASS DEFINITION: ALV 이벤트 처리를 위한 로컬 클래스 정의
*----------------------------------------------------------------------*
"== ALV 1 이벤트 핸들러 클래스 정의 ===================================
CLASS lcl_event_receiver DEFINITION.
PUBLIC SECTION.
METHODS:
"더블 클릭 이벤트 처리
handle_double_click FOR EVENT double_click OF cl_gui_alv_grid
IMPORTING e_row e_column es_row_no,
"툴바 버튼 이벤트 처리
handle_toolbar FOR EVENT toolbar OF cl_gui_alv_grid
IMPORTING e_object e_interactive,
"사용자 정의 버튼(ucomm) 이벤트 처리
handle_user_command FOR EVENT user_command OF cl_gui_alv_grid
IMPORTING e_ucomm,
"핫스팟 클릭 이벤트 처리
handle_hotspot_click FOR EVENT hotspot_click OF cl_gui_alv_grid
IMPORTING e_row_id e_column_id es_row_no.
ENDCLASS.
"== ALV 2 이벤트 핸들러 클래스 정의 ===================================
CLASS lcl_event_receiver2 DEFINITION.
PUBLIC SECTION.
METHODS:
"더블 클릭 이벤트 처리
handle_double_click FOR EVENT double_click OF cl_gui_alv_grid
IMPORTING e_row e_column es_row_no.
ENDCLASS.
*----------------------------------------------------------------------*
* CLASS IMPLEMENTATION: 로컬 클래스의 메서드 구현
*----------------------------------------------------------------------*
"== ALV 1 이벤트 핸들러 클래스 구현 ===================================
CLASS lcl_event_receiver IMPLEMENTATION.
METHOD handle_double_click.
" 실제 로직은 서브루틴에서 처리 (주석 처리됨)
" PERFORM handle_double_click USING e_row e_column es_row_no.
ENDMETHOD.
METHOD handle_toolbar.
" PERFORM set_toolbar USING e_object.
ENDMETHOD.
METHOD handle_user_command.
" PERFORM handle_user_command USING e_ucomm.
ENDMETHOD.
METHOD handle_hotspot_click.
PERFORM hotspot_click USING e_row_id e_column_id.
ENDMETHOD.
ENDCLASS.
"== ALV 2 이벤트 핸들러 클래스 구현 ===================================
CLASS lcl_event_receiver2 IMPLEMENTATION.
METHOD handle_double_click.
" PERFORM handle_double_click2 USING e_row e_column es_row_no.
ENDMETHOD.
ENDCLASS.
*----------------------------------------------------------------------*
* SELECTION-SCREEN: 사용자에게 값을 입력받는 화면 정의
*----------------------------------------------------------------------*
SELECTION-SCREEN: FUNCTION KEY 1. "어플리케이션 툴바에 버튼 추가
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-t01. "입력 블록 시작
SELECT-OPTIONS: s_ekorg FOR ekko-ekorg NO INTERVALS. "구매조직 (범위 입력 없이 단일 값만)
PARAMETERS: p_path TYPE rlgrap-filename. "업로드할 파일 경로
SELECTION-SCREEN SKIP. "한 줄 띄움
PARAMETERS: p_test AS CHECKBOX. "테스트 실행 체크박스
SELECTION-SCREEN SKIP. "한 줄 띄움
PARAMETERS: p_code AS CHECKBOX DEFAULT 'X'. "코드 변환 실행 체크박스 (기본값 체크)
PARAMETERS: p_chk AS CHECKBOX. "기타 확인용 체크박스
SELECTION-SCREEN END OF BLOCK b1. "입력 블록 끝
ZMMC2000G_WRD.( 엑셀컨드롤)
*&---------------------------------------------------------------------*
*& Include ZMMC2000G_WRD
*& MS Word OLE 자동화 관련 데이터 선언 및 서브루틴
*&---------------------------------------------------------------------*
INCLUDE <CTLDEF>. "OLE 자동화 제어에 필요한 기본 Include
INCLUDE OFFICEINTEGRATIONINCLUDE. "SAP Office 통합 기능 Include
*----------------------------------------------------------------------*
* OLE 통신에 필요한 데이터 타입 및 전역 변수 선언
*----------------------------------------------------------------------*
"Word로 전달할 테이블 매핑 정보 타입 (Word 필드명 <-> ABAP 테이블명)
TYPES: BEGIN OF OLEWORD_TAB,
OLENM(20) TYPE C, "Word 문서 내에서 사용할 이름
TBLNM(20) TYPE C, "ABAP 프로그램의 인터널 테이블 이름
END OF OLEWORD_TAB.
"OLE 제어용 객체 및 변수
DATA: FACTORY TYPE REF TO I_OI_DOCUMENT_FACTORY, "OLE 문서 생성/관리 팩토리 객체
DOCUMENT TYPE REF TO I_OI_DOCUMENT_PROXY, "실제 Word 문서 제어용 프록시 객체
LINK_SERVER TYPE REF TO I_OI_LINK_SERVER, "ABAP 데이터와 문서 연결용 서버 객체
RETCODE TYPE T_OI_RET_STRING, "OLE 호출 결과 코드
DOC_TABLE LIKE W3MIME OCCURS 0, "Word 문서 바이너리 데이터 테이블
DOC_SIZE TYPE I, "Word 문서 크기
IS_CLOSED TYPE I, "문서 종료 여부 플래그
DOC_TYPE(80) TYPE C VALUE SOI_DOCTYPE_WORD97_DOCUMENT, "문서 타입 (Word 97)
OLE_ITAB TYPE OLEWORD_TAB OCCURS 0 WITH HEADER LINE. "테이블 매핑 정보 저장용
*&--------------------------------------------------------------------*
*& FORM INIT_WORDOLE: MS Word OLE 통신 초기화
*&--------------------------------------------------------------------*
FORM INIT_WORDOLE USING P_OLE_NAME.
"팩토리 객체가 생성되지 않았을 경우에만 초기화 수행
IF FACTORY IS INITIAL.
"1. OLE 팩토리 생성
CALL METHOD C_OI_FACTORY_CREATOR=>GET_DOCUMENT_FACTORY
IMPORTING
FACTORY = FACTORY
RETCODE = RETCODE.
IF RETCODE <> C_OI_ERRORS=>RET_OK. EXIT. ENDIF.
"2. 팩토리 시작
CALL METHOD FACTORY->START_FACTORY
EXPORTING
R3_APPLICATION_NAME = P_OLE_NAME
IMPORTING
RETCODE = RETCODE.
CALL METHOD C_OI_ERRORS=>SHOW_MESSAGE EXPORTING TYPE = 'E'.
"3. 데이터 연결을 위한 링크 서버 생성
CALL METHOD FACTORY->GET_LINK_SERVER
IMPORTING
LINK_SERVER = LINK_SERVER
RETCODE = RETCODE.
CALL METHOD C_OI_ERRORS=>SHOW_MESSAGE EXPORTING TYPE = 'E'.
"4. 링크 서버 시작
CALL METHOD LINK_SERVER->START_LINK_SERVER
IMPORTING
RETCODE = RETCODE.
ENDIF.
ENDFORM. "INIT_WORDOLE
*&--------------------------------------------------------------------*
*& FORM APPEND_WORDOLE: Word로 전달할 ABAP 인터널 테이블 정보 추가
*&--------------------------------------------------------------------*
FORM APPEND_WORDOLE USING P_INIT P_OLETABLE_NAME P_TABLE_NAME.
DATA LT_TAB TYPE OLEWORD_TAB.
"초기화 플래그('X')가 넘어오면 매핑 테이블 초기화
IF P_INIT = 'X'.
REFRESH OLE_ITAB.
CLEAR OLE_ITAB.
ENDIF.
"Word 필드명과 ABAP 테이블명을 구조체에 담아 매핑 테이블에 추가
LT_TAB-OLENM = P_OLETABLE_NAME.
LT_TAB-TBLNM = P_TABLE_NAME.
APPEND LT_TAB TO OLE_ITAB.
ENDFORM. "APPEND_WORDOLE
*&--------------------------------------------------------------------*
*& FORM SHOW_WORDOLE: Word 문서 열고 데이터 전송 및 매크로 실행
*&--------------------------------------------------------------------*
FORM SHOW_WORDOLE USING P_OBJ_ID P_MACRO.
PERFORM LINK_SERVER. "1. ABAP 인터널 테이블 데이터를 Word와 연결
PERFORM OPEN_DOC USING P_OBJ_ID. "2. SAP 서버에서 Word 템플릿 파일 열기
CHECK NOT P_MACRO IS INITIAL.
PERFORM WORD_MACRO USING P_MACRO. "3. Word 매크로 실행
ENDFORM. "SHOW_WORDOLE
*&--------------------------------------------------------------------*
*& FORM LINK_SERVER: OLE_ITAB의 정보를 기반으로 ABAP 테이블과 Word 연결
*&--------------------------------------------------------------------*
FORM LINK_SERVER.
FIELD-SYMBOLS: <TABLE> TYPE STANDARD TABLE.
DATA L_ITBL_NAME(30) TYPE C.
CHECK NOT LINK_SERVER IS INITIAL.
"매핑 테이블(OLE_ITAB)을 순회하며 각 테이블을 링크 서버에 등록
LOOP AT OLE_ITAB.
"동적으로 인터널 테이블 할당 (예: 'GT_DATA' -> GT_DATA[])
CONCATENATE OLE_ITAB-TBLNM '[]' INTO L_ITBL_NAME.
ASSIGN (L_ITBL_NAME) TO <TABLE>.
"링크 서버에 데이터 테이블 추가
CALL METHOD LINK_SERVER->ADD_TABLE_ITEM2
EXPORTING
ITEM_NAME = OLE_ITAB-OLENM
IMPORTING
RETCODE = RETCODE
CHANGING
DATA_TABLE = <TABLE>.
CALL METHOD C_OI_ERRORS=>SHOW_MESSAGE EXPORTING TYPE = 'E'.
ENDLOOP.
ENDFORM. "LINK_SERVER
*&--------------------------------------------------------------------*
*& FORM OPEN_DOC: SAP MIME Repository에서 Word 템플릿 문서 열기
*&--------------------------------------------------------------------*
FORM OPEN_DOC USING P_OPEN_ID.
"1. SAP MIME 저장소에서 Object ID를 이용해 Word 문서 데이터를 읽어옴
CALL FUNCTION 'SAP_OI_LOAD_MIME_DATA'
EXPORTING
OBJECT_ID = P_OPEN_ID
IMPORTING
DATA_SIZE = DOC_SIZE
DOCUMENT_FORMAT = DOC_FORMAT
DOCUMENT_TYPE = DOC_TYPE
TABLES
DATA_TABLE = DOC_TABLE
EXCEPTIONS
OTHERS = 1.
IF SY-SUBRC <> 0.
MESSAGE ID SY-MSGID TYPE 'E' NUMBER SY-MSGNO
WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
ENDIF.
"2. 읽어온 문서 데이터로 Word 문서 열기
IF DOC_SIZE <> 0.
"문서 제어용 프록시 객체 생성
CALL METHOD FACTORY->GET_DOCUMENT_PROXY
EXPORTING
DOCUMENT_TYPE = DOC_TYPE
IMPORTING
DOCUMENT_PROXY = DOCUMENT
RETCODE = RETCODE.
CALL METHOD C_OI_ERRORS=>SHOW_MESSAGE EXPORTING TYPE = 'E'.
"바이너리 테이블 데이터를 이용해 문서 열기
CALL METHOD DOCUMENT->OPEN_DOCUMENT_FROM_TABLE
EXPORTING
DOCUMENT_TABLE = DOC_TABLE[]
DOCUMENT_SIZE = DOC_SIZE
IMPORTING
RETCODE = RETCODE.
CALL METHOD C_OI_ERRORS=>SHOW_MESSAGE EXPORTING TYPE = 'E'.
ELSE.
MESSAGE E016(RP) WITH 'No document has been selected'.
ENDIF.
ENDFORM. "OPEN_DOC
*&--------------------------------------------------------------------*
*& FORM WORD_MACRO: Word 문서 내의 매크로 실행
*&--------------------------------------------------------------------*
FORM WORD_MACRO USING P_MACRO.
CALL METHOD DOCUMENT->EXECUTE_MACRO
EXPORTING
MACRO_STRING = P_MACRO
IMPORTING
RETCODE = RETCODE.
CALL METHOD C_OI_ERRORS=>SHOW_MESSAGE EXPORTING TYPE = 'E'.
ENDFORM. "WORD_MACRO
*&--------------------------------------------------------------------*
*& FORM CLOSE_WORDOLE: Word 문서 닫고 OLE 연결 해제
*&--------------------------------------------------------------------*
FORM CLOSE_WORDOLE.
IF NOT DOCUMENT IS INITIAL.
"문서가 이미 닫혔는지 확인
CALL METHOD DOCUMENT->IS_DESTROYED
IMPORTING
RET_VALUE = IS_CLOSED.
"문서가 열려있으면 저장하며 닫기
IF IS_CLOSED IS INITIAL.
CALL METHOD DOCUMENT->CLOSE_DOCUMENT
EXPORTING
DO_SAVE = 'X'
IMPORTING
RETCODE = RETCODE.
CALL METHOD C_OI_ERRORS=>SHOW_MESSAGE EXPORTING TYPE = 'E'.
ENDIF.
"문서 객체 해제
CALL METHOD DOCUMENT->RELEASE_DOCUMENT
IMPORTING
RETCODE = RETCODE.
CALL METHOD C_OI_ERRORS=>SHOW_MESSAGE EXPORTING TYPE = 'E'.
FREE DOCUMENT.
ENDIF.
ENDFORM. "CLOSE_WORDOLE
ZMMC2000G_I01, ZMMC2000G_O01는 안 올릴려고 했는데..
진짜 별거 없잔잖아요..
그래도 혹시 참조할 분이 있을수도 있어서 등록합니다.
이 Include 파일은 프로그램의 화면(Screen) 100번에서 사용자가 특정 행동을 했을 때(PAI - Process After Input) 실행되는 로직을 담고 있습니다.
- MODULE EXIT_0100 INPUT
- 모든 화면에 공통적으로 들어가는 모듈입니다.
- 사용자가 뒤로가기(F3), 종료(Shift+F3), 취소(F12) 버튼을 누르면 프로그램을 현재 화면을 닫고 이전 화면으로 돌아가는 역할을 합니다.
- MODULE USER_COMMAND_0100 INPUT
- 100번 화면에서 발생하는 사용자 이벤트를 처리합니다.
- 사용자가 'EXEC'라는 기능 코드(아마도 "PO 생성" 버튼에 할당된)를 실행하면, CREATE_PO 라는 서브루틴을 호출하여 실질적인 구매 오더 생성 작업을 시작합니다.
*&---------------------------------------------------------------------*
*& Include ZMMC2000_I01
*& 화면 100번의 PAI (Process After Input) 모듈 정의
*&---------------------------------------------------------------------*
*&---------------------------------------------------------------------*
*& Module EXIT_0100 INPUT: 화면 공통 종료 로직
*&---------------------------------------------------------------------*
MODULE EXIT_0100 INPUT.
CASE SY-UCOMM.
"사용자가 '뒤로가기', '종료', '취소' 버튼을 누를 경우
WHEN 'BACK' OR 'EXIT' OR 'CANC'.
LEAVE TO SCREEN 0. "프로그램을 종료하고 이전 화면(선택 화면)으로 돌아감
ENDCASE.
ENDMODULE.
*&---------------------------------------------------------------------*
*& Module USER_COMMAND_0100 INPUT: 화면 100번의 사용자 명령어 처리
*&---------------------------------------------------------------------*
MODULE USER_COMMAND_0100 INPUT.
CASE SY-UCOMM.
"사용자가 'EXEC'(실행) 버튼을 클릭했을 경우
WHEN 'EXEC'.
PERFORM CREATE_PO. "PO(구매 오더) 생성 로직을 담은 서브루틴 호출
ENDCASE.
ENDMODULE.
이 Include 파일은 프로그램의 100번 화면이 사용자에게 표시되기 전(PBO - Process Before Output)에 실행되는 로직들을 담고 있습니다. 화면의 제목과 버튼을 설정하고, 메인 ALV(ABAP List Viewer) 그리드를 화면에 출력하는 역할을 합니다.
*&---------------------------------------------------------------------*
*& Include ZMMC2000_O01
*& 화면 100번의 PBO (Process Before Output) 모듈 정의
*&---------------------------------------------------------------------*
*&---------------------------------------------------------------------*
*& Module STATUS_0100 OUTPUT: 화면의 GUI 상태 및 제목 설정
*&---------------------------------------------------------------------*
MODULE status_0100 OUTPUT.
SET PF-STATUS '0100'. "화면의 버튼(툴바) 세트를 '0100'으로 지정
SET TITLEBAR '0100'. "화면의 제목을 '0100'으로 지정
ENDMODULE.
*&---------------------------------------------------------------------*
*& Module DISPLAY_ALV OUTPUT: 메인 ALV 그리드 표시
*&---------------------------------------------------------------------*
MODULE display_alv OUTPUT.
"ALV 리프레시 시 스크롤 위치 고정을 위한 설정
gs_stbl-row = 'X'.
gs_stbl-col = 'X'.
"ALV 그리드 객체가 아직 생성되지 않았을 경우 (최초 화면 로드 시)
IF grid IS INITIAL.
PERFORM create_controls. "1. ALV를 표시할 화면의 컨테이너 생성
PERFORM set_event. "2. ALV 이벤트 핸들러 등록 (예: 클릭, 더블클릭)
PERFORM alv_layout. "3. ALV 레이아웃(디자인) 설정
PERFORM exclude_tb_functions. "4. ALV 기본 툴바에서 불필요한 버튼 제외
PERFORM set_variant. "5. ALV 표시 형식(Variant) 설정
PERFORM fieldcat_init. "6. ALV 컬럼(열) 정보 생성 (필드 카탈로그)
"7. 설정된 정보를 바탕으로 ALV 그리드를 처음 화면에 출력
CALL METHOD grid->set_table_for_first_display
EXPORTING
i_save = 'U' "레이아웃 변경은 사용자별로 저장
is_layout = gs_layout
is_variant = gs_variant
it_toolbar_excluding = gt_exclude[]
CHANGING
it_outtab = gt_itab[]
it_sort = gt_sort[]
it_fieldcatalog = gt_fieldcat.
"그리드 객체가 이미 생성된 경우 (화면 REFRESH 시)
ELSE.
"데이터만 새로고침하여 성능 향상
CALL METHOD grid->refresh_table_display
EXPORTING
is_stable = gs_stbl.
ENDIF.
ENDMODULE.
*&---------------------------------------------------------------------*
*& FORM hotspot_click: ALV 핫스팟(링크) 클릭 시 이벤트 처리
*&---------------------------------------------------------------------*
FORM hotspot_click USING e_row TYPE lvc_s_row
e_col TYPE lvc_s_col.
"이 서브루틴은 메인 ALV의 특정 셀을 클릭했을 때,
"해당 행과 관련된 상세 로그를 팝업 ALV로 보여주는 기능을 합니다.
"팝업 ALV 표시에 필요한 지역 변수 선언 (REUSE_ALV 사용)
DATA: lt_fieldcat TYPE slis_t_fieldcat_alv,
ls_fieldcat TYPE slis_fieldcat_alv,
lt_excluding TYPE slis_t_extab,
ls_excluding TYPE slis_extab.
"팝업 ALV의 툴바에서 특정 버튼을 제외하기 위한 매크로
DEFINE __excluding.
ls_excluding-fcode = &1.
APPEND ls_excluding TO lt_excluding.
END-OF-DEFINITION.
"팝업 ALV에 필요 없는 표준 버튼들 제거
__excluding: '&ETA', '&OUP', '&ODN', '%SC', '%SC+', '&ILT', '&OL0', '&NT1'.
"팝업 ALV의 필드 카탈로그(컬럼) 수동 생성
CLEAR ls_fieldcat.
ls_fieldcat-fieldname = 'pokey'.
ls_fieldcat-seltext_s = 'pokey'.
APPEND ls_fieldcat TO lt_fieldcat.
CLEAR ls_fieldcat.
ls_fieldcat-fieldname = 'icon'.
ls_fieldcat-seltext_s = 'icon'.
ls_fieldcat-outputlen = 4.
APPEND ls_fieldcat TO lt_fieldcat.
CLEAR ls_fieldcat.
ls_fieldcat-fieldname = 'message'.
ls_fieldcat-seltext_s = 'message'.
ls_fieldcat-outputlen = 200.
APPEND ls_fieldcat TO lt_fieldcat.
"클릭한 행의 데이터를 읽어옴
DATA gt_log_view LIKE gt_log.
READ TABLE gt_itab INTO DATA(gs_itab) INDEX e_row-index.
"전체 로그(gt_log)에서 클릭한 행의 키(pokey)와 일치하는 로그만 필터링
LOOP AT gt_log INTO DATA(wa) WHERE pokey = gs_itab-pokey.
APPEND wa TO gt_log_view.
ENDLOOP.
"필터링된 로그 데이터를 팝업 ALV로 출력
CALL FUNCTION 'REUSE_ALV_POPUP_TO_SELECT'
EXPORTING
i_title = '오류 목록'
i_zebra = 'X' "줄무늬 표시
i_tabname = 'GS_LOG'
it_fieldcat = lt_fieldcat[]
it_excluding = lt_excluding[]
TABLES
t_outtab = gt_log_view
EXCEPTIONS
OTHERS = 1.
ENDFORM.
이제 핵심이죠~
ZMMC2000_F01
이 Include 파일은 프로그램의 핵심 로직을 담당하는 서브루틴(FORM)들을 모아놓은 곳입니다.
(데이터 처리, ALV 설정, BAPI 호출 등)
CREATE_PO부분만 참고하셔서 사용하면 됩니다.
*&---------------------------------------------------------------------*
*& Include ZMMC2000_F01
*& 프로그램의 메인 로직을 구성하는 서브루틴(FORM) 정의
*&---------------------------------------------------------------------*
*&--------------------------------------------------------------------*
*& FORM init: 선택 화면 초기화
*&--------------------------------------------------------------------*
FORM init.
"선택 화면의 어플리케이션 툴바에 '템플릿 다운로드' 버튼 생성
gv_functxt-quickinfo = 'Template'.
gv_functxt-icon_id = icon_xls.
gv_functxt-icon_text = 'Excel form'.
sscrfields-functxt_01 = gv_functxt.
ENDFORM.
*&--------------------------------------------------------------------*
*& FORM user_command_1000: 선택 화면의 사용자 명령어 처리
*&--------------------------------------------------------------------*
FORM user_command_1000.
CASE sscrfields-ucomm.
WHEN 'FC01'. "사용자가 '템플릿 다운로드' 버튼 클릭 시
PERFORM excel_form_download2.
ENDCASE.
ENDFORM.
*&--------------------------------------------------------------------*
*& FORM excel_form_download2: 엑셀 템플릿 다운로드
*&--------------------------------------------------------------------*
FORM excel_form_download2.
"Web Repository(SMW0)에 저장된 엑셀 템플릿을 사용자 PC로 다운로드합니다.
DATA: lv_dfname LIKE rlgrap-filename,
lv_objid LIKE wwwdata-objid.
lv_dfname = 'PO_telmplate.xlsx'. "다운로드될 파일 이름
lv_objid = 'ZMMC2000G_XLS'. "Web Repository의 Object ID
"Web 템플릿 다운로드 및 실행
CALL FUNCTION 'DOWNLOAD_WEB_OBJECT'
EXPORTING
key = VALUE #( objid = lv_objid )
destination = lv_dfname.
CALL FUNCTION 'WS_EXECUTE'
EXPORTING
commandline = lv_dfname
program = 'EXCEL.EXE'.
ENDFORM.
*&--------------------------------------------------------------------*
*& FORM f4_filename: 파일 경로(p_path) F4 도움말 처리
*&--------------------------------------------------------------------*
FORM f4_filename.
"사용자 PC에서 파일을 선택할 수 있는 대화상자를 띄웁니다.
CALL METHOD cl_gui_frontend_services=>file_open_dialog
EXPORTING
window_title = 'File open'
file_filter = '*.XLSX'
CHANGING
file_table = DATA(lt_files)
rc = DATA(lv_rc).
IF sy-subrc = 0.
READ TABLE lt_files INTO DATA(ls_files) INDEX 1.
p_path = ls_files-filename.
ENDIF.
ENDFORM.
*&--------------------------------------------------------------------*
*& FORM get_data: 메인 데이터 처리 (엑셀 업로드 -> 데이터 검증)
*&--------------------------------------------------------------------*
FORM get_data.
PERFORM get_excel_data. "1. 업로드한 엑셀 데이터 인터널 테이블로 변환
PERFORM get_check_data. "2. 데이터 코드 변환 및 유효성 검증
ENDFORM.
*&--------------------------------------------------------------------*
*& FORM get_excel_data: 엑셀 파일의 데이터를 인터널 테이블로 업로드
*&--------------------------------------------------------------------*
FORM get_excel_data.
DATA: lt_excel LIKE TABLE OF alsmex_tabline WITH HEADER LINE.
"엑셀 파일을 읽어 인터널 테이블(lt_excel)에 저장
CALL FUNCTION 'ALSM_EXCEL_TO_INTERNAL_TABLE'
EXPORTING
filename = p_path
i_begin_col = 1
i_begin_row = 3 "3행부터 데이터 읽기 시작
i_end_col = 1000
i_end_row = 10000
TABLES
intern = lt_excel
EXCEPTIONS
OTHERS = 1.
IF sy-subrc <> 0.
MESSAGE '엑셀 파일 업로드 또는 변환에 실패했습니다.' TYPE 'E'.
STOP.
ENDIF.
"읽어온 데이터를 프로그램 내부 구조체(gs_data2)로 옮김
LOOP AT lt_excel.
ASSIGN COMPONENT lt_excel-col OF STRUCTURE gs_data2 TO FIELD-SYMBOL(<field>).
<field> = lt_excel-value.
AT END OF row.
"숫자 필드에 대해 앞자리 '0' 채우기 (ALPHA 변환)
gs_data2-ebeln = |{ gs_data2-ebeln ALPHA = IN }|.
gs_data2-ebelp = |{ gs_data2-ebelp ALPHA = IN }|.
gs_data2-lifnr_ECC = |{ gs_data2-lifnr_ECC ALPHA = IN }|.
gs_data2-sakto = |{ gs_data2-sakto ALPHA = IN }|.
gs_data2-kostl_ECC = |{ gs_data2-kostl_ECC ALPHA = IN }|.
CALL FUNCTION 'CONVERSION_EXIT_MATN1_INPUT'
EXPORTING
input = gs_data2-matnr_ECC
IMPORTING
output = gs_data2-matnr_ECC.
APPEND gs_data2 TO gt_data2.
CLEAR gs_data2.
ENDAT.
ENDLOOP.
ENDFORM.
*&--------------------------------------------------------------------*
*& FORM get_check_data: 업로드 데이터 변환 및 유효성 검증
*&--------------------------------------------------------------------*
FORM get_check_data.
"이 서브루틴은 엑셀 데이터를 바탕으로 시스템에 맞는 코드로 변환(Migration)하고,
"각 필드의 값이 유효한지 마스터 데이터를 조회하여 검증합니다.
"1. 코드 변환 (선택화면의 'Code Conversion' 체크박스에 따라 분기)
IF p_code = 'X'.
"미리 정의된 코드 매핑 테이블(zmig_mm_code 등)을 조회하여
"기존 시스템(ECC) 코드를 새 시스템(HANA) 코드로 변환
"대상: 자재, 플랜트, 공급처(Vendor), 구매그룹, 코스트센터 등
"...(코드 변환 로직)...
ELSE.
"코드 변환 없이 기존 데이터 사용
"...(데이터 이동 로직)...
ENDIF.
"2. 마스터 데이터 및 필수값 유효성 검증
"미리 조회해둔 마스터 데이터(lt_lifnr, lt_marc 등)와 비교하여 검증 수행
LOOP AT gt_data INTO gs_data.
CLEAR gs_itab.
MOVE-CORRESPONDING gs_data TO gs_itab.
gs_itab-pokey = |{ gs_itab-ebeln }{ gs_itab-ebelp }|.
"검증 로직 (예시)
" - 공급처(Vendor) 코드가 유효한가?
" - 자재 코드가 해당 플랜트에 존재하는가?
" - 통화, 구매그룹, 지급조건 등 코드값이 유효한가?
" - 수량, 단가, 납품일 등 필수값이 입력되었는가?
" ...(각 필드별 검증 로직)...
"검증 실패 시, ALV에 표시될 아이콘과 메시지를 로그 테이블(gt_log)에 기록
IF "검증 실패 조건".
gs_itab-icon = icon_led_red.
gs_itab-message = '오류 메시지'.
gs_log-pokey = gs_itab-pokey.
gs_log-icon = icon_led_red.
gs_log-message = '상세 오류 메시지'.
APPEND gs_log TO gt_log.
ENDIF.
APPEND gs_itab TO gt_itab.
ENDLOOP.
ENDFORM.
*&--------------------------------------------------------------------*
*& FORM create_po: PO 생성 BAPI 호출
*&--------------------------------------------------------------------*
FORM create_po.
"--------------------------------------------------------------------
" 1. 사전 준비: 사용자 선택 확인 및 처리 대상 PO 선정
"--------------------------------------------------------------------
DATA: lt_srow TYPE lvc_t_row. "ALV에서 선택한 행의 인덱스 테이블
"ALV 그리드에서 사용자가 선택한 행 정보 가져오기
CALL METHOD grid->get_selected_rows
IMPORTING
et_index_rows = lt_srow.
"선택된 데이터가 없으면 오류 메시지 후 종료
IF lt_srow IS INITIAL.
MESSAGE '생성할 데이터를 선택해주세요.' TYPE 'E'.
RETURN.
ENDIF.
"사용자에게 PO 생성 여부 확인
PERFORM popup_confirm USING '확인' 'PO를 생성하시겠습니까?' DATA(lv_answer).
CHECK lv_answer = '1'. "사용자가 '예'를 선택한 경우에만 진행
"선택된 행 중, 오류가 없는(icon 필드가 비어있는) 행의 Old PO 번호(ebeln)만 추출
DATA(lt_select) = VALUE ekko_t_ebeln(
FOR ls_row IN lt_srow
LET lv_icon = VALUE #( gt_itab[ ls_row-index ]-icon ) IN
( ebeln = COND #( WHEN lv_icon IS INITIAL THEN VALUE #( gt_itab[ ls_row-index ]-ebeln OPTIONAL ) ) )
).
"추출된 PO 번호 리스트 정리 (초기값 제거, 정렬, 중복 제거하여 고유한 PO 생성 단위로 만듦)
DELETE lt_select WHERE ebeln IS INITIAL.
SORT lt_select BY ebeln.
DELETE ADJACENT DUPLICATES FROM lt_select COMPARING ebeln.
"처리할 대상이 없으면 오류 메시지 후 종료
IF lt_select IS INITIAL.
MESSAGE '오류가 없으며 처리 가능한 데이터가 없습니다.' TYPE 'E'.
RETURN.
ENDIF.
"--------------------------------------------------------------------
" 2. 메인 루프: PO 번호 단위로 BAPI 호출 준비 및 실행
"--------------------------------------------------------------------
"BAPI 호출에 필요한 구조체 및 인터널 테이블 선언
DATA: header LIKE bapimepoheader,
headerx LIKE bapimepoheaderx,
ponumber LIKE ekko-ebeln,
item LIKE bapimepoitem OCCURS 0 WITH HEADER LINE,
itemx LIKE bapimepoitemx OCCURS 0 WITH HEADER LINE,
sched LIKE bapimeposchedule OCCURS 0 WITH HEADER LINE,
schedx LIKE bapimeposchedulx OCCURS 0 WITH HEADER LINE,
account LIKE bapimepoaccount OCCURS 0 WITH HEADER LINE,
accountx LIKE bapimepoaccountx OCCURS 0 WITH HEADER LINE,
cond LIKE bapimepocond OCCURS 0 WITH HEADER LINE,
condx LIKE bapimepocondx OCCURS 0 WITH HEADER LINE,
potext LIKE bapimepotext OCCURS 0 WITH HEADER LINE,
return LIKE bapiret2 OCCURS 0 WITH HEADER LINE,
nopricepo LIKE bapiflag-bapiflag.
"선정된 고유 PO 번호(lt_select)를 기준으로 루프 시작 (하나의 PO 생성 단위)
LOOP AT lt_select INTO DATA(ls_select).
"루프 시작 시 BAPI 파라미터 초기화
REFRESH: return, item, itemx, sched, schedx, account, accountx, potext, cond, condx.
CLEAR: ponumber, header, headerx.
"BAPI 헤더 파라미터(POHEADER, POHEADERX) 채우기
READ TABLE gt_itab INTO DATA(ls_ekko) WITH KEY ebeln = ls_select-ebeln.
header-comp_code = s_ekorg-low.
header-doc_type = 'NB'.
header-doc_date = ls_ekko-bedat.
header-vendor = ls_ekko-lifnr.
header-currency = ls_ekko-waers.
header-purch_org = s_ekorg-low.
header-pur_group = ls_ekko-ekgrp.
header-collect_no = ls_ekko-ebeln. "참조 필드에 Old PO 번호 기록
header-pmnttrms = ls_ekko-zterm.
header-incoterms1 = ls_ekko-inco1.
header-incoterms2 = ls_ekko-inco2.
header-langu = sy-langu.
IF NOT ls_ekko-wkurs IS INITIAL.
header-exch_rate = ls_ekko-wkurs.
headerx-exch_rate = 'X'.
ENDIF.
headerx-comp_code = 'X'.
headerx-doc_type = 'X'.
headerx-doc_date = 'X'.
headerx-vendor = 'X'.
headerx-currency = 'X'.
headerx-purch_org = 'X'.
headerx-pur_group = 'X'.
headerx-collect_no = 'X'.
headerx-pmnttrms = 'X'.
headerx-incoterms1 = 'X'.
headerx-incoterms2 = 'X'.
headerx-langu = 'X'.
nopricepo = ''.
"해당 PO에 속한 품목(Item)들을 기준으로 내부 루프 시작
LOOP AT gt_itab INTO DATA(ls_ekpo) WHERE ebeln = ls_select-ebeln.
"--- BAPI 아이템 정보(POITEM) 채우기 ---
item-po_item = ls_ekpo-ebelp.
item-material = ls_ekpo-matnr.
item-stge_loc = ls_ekpo-lgort.
item-po_unit = ls_ekpo-meins.
item-plant = ls_ekpo-werks.
item-quantity = ls_ekpo-menge.
item-po_price = '2'. "가격 책정 방식 (1:총가격, 2:단가)
item-net_price = ls_ekpo-netpr.
item-no_rounding = 'X'. "반올림 안함
item-tax_code = ls_ekpo-mwskz.
item-price_unit = ls_ekpo-peinh.
item-item_cat = ls_ekpo-pstyp.
item-acctasscat = ls_ekpo-knttp.
item-qual_insp = ls_ekpo-insmk. "재고유형
item-ir_ind = 'X'. "송장수령
item-gr_basediv = ls_ekpo-webre. "입고기준 송장처리
item-conf_ctrl = ls_ekpo-bstae. "확정 제어키
item-ers = ls_ekpo-xersy. "대금 자동 정산
IF ls_ekpo-repos IS NOT INITIAL. "무상 품목 체크
item-free_item = 'X'.
item-ir_ind = ''.
ENDIF.
IF ls_ekpo-knttp = 'K' OR ls_ekpo-knttp = 'A'. "계정지정 범주 K 또는 A
item-matl_group = ls_ekpo-matkl.
IF ls_ekpo-matnr IS INITIAL.
item-short_text = ls_ekpo-txz01.
ENDIF.
ENDIF.
IF ls_ekpo-retpo IS NOT INITIAL. "반품 품목
item-ret_item = 'X'.
ENDIF.
item-over_dlv_tol = ls_ekpo-uebto. "납품초과 허용 한도
item-under_dlv_tol = ls_ekpo-untto. "납품미달 허용 한도
APPEND item.
"--- BAPI 아이템 변경 플래그(POITEMX) 채우기 ---
itemx-po_item = ls_ekpo-ebelp.
itemx-po_itemx = 'X'.
itemx-material = 'X'.
itemx-stge_loc = 'X'.
itemx-po_unit = 'X'.
itemx-plant = 'X'.
itemx-quantity = 'X'.
itemx-po_price = 'X'.
itemx-net_price = 'X'.
itemx-no_rounding = 'X'.
itemx-tax_code = 'X'.
itemx-price_unit = 'X'.
itemx-item_cat = 'X'.
itemx-acctasscat = 'X'.
itemx-qual_insp = 'X'.
itemx-ir_ind = 'X'.
itemx-gr_basediv = 'X'.
itemx-conf_ctrl = 'X'.
itemx-ers = 'X'.
IF ls_ekpo-repos IS NOT INITIAL.
itemx-free_item = 'X'.
ENDIF.
IF ls_ekpo-knttp = 'K' OR ls_ekpo-knttp = 'A'.
itemx-matl_group = 'X'.
IF ls_ekpo-matnr IS INITIAL.
itemx-short_text = 'X'.
ENDIF.
ENDIF.
IF ls_ekpo-retpo IS NOT INITIAL.
itemx-ret_item = 'X'.
ENDIF.
itemx-over_dlv_tol = 'X'.
itemx-under_dlv_tol = 'X'.
APPEND itemx.
"--- BAPI 납품일정 정보(POSCHEDULE, POSCHEDULEX) 채우기 ---
sched-po_item = ls_ekpo-ebelp.
sched-sched_line = '0001'.
sched-del_datcat_ext = 'D'. "납품일자 유형: 일(Day)
sched-delivery_date = ls_ekpo-eindt.
APPEND sched.
schedx-po_item = ls_ekpo-ebelp.
schedx-sched_line = '0001'.
schedx-po_itemx = 'X'.
schedx-sched_linex = 'X'.
schedx-del_datcat_ext = 'X'.
schedx-delivery_date = 'X'.
APPEND schedx.
"--- BAPI 계정지정 정보(POACCOUNT, POACCOUNTX) 채우기 ---
IF ls_ekpo-knttp IS NOT INITIAL.
account-po_item = ls_ekpo-ebelp.
account-serial_no = 1.
account-unload_pt = ls_ekpo-ablad.
account-gl_account = ls_ekpo-sakto.
account-tax_code = ls_ekpo-mwskz.
account-costcenter = ls_ekpo-kostl.
account-asset_no = ls_ekpo-anln1.
IF ls_ekpo-knttp = 'A'.
account-orderid = ls_ekpo-aufnr.
ENDIF.
APPEND account.
accountx-po_item = ls_ekpo-ebelp.
accountx-serial_no = 1.
accountx-unload_pt = 'X'.
accountx-gl_account = 'X'.
accountx-tax_code = 'X'.
accountx-costcenter = 'X'.
accountx-asset_no = 'X'.
accountx-orderid = 'X'.
APPEND accountx.
ENDIF.
"--- BAPI 품목 텍스트(POTEXTITEM) 채우기 ---
potext-po_item = ls_ekpo-ebelp.
potext-text_id = 'F01'.
potext-text_form = '*'.
potext-text_line = |{ ls_ekpo-ebeln } - { ls_ekpo-ebelp }|.
APPEND potext.
"--- BAPI 가격 조건(POCOND, POCONDX) 처리 ---
"구매정보레코드(Info Record) 및 관련 가격 조건(KONP) 조회
SELECT eina~infnr, ... FROM eina INNER JOIN eine ...
WHERE ... INTO TABLE @DATA(lt_info).
IF lt_info IS NOT INITIAL.
SELECT a017~knumh, konp~kschl, ... FROM a017 INNER JOIN konp ...
FOR ALL ENTRIES IN @lt_info
WHERE ... INTO TABLE @DATA(pt_konp).
ENDIF.
DATA(lv_condtion) = abap_false.
"각 가격 조건(ZTA1, ZFR1 등)에 대해, 시스템에 기존 조건이 있는지 확인하고
"업로드된 값의 유무에 따라 신규(I) 또는 수정(U)으로 BAPI 파라미터를 구성
"관세(ZTA1) 처리
READ TABLE pt_konp INTO DATA(ls_konp) WITH KEY kschl = 'ZTA1' BINARY SEARCH.
IF sy-subrc = 0. lv_condtion = abap_true. ENDIF. "기존 조건 존재
IF ls_ekpo-zta1 IS NOT INITIAL. "업로드 값 존재
cond-itm_number = ls_ekpo-ebelp.
cond-cond_type = 'ZTA1'.
cond-cond_value = ls_ekpo-zta1.
cond-change_id = COND #( WHEN lv_condtion = abap_true THEN 'U' ELSE 'I' ).
APPEND cond.
ELSE. "업로드 값 없음
IF lv_condtion = abap_true. "기존 조건만 있으면 변경 불필요 (삭제 시 로직 추가 필요)
ENDIF.
ENDIF.
" ... (ZFR1, ZFR2, ZFR9 등 다른 조건들도 위와 유사하게 처리) ...
"조건 변경 플래그 설정
condx-itm_number = ls_ekpo-ebelp.
condx-itm_numberx = 'X'.
condx-cond_type = 'X'.
condx-cond_value = 'X'.
condx-change_id = 'X'.
APPEND condx.
ENDLOOP.
"------------------------------------------------------------------
" 3. BAPI 실행 및 결과 처리
"------------------------------------------------------------------
CALL FUNCTION 'BAPI_PO_CREATE1'
EXPORTING
poheader = header
poheaderx = headerx
testrun = p_test
IMPORTING
exppurchaseorder = ponumber
TABLES
return = return
poitem = item
poitemx = itemx
poschedule = sched
poschedulex = schedx
poaccount = account
poaccountx = accountx
pocond = cond
pocondx = condx
potextitem = potext.
"BAPI 리턴 메시지 중 'E'(Error) 타입이 있는지 확인
READ TABLE return WITH KEY type = 'E' TRANSPORTING NO FIELDS.
IF sy-subrc = 0. "오류가 하나라도 발생한 경우
IF p_test IS INITIAL. "테스트 실행이 아닐 경우 롤백
CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
ENDIF.
"결과를 ALV에 빨간색 아이콘과 첫 번째 오류 메시지로 업데이트
MODIFY gt_itab FROM VALUE #( icon = icon_led_red message = return[ 1 ]-message )
TRANSPORTING icon message WHERE ebeln = ls_ekko-ebeln.
ELSE. "성공한 경우
IF p_test IS NOT INITIAL. "테스트 실행인 경우
"ALV에 초록색 아이콘과 성공 메시지로 업데이트
MODIFY gt_itab FROM VALUE #( icon = icon_led_green message = return[ 1 ]-message )
TRANSPORTING icon message WHERE ebeln = ls_ekko-ebeln.
ELSE. "실제 실행인 경우
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT' EXPORTING wait = 'X'.
"ALV에 초록색 아이콘, 성공 메시지, 생성된 신규 PO 번호로 업데이트
LOOP AT item INTO DATA(ls_result).
MODIFY gt_itab FROM VALUE #(
icon = icon_led_green
message = return[ 1 ]-message
ebeln_new = ponumber
ebelp_new = ls_result-po_item
)
TRANSPORTING icon message ebeln_new ebelp_new
WHERE ebeln = ls_ekko-ebeln AND ebelp = ls_result-po_item.
"생성 성공 로그를 Custom 테이블(zmmt0751)에 저장
INSERT zmmt0751 FROM VALUE #(
pokey = |{ header-collect_no }{ ls_result-po_item }|
ebeln = ponumber
ebelp = ls_result-po_item
erdat = sy-datum
ernam = sy-uname
ekorg = s_ekorg-low
).
ENDLOOP.
ENDIF.
ENDIF.
ENDLOOP.
ENDFORM.
*&--------------------------------------------------------------------*
*& FORM popup_confirm: 사용자 확인 팝업 호출
*&--------------------------------------------------------------------*
FORM popup_confirm USING pv_title pv_question pv_answer.
CALL FUNCTION 'POPUP_TO_CONFIRM'
EXPORTING
titlebar = pv_title
text_question = pv_question
IMPORTING
answer = pv_answer
EXCEPTIONS
OTHERS = 1.
ENDFORM.
*&--------------------------------------------------------------------*
*& FORM curr_change: 통화 코드 변환 ('RMB' -> 'CNY')
*&--------------------------------------------------------------------*
FORM curr_change CHANGING pv_data1 pv_data2.
CASE pv_data1.
WHEN 'RMB'.
pv_data2 = 'CNY'.
WHEN OTHERS.
pv_data2 = pv_data1.
ENDCASE.
ENDFORM.
*&--------------------------------------------------------------------*
*& ALV 설정 관련 서브루틴들
*&--------------------------------------------------------------------*
FORM create_controls.
"화면 상단에 ALV가 표시될 컨테이너(도킹 컨테이너)를 생성
CREATE OBJECT grid EXPORTING i_parent = g_docking_container.
ENDFORM.
FORM set_event.
"ALV의 이벤트(예: 핫스팟 클릭)를 처리할 클래스를 등록
CREATE OBJECT event_receiver.
SET HANDLER event_receiver->handle_hotspot_click FOR grid.
ENDFORM.
FORM alv_layout.
"ALV의 기본 레이아웃 설정 (행 선택모드, 줄무늬, 컬럼 너비 최적화)
gs_layout-sel_mode = 'A'. "다중 행 선택
gs_layout-zebra = 'X'. "줄무늬
gs_layout-cwidth_opt = 'X'. "너비 최적화
ENDFORM.
FORM exclude_tb_functions CHANGING pt_exclude TYPE ui_functions.
"ALV 표준 툴바에서 불필요한 버튼들(행 추가/삭제, 복사/붙여넣기 등)을 제거
" ...(제외 로직 생략)...
ENDFORM.
FORM set_variant.
"ALV 레이아웃을 저장하고 불러오기 위한 Variant 설정
gs_variant-report = sy-repid.
gs_variant-username = sy-uname.
ENDFORM.
FORM fieldcat_init.
"ALV에 표시될 컬럼들의 속성을 정의 (컬럼명, 순서, 색상, 핫스팟 등)
" - 시스템 구조를 이용해 필드 카탈로그 자동 생성
" - LOOP를 돌며 각 필드의 속성을 개별적으로 수정
" (예: 'MESSAGE' 필드에 핫스팟 기능 추가, 특정 필드 숨기기 등)
" ...(필드 카탈로그 생성 및 수정 로직)...
ENDFORM.
이렇게 엑셀업로드로 PO만드는 프로그램을 마칩니다.
엑셀업로드가 아닌
구시스템의 PO정보 테이블을 가져와서 만드는 것을 코딩하겠습니다.
'ABAP' 카테고리의 다른 글
[ABAP] 엑셀로 구매정보레코드(Info Record) 대량 생성/변경 (0) | 2025.06.29 |
---|---|
[ABAP] 구시스템 참조하여 데이터 가져오기 (0) | 2025.06.28 |
[ABAP] BAPI_PO_CREATE1을 활용한 마이그레이션용 구매오더(PO) 생성 가이드 (0) | 2025.06.24 |
[step-3] executable program templete - PBO,PAI,CLS,F01 (0) | 2025.06.24 |
[step-2] executable program templete - TOP,SEL (0) | 2025.06.23 |