SAP 에서 화면을 확장하는 방법은 시나리오에 따라 두 갈래로 나뉩니다. 표준이 미리 만들어 둔 서브스크린 슬롯에 필드를 끼워 넣는 방식 과, 새 Function Group + 새 Screen + 새 BAdI 정의를 직접 만들어서 SUBSCRIBE 매핑으로 표준에 노출시키는 방식. 전자는 단일 필드 추가에 적합하고, 후자는 별도 영역 / 탭 / 전용 화면 단위로 확장할 때 사용합니다.
이 글은 후자 — BAdI 정의 자체를 새로 만들어 Screen 을 관리하는 풀 커스텀 패턴 을 다룹니다. 화면 구성을 자체 Function Group 으로 가지고, 그 Screen 을 BAdI 정의의 SUBSCRIBE 영역에 등록해서 표준 트랜잭션이 호출할 때 노출되게 만드는 구조입니다.
표준 슬롯 확장에 비해 자유도가 높지만 그만큼 책임도 큽니다. PBO·PAI 흐름·데이터 교환·BAdI 활성화·Subscribe 매핑까지 작성자가 모두 책임집니다. 이 글에서는 5단계로 끝까지 따라갈 수 있게 정리합니다.
핵심 — 4개 객체가 SUBSCRIBE 로 연결된다
| 객체 | 담당 | T-Code |
|---|---|---|
| 1 | Function Group 생성 (Screen 컨테이너) | SE80 / SE37 |
| 2 | Screen 생성 (PBO / PAI / 레이아웃) | SE80 / SE51 |
| 3 | BAdI 정의 생성 (인터페이스 + SUBSCRIBE) | SE18 |
| 4 | BAdI 구현 (Implementation) | SE19 |
| 5 | SUBSCRIBE 매핑 (Function Group + Screen 연결) | BAdI 정의 내 Subscreens 탭 |
SUBSCRIBE 매핑이 핵심 연결고리입니다. BAdI 정의에 있는 SUBSCRIBE 영역에 Function Group · Screen 번호 · Subscreen Area 를 매핑해야 표준 트랜잭션이 호출 시점에 그 Screen 을 현재 화면 영역에 끼워 그려줍니다. 이 매핑이 비어 있으면 BAdI 가 구현되어도 화면이 표시되지 않습니다.
1단계 — Function Group 생성
Screen 을 담을 컨테이너입니다. Z 네이밍으로 새 Function Group 을 만듭니다.
SE80 → 객체 유형: Function Group → 신규 생성
→ 이름: ZFXX_PO_SCREEN
→ 짧은 설명: BAdI Screen Exit Function Group
→ 패키지 / CTS 선택
→ 저장 → 활성화
이 Function Group 안에 Screen 1개 또는 여러 개를 만들 수 있습니다. 같은 영역에서 사용할 화면들을 한 그룹에 묶으면 데이터 공유와 관리가 편합니다.
Function Group 의 Top Include(LZFXX_PO_SCREENTOP) 에 화면이 사용할 글로벌 변수 / 작업 영역을 선언합니다.
* TOP Include
FUNCTION-POOL zfxx_po_screen.
DATA: gv_zmosen TYPE zmosen, " 모선관리번호 (화면 변수)
gs_ekpo TYPE ekpo, " 백엔드 데이터 공유용
gs_ekko TYPE ekko.
2단계 — Screen 생성 (PBO / PAI 로직 포함)
Function Group 우클릭 → Screen 생성 → 번호 부여(예: 0100).
SE80 → ZFXX_PO_SCREEN → 우클릭 → Screen 신규
→ Screen 번호: 0100
→ Screen 유형: Subscreen
→ Layout 편집: 필드 배치 (모선번호 등)
→ 흐름 로직 작성
Subscreen 유형으로 만드는 게 핵심입니다. 일반 Screen 으로 만들면 독립 화면이 되어 BAdI Subscreen 영역에 끼워 넣을 수 없습니다.
흐름 로직 예시:
PROCESS BEFORE OUTPUT.
MODULE pbo_0100.
PROCESS AFTER INPUT.
MODULE pai_0100.
PROCESS ON VALUE-REQUEST.
FIELD gv_zmosen MODULE f4_zmosen.
Module 구현:
* PBO — 화면 그리기 직전
MODULE pbo_0100 OUTPUT.
" 백엔드 데이터를 화면 변수로 옮기기
gv_zmosen = gs_ekpo-zmosen.
" 화면 모드(조회/수정)에 따라 활성화 제어
IF gs_ekpo-loekz IS NOT INITIAL. " 삭제된 라인은 비활성
LOOP AT SCREEN.
IF screen-name = 'GV_ZMOSEN'.
screen-input = 0.
MODIFY SCREEN.
ENDIF.
ENDLOOP.
ENDIF.
ENDMODULE.
* PAI — 사용자 입력 후
MODULE pai_0100 INPUT.
" 화면 변수를 백엔드 데이터로 옮기기
gs_ekpo-zmosen = gv_zmosen.
ENDMODULE.
PBO / PAI 모듈이 화면 ↔ 백엔드 데이터 교환의 핵심입니다. 표준 BAdI Method 가 호출될 때 GS_EKPO 를 채워주고, 사용자 입력은 GS_EKPO 에서 다시 표준 측으로 반환됩니다.
3단계 — BAdI 정의 생성 (Classic BAdI)
이제 Screen 을 표준에 노출시킬 BAdI 정의를 만듭니다.
SE18 → BAdI 정의: ZBADI_PO_SCREEN
→ 짧은 설명: PO Screen Exit BAdI
→ Multiple Use 체크 (옵션)
→ 인터페이스 자동 생성 (ZIF_EX_BADI_PO_SCREEN)
→ 메소드 정의:
- GET_DATA : 표준이 BAdI 에 PO 데이터 전달
- SAVE_DATA : 화면에서 변경된 데이터를 표준으로 반환
- CHECK_DATA : 입력값 검증
메소드 시그니처 예시:
" GET_DATA - 표준 → BAdI
METHODS get_data
IMPORTING
is_ekko TYPE ekko
is_ekpo TYPE ekpo.
" SAVE_DATA - BAdI → 표준
METHODS save_data
EXPORTING
es_ekpo TYPE ekpo.
이 메소드들이 화면 PBO/PAI 모듈과 백엔드 데이터 교환을 담당합니다.
4단계 — SUBSCRIBE 매핑 (가장 중요한 단계)
BAdI 정의 화면에서 Subscreens 탭(또는 Subscribe 영역) 으로 이동해 1단계·2단계에서 만든 Function Group + Screen 을 매핑합니다.
SE18 → ZBADI_PO_SCREEN → Subscreens 탭
→ 새 항목 추가:
- Subscreen Area: ITEM_DETAIL (BAdI 가 노출될 영역)
- Program: SAPLZFXX_PO_SCREEN (Function Group 의 메인 프로그램)
- Dynpro: 0100 (2단계에서 만든 Screen 번호)
→ 저장 + 활성화
Subscreen Area 가 표준 트랜잭션이 인지하는 노출 위치 이름입니다. 회사에서 정해진 이름(예: ITEM_DETAIL · HEAD_CUSTOMER_DATA) 을 사용해야 표준이 그 영역에 끼워 넣어 줍니다.
이 매핑이 완성되면 표준이 BAdI 의 Subscreen Area 를 그릴 때 자동으로 우리 Function Group 의 Screen 0100 을 호출 합니다. 매핑 없이는 BAdI 가 활성화돼도 화면이 비어 있게 그려집니다.
5단계 — BAdI 구현 (SE19)
마지막으로 BAdI 정의를 구현해서 데이터 교환 로직을 채웁니다.
SE19 → ZBADI_PO_SCREEN 구현체 생성
→ 이름: ZIM_PO_SCREEN_001
→ 짧은 설명: PO Screen 구현체
→ 메소드 구현 → 활성화
메소드 구현 예시:
METHOD if_ex_zbadi_po_screen~get_data.
" 표준에서 받은 데이터를 Function Group 의 글로벌 영역으로 전송
CALL FUNCTION 'ZFXX_PO_SCREEN_SET_DATA'
EXPORTING
is_ekpo = is_ekpo
is_ekko = is_ekko.
ENDMETHOD.
METHOD if_ex_zbadi_po_screen~save_data.
" Function Group 에서 사용자 입력값을 가져와서 표준에 반환
CALL FUNCTION 'ZFXX_PO_SCREEN_GET_DATA'
IMPORTING
es_ekpo = es_ekpo.
ENDMETHOD.
Function Group 안에 글로벌 변수 액세스용 Function Module 을 2개 만들어두면(SET_DATA · GET_DATA) BAdI 구현체에서 안전하게 데이터를 주고받을 수 있습니다.
두 방식 비교 — 언제 어떤 패턴을 쓸 것인가
| 상황 | 표준 슬롯 (MAP_DYNPRO_FIELDS) | 신규 BAdI 정의 + Subscribe |
|---|---|---|
| 단일 필드 1~2개 추가 | ✓ 적합 (가장 빠름) | 과한 설계 |
| 전용 탭 / 영역 분리 | 표준 슬롯에 제약 | ✓ 적합 |
| 여러 화면 / 트랜잭션에 공통 노출 | 표준마다 따로 매핑 필요 | ✓ 적합 (한 Function Group 공유) |
| 회사 자체 트랜잭션 화면 | 불가능 | ✓ 적합 |
| 유지보수 비용 | 낮음 (표준이 변경 흡수) | 높음 (자체 책임) |
규칙은 단순합니다 — 필드 1~2개면 MAP_DYNPRO_FIELDS, 영역 / 탭 단위면 BAdI 정의 + Subscribe.
흔히 빠뜨리는 함정
SUBSCRIBE 매핑이 비어 있음
BAdI 가 활성화되고 구현체도 만들었는데 화면이 안 보이는 가장 흔한 원인. SE18 의 Subscreens 탭에서 Program · Dynpro · Subscreen Area 가 모두 정확히 채워져 있는지 확인하시기 바랍니다.
Screen 을 일반 유형으로 만듦
Subscreen 이 아닌 일반 Dynpro 로 만들면 BAdI Subscreen 영역에 끼워 넣을 수 없습니다. SE51 의 Screen 속성에서 유형(Type) 을 반드시 Subscreen 으로 설정.
Function Group 의 글로벌 변수 공유 실패
BAdI 구현체와 Function Group 의 PBO / PAI 모듈은 다른 LUW 컨텍스트라 일반 변수로는 데이터 공유가 안 됩니다. 반드시 Function Group 의 글로벌 변수(TOP Include) 또는 SET/GET FM 을 통해 교환해야 합니다.
Subscreen Area 이름이 틀림
표준 트랜잭션이 인지하는 Subscreen Area 이름은 정해져 있습니다. 임의로 만든 이름은 표준이 모르므로 호출되지 않습니다. 회사에서 사용 중인 Area 이름을 사전에 확인하시기 바랍니다.
Multiple Use 미체크
여러 구현체가 동시 활성화돼야 하는 시나리오(다른 모듈에서도 같은 BAdI 사용) 라면 Multiple Use 를 체크해야 합니다. 미체크 상태에서 두 번째 구현체 활성화 시 SINGLE_EXIT_MULTIPLY_ACTIVE 예외가 발생합니다.
F4 서치헬프 흐름 누락
PBO / PAI 만 정의하고 PROCESS ON VALUE-REQUEST 를 빠뜨리면 F4 가 동작하지 않습니다. 화면 흐름 로직에 별도 분기를 추가하시기 바랍니다.
활성화 / 비활성화 제어 누락
PBO 모듈에서 LOOP AT SCREEN 으로 활성 / 비활성을 처리하지 않으면 모든 모드(조회 · 변경 · 생성) 에서 같은 화면이 그려집니다. 표준 화면 모드를 받아서 모드별 분기 처리가 필요합니다.
CTS 분할 위험
Function Group · Screen · BAdI 정의 · BAdI 구현체 · Subscribe 매핑이 다른 CTS 에 담기면 운영 이송 시 일부만 이동해 화면이 깨집니다. 한 CTS 에 묶어두시기 바랍니다.
두 방식 시리즈 정리
이 글은 "새 BAdI 정의 + Function Group + Screen + Subscribe 매핑" 의 풀 커스텀 패턴을 다뤘습니다. 같은 시리즈로 봐야 할 글 — "Screen Exit 커스텀 필드 추가 — MAP_DYNPRO_FIELDS BAdI 활용 방법" 은 표준이 이미 만들어 둔 슬롯에 필드를 끼워 넣는 가벼운 방식. 두 글이 같은 "Screen Exit" 카테고리지만 메커니즘이 완전히 다르므로 시나리오에 맞게 골라 쓰시기 바랍니다.
같이 보면 좋은 글: "BAdI 찾는 방법 5가지 — CL_EXITHANDLER 디버깅·SE84·SXS_ATTR 메타테이블" — 본인이 만든 BAdI 가 정상 호출되는지 추적할 때 유용합니다.
요약
| 단계 | 하는 일 | 핵심 포인트 |
|---|---|---|
| 1 | Function Group 생성 | Screen 컨테이너 + TOP Include 글로벌 변수 |
| 2 | Screen 생성 | Subscreen 유형 + PBO/PAI 로직 |
| 3 | BAdI 정의 생성 | 인터페이스 + GET_DATA / SAVE_DATA 메소드 |
| 4 | SUBSCRIBE 매핑 | Program + Dynpro + Subscreen Area |
| 5 | BAdI 구현 | SET/GET FM 으로 글로벌 데이터 교환 |
BAdI 정의로 Screen Exit 를 만드는 방식은 MAP_DYNPRO_FIELDS 패턴보다 자유도가 높지만 작성자가 더 많은 책임을 집니다. 화면 흐름 로직·데이터 교환·활성화 제어·Subscribe 매핑까지 직접 관리해야 하며, 운영 이송 시 모든 객체가 같은 CTS 에 묶여야 합니다. 단일 필드 추가는 표준 슬롯 패턴(MAP_DYNPRO_FIELDS) 이 더 효율적이고, 전용 영역 · 탭 · 회사 자체 화면 단위 확장이 필요할 때 이 풀 커스텀 패턴을 선택하시기 바랍니다.
Disclaimer — 이 포스트는 실무 정리 노트를 바탕으로 AI 보조로 정리되었습니다.
Classic BAdI 정의 구조 · SUBSCRIBE 영역 동작 · Subscreen 매핑 룰은 SAP NetWeaver 표준(ECC 6.0 / S/4HANA on-premise) 기준이며, Subscreen Area 이름 · 표준 트랜잭션이 호출하는 BAdI 위치 · 회사 네이밍 룰은 사내 환경에 따라 다르므로 운영 시스템 적용 전 개발·QA 환경에서 검증하시기 바랍니다.