ALV 리포트 화면에서 사용자가 어떤 행을 선택했을 때, 그 행에 연결된 첨부파일 / 노트 / 비즈니스 문서를 바로 볼 수 있게 하려면 SAP 표준 GOS 서비스를 ALV 의 시스템 메뉴에 등록 해야 합니다. 자체 Dynpro 화면에 Custom Container 를 그리고 CL_GOS_MANAGER 를 직접 인스턴스화하는 방법도 있지만, ALV 리포트처럼 이미 화면 프레임이 정해진 출력 화면 에서는 더 가벼운 방법이 있습니다.
표준 Function Module SWU_OBJECT_PUBLISH 를 호출하면 현재 LUW 의 ALV 화면 메뉴에 GOS 아이콘이 자동으로 추가 됩니다. ALV 의 표준 툴바 / 시스템 메뉴 어디에서도 클릭 가능한 GOS 서비스 메뉴가 펼쳐지며, 첨부파일 추가 · 조회 · 송신 등의 기능이 표준 ME23N 과 동일하게 동작합니다.
이 글에서는 SWU_OBJECT_PUBLISH 의 시그니처·OAC0/OAC3 저장소와의 관계·ALV 더블클릭 이벤트와 연동 패턴·다건 객체 등록·CL_GOS_MANAGER 와의 차이점까지 한 번에 정리합니다. ALV 조회 리포트에 첨부 기능을 가볍게 끼워 넣고 싶을 때 가장 빠른 도구입니다.
핵심 — SWU_OBJECT_PUBLISH vs CL_GOS_MANAGER
| 항목 | SWU_OBJECT_PUBLISH (FM) | CL_GOS_MANAGER (Class) |
|---|---|---|
| 호출 방식 | Function Module 한 줄 | 클래스 인스턴스 생성 |
| 적합 시나리오 | ALV 조회 리포트 · 표준 메뉴 등록 | 자체 Dynpro · Custom Container |
| 컨테이너 필요 여부 | 불필요 (표준 메뉴 자동 등록) | 필수 (CL_GUI_CUSTOM_CONTAINER) |
| 다건 객체 등록 | 반복 호출 (각 행마다) | SET_ID_OF_PUBLISHED_OBJECT 로 전환 |
| 코드 라인 수 | 5~10줄 | 20~30줄 (PBO/PAI 포함) |
선택 기준: ALV 조회 위주 + 표준 메뉴에서 GOS 접근 이면 SWU_OBJECT_PUBLISH, 자체 Dynpro + 화면 영역에 GOS 아이콘 직접 배치 면 CL_GOS_MANAGER. 두 방식 모두 내부적으로 같은 GOS 백엔드(SRGBRBREL) 를 사용하므로 첨부 결과는 동일합니다.
1단계 — 시그니처 확인
| 구분 | 파라미터 | 의미 |
|---|---|---|
| IMPORTING | OBJTYPE |
BOR 객체 유형 (예: BUS2012) 또는 OAC0 저장소명 |
| IMPORTING | OBJKEY |
객체 키 값 (PO 번호 · 자재문서 등) |
| IMPORTING | CREATOR (Opt) |
첨부 생성자 (기본 = 로그인 사용자) |
| IMPORTING | METHOD (Opt) |
기본 동작 메소드 (특수 시나리오만 사용) |
| IMPORTING | MODE (Opt, 기본 'E') |
'E' Edit / 'A' Display |
| TABLES | CONTAINER (Opt) |
컨텍스트 데이터 (워크플로우 연동 시) |
리턴 — 함수 호출 자체로 GOS 등록이 끝납니다. 호출자가 별도 객체 / 메모리를 관리할 필요가 없습니다.
2단계 — OBJTYPE 결정 — BOR 객체 vs OAC0 저장소
표준 BOR 객체 사용 (가장 흔함):
" PO 4500000001 에 GOS 아이콘 등록
CALL FUNCTION 'SWU_OBJECT_PUBLISH'
EXPORTING
objtype = 'BUS2012' " 표준 PO BOR 객체
objkey = '4500000001'
mode = 'A' " 조회 모드
EXCEPTIONS
objtype_not_found = 1.
OAC0 저장소 사용 (회사 자체 객체 + DMS 저장소):
T-Code: OAC0
→ 저장소 정의 (Content Repository)
→ 또는 Document type 매핑
T-Code: OAC3
→ Workflow Object Repository Browser
→ BOR 객체 ↔ 저장소 매핑
자체 Z 객체에 첨부를 붙이려면 BOR 객체를 신규 정의(SWO1) 하거나 OAC0/OAC3 으로 저장소를 등록한 후 그 이름을 OBJTYPE 에 전달합니다.
자주 쓰는 BOR 객체 매핑:
| OBJTYPE | 대상 | OBJKEY 예시 |
|---|---|---|
BUS2012 |
구매오더 | 4500000001 |
BUS2081 |
송장 | 51000000012026 |
BUS2017 |
자재문서 | MBLNR + MJAHR |
BUS1001 · MARA |
자재 마스터 | MATNR |
3단계 — ALV 더블 클릭 이벤트와 연동
ALV 의 표준 더블 클릭 이벤트(DOUBLE_CLICK) 에서 SWU_OBJECT_PUBLISH 를 호출하면 사용자가 더블 클릭한 행의 객체를 GOS 에 즉시 등록.
" ALV 더블 클릭 핸들러
METHOD on_double_click.
DATA: ls_data TYPE ty_alv_data.
" 1) 더블 클릭한 행의 데이터 가져오기
READ TABLE gt_alv_data INTO ls_data INDEX e_row-index.
CHECK sy-subrc = 0.
" 2) GOS 등록 — 그 행의 PO 번호를 객체로
CALL FUNCTION 'SWU_OBJECT_PUBLISH'
EXPORTING
objtype = 'BUS2012'
objkey = ls_data-ebeln
mode = 'A' " 조회 모드
EXCEPTIONS
objtype_not_found = 1.
ENDMETHOD.
호출 후 사용자가 ALV 상단 메뉴 → System → Services for Object 를 누르면 그 PO 에 연결된 첨부 / 노트 / 송신 메뉴가 나타납니다. 사용자가 행을 더블 클릭할 때마다 다른 PO 가 GOS 에 활성 으로 등록됩니다.
4단계 — INITIALIZATION 시점 등록 (단일 객체 시나리오)
리포트가 단일 객체(예: 특정 PO 한 건의 상세) 만 다루면 INITIALIZATION / START-OF-SELECTION 에서 한 번만 등록.
START-OF-SELECTION.
" 단일 PO 의 GOS 메뉴 활성화
CALL FUNCTION 'SWU_OBJECT_PUBLISH'
EXPORTING
objtype = 'BUS2012'
objkey = p_ebeln " Selection screen 파라미터
mode = 'E' " 변경 가능
EXCEPTIONS
objtype_not_found = 1.
" ALV 출력 ...
이 패턴에서는 ALV 전체에 하나의 객체가 항상 활성. 화면 시작부터 끝까지 GOS 메뉴를 통해 같은 PO 의 첨부 / 노트를 다룰 수 있습니다.
5단계 — 변경 모드 (편집) 활용
조회 ALV 는 MODE = 'A' 가 일반적이지만, 사용자가 ALV 에서 직접 첨부를 올리는 시나리오라면 'E' 로 전환.
CALL FUNCTION 'SWU_OBJECT_PUBLISH'
EXPORTING
objtype = 'BUS2012'
objkey = p_ebeln
mode = 'E' " 첨부 추가 / 삭제 가능
EXCEPTIONS
objtype_not_found = 1.
권한 그룹에 따라 동적 분기:
DATA lv_mode TYPE sgs_rwmod.
AUTHORITY-CHECK OBJECT 'Z_GOS_ATTACH'
ID 'ACTVT' FIELD '02'. " 02 = Change
IF sy-subrc = 0.
lv_mode = 'E'.
ELSE.
lv_mode = 'A'.
ENDIF.
CALL FUNCTION 'SWU_OBJECT_PUBLISH'
EXPORTING
objtype = 'BUS2012'
objkey = p_ebeln
mode = lv_mode
EXCEPTIONS
objtype_not_found = 1.
6단계 — 첨부 유무 표시 (ALV 컬럼 + 아이콘)
ALV 행마다 첨부 유무를 컬럼에 표시하려면 SRGBRBREL 을 한 번에 조회한 후 아이콘 컬럼을 채웁니다.
" 1) 모든 행의 첨부 유무 한 번에 조회 (대용량 권장)
SELECT instid_a
INTO TABLE @DATA(lt_atta_keys)
FROM srgbrbrel
FOR ALL ENTRIES IN @gt_alv_data
WHERE instid_a = @gt_alv_data-ebeln
AND typeid_a = 'BUS2012'
AND catid_a = 'BO'
AND reltype = 'ATTA'.
" 2) ALV 데이터에 아이콘 컬럼 채움
LOOP AT gt_alv_data ASSIGNING FIELD-SYMBOL(<ls_alv>).
READ TABLE lt_atta_keys WITH KEY instid_a = <ls_alv>-ebeln
TRANSPORTING NO FIELDS.
IF sy-subrc = 0.
<ls_alv>-atta_icon = '@4P@'. " 클립 아이콘 (예시)
ELSE.
<ls_alv>-atta_icon = ''.
ENDIF.
ENDLOOP.
ALV 의 Field Catalog 에서 icon = 'X' 로 표시하면 아이콘이 렌더링됩니다. 사용자는 첨부 유무를 한눈에 보고 그 행만 더블 클릭해서 첨부 메뉴를 활성화할 수 있습니다.
흔히 빠뜨리는 함정
OBJTYPE 잘못 입력
존재하지 않는 BOR 객체를 OBJTYPE 에 넘기면 OBJTYPE_NOT_FOUND 예외 발생. 표준 BOR 객체명(BUS*) 또는 OAC3 에서 정의된 저장소명을 정확히 사용.
OBJKEY 길이 / 자리수
OBJKEY 는 BOR 객체별로 정해진 자리수가 있습니다. PO 는 10자리, 자재문서는 MBLNR(10) + MJAHR(4) = 14자리. 자리수 맞추지 않으면 GOS 가 객체를 찾지 못해 첨부 메뉴가 비어 있습니다.
ALV 더블 클릭마다 누적 등록
ALV 더블 클릭 이벤트에서 SWU_OBJECT_PUBLISH 를 호출하면 새 객체로 갱신되는데, 이전 객체도 메모리에 누적될 수 있습니다. 다건 시나리오에서는 첫 번째 호출 후 UNPUBLISH 단계를 명시적으로 처리하지 않아도 SAP 가 새 객체로 전환해 줍니다.
권한 / Authorization 차이
SAP 가 BOR 객체별로 표준 권한 체크를 합니다. 사용자가 PO 조회 권한은 있어도 첨부 추가 권한(S_BDS_FOLD·S_DOKU_AUT) 이 없으면 첨부 추가가 거부됩니다.
MODE 'E' 인데 ALV 가 ReadOnly
SWU_OBJECT_PUBLISH 가 'E' 모드로 등록돼도 ALV 자체가 ReadOnly 라면 헷갈릴 수 있습니다. ALV 의 행 변경과 GOS 첨부는 별개 흐름이므로 GOS 만 변경 모드로 두는 것은 정상.
Container 파라미터의 용도
CONTAINER 는 워크플로우 컨테이너 데이터 전달용입니다. 일반 첨부 시나리오에서는 비워두면 됩니다. SAP 워크플로우 / 이벤트 트리거 사용 시에만 채움.
첨부 후 화면 갱신
SWU_OBJECT_PUBLISH 호출 직후에는 GOS 메뉴가 즉시 활성화되지 않을 수 있습니다. ALV 의 PBO 가 다시 그려진 후에 메뉴가 갱신되므로 사용자에게 안내 메시지 + Enter 한 번 누르도록 가이드.
Z 객체 / 자체 BOR
회사 자체 객체에 첨부를 붙이려면 SWO1 으로 BOR 객체를 신규 정의하고 그 객체 타입을 SWU_OBJECT_PUBLISH 에 넘깁니다. 단순 ZAP* T-Code 만 만들고 표준 BUS2012 같은 BOR 만 호출하면 회사 객체 데이터에 첨부가 매핑되지 않습니다.
전체 코드 — 복사용 통합본 (ALV + 더블클릭 + GOS)
*&---------------------------------------------------------------------*
*& Report Z_XX_GOS_ALV_DEMO
*&---------------------------------------------------------------------*
*& ALV 리포트 + 더블클릭으로 GOS 첨부 메뉴 등록
*&---------------------------------------------------------------------*
REPORT z_xx_gos_alv_demo.
TYPES: BEGIN OF ty_alv_data,
atta_icon TYPE icon_d,
ebeln TYPE ekko-ebeln,
bukrs TYPE ekko-bukrs,
lifnr TYPE ekko-lifnr,
bsart TYPE ekko-bsart,
aedat TYPE ekko-aedat,
END OF ty_alv_data.
DATA: gt_alv_data TYPE TABLE OF ty_alv_data,
go_alv TYPE REF TO cl_salv_table.
PARAMETERS: p_bukrs TYPE ekko-bukrs OBLIGATORY DEFAULT '1000'.
*---------------------------------------------------------------------*
* Event Handler
*---------------------------------------------------------------------*
CLASS lcl_handler DEFINITION.
PUBLIC SECTION.
METHODS on_double_click
FOR EVENT double_click OF cl_salv_events_table
IMPORTING row column.
ENDCLASS.
CLASS lcl_handler IMPLEMENTATION.
METHOD on_double_click.
DATA ls_data TYPE ty_alv_data.
" ★ 더블클릭한 행 데이터 추출
READ TABLE gt_alv_data INTO ls_data INDEX row.
CHECK sy-subrc = 0.
" ★ 그 PO 를 GOS 객체로 등록
CALL FUNCTION 'SWU_OBJECT_PUBLISH'
EXPORTING
objtype = 'BUS2012'
objkey = ls_data-ebeln
mode = 'A'
EXCEPTIONS
objtype_not_found = 1.
IF sy-subrc <> 0.
MESSAGE 'GOS 객체 등록 실패' TYPE 'I' DISPLAY LIKE 'E'.
ELSE.
MESSAGE |GOS 메뉴 활성화: { ls_data-ebeln }. System → Services for Object 확인| TYPE 'S'.
ENDIF.
ENDMETHOD.
ENDCLASS.
*---------------------------------------------------------------------*
* Main
*---------------------------------------------------------------------*
START-OF-SELECTION.
" 1) 데이터 조회
SELECT ebeln, bukrs, lifnr, bsart, aedat
FROM ekko
INTO TABLE @DATA(lt_po)
WHERE bukrs = @p_bukrs
UP TO 200 ROWS.
" 2) ALV 데이터로 변환
gt_alv_data = VALUE #(
FOR ls_po IN lt_po
( ebeln = ls_po-ebeln
bukrs = ls_po-bukrs
lifnr = ls_po-lifnr
bsart = ls_po-bsart
aedat = ls_po-aedat ) ).
" 3) 첨부 유무 일괄 조회
IF gt_alv_data IS NOT INITIAL.
SELECT instid_a
INTO TABLE @DATA(lt_atta_keys)
FROM srgbrbrel
FOR ALL ENTRIES IN @gt_alv_data
WHERE instid_a = @gt_alv_data-ebeln
AND typeid_a = 'BUS2012'
AND catid_a = 'BO'
AND reltype = 'ATTA'.
LOOP AT gt_alv_data ASSIGNING FIELD-SYMBOL(<ls_alv>).
READ TABLE lt_atta_keys WITH KEY instid_a = <ls_alv>-ebeln
TRANSPORTING NO FIELDS.
IF sy-subrc = 0.
<ls_alv>-atta_icon = '@4P@'.
ENDIF.
ENDLOOP.
ENDIF.
" 4) ALV 표시
cl_salv_table=>factory(
IMPORTING r_salv_table = go_alv
CHANGING t_table = gt_alv_data ).
" 5) 더블클릭 이벤트 등록
DATA(lo_events) = go_alv->get_event( ).
DATA(lo_handler) = NEW lcl_handler( ).
SET HANDLER lo_handler->on_double_click FOR lo_events.
" 6) 출력
go_alv->display( ).
같이 보면 좋은 글:
- "CL_GOS_MANAGER 첨부파일 활용 — 자체 화면에 표준 GOS 서비스 끼우기" — 자체 Dynpro 시나리오용 짝꿍 글
- "BAPI_PO_CREATE1 — 구매오더 생성 BAPI 호출 방법" — PO 생성 후 GOS 자동 등록 흐름
- "BAdI 찾는 방법 5가지 — CL_EXITHANDLER 디버깅·SE84·SXS_ATTR 메타테이블" — 첨부 BAdI 확장 시 활용
요약
| 단계 | 하는 일 | 핵심 포인트 |
|---|---|---|
| 1 | OBJTYPE 결정 | 표준 BOR (BUS2012) 또는 OAC0 저장소 |
| 2 | OBJKEY 자리수 맞춤 | PO 10자리 · 자재문서 14자리 등 |
| 3 | MODE 결정 | 'A' 조회 / 'E' 편집 |
| 4 | 호출 시점 선택 | 단일 객체 → START-OF-SELECTION / 다건 → ALV 더블클릭 |
| 5 | 첨부 유무 표시 | SRGBRBREL FAE 일괄 조회 + 아이콘 컬럼 |
| 6 | 사용자 안내 | System → Services for Object 위치 안내 |
SWU_OBJECT_PUBLISH 는 ALV 리포트에 표준 GOS 첨부 메뉴를 가장 가볍게 끼워 넣는 도구입니다. OBJTYPE + OBJKEY + MODE 3개만 정확히 채우면 호출 한 번으로 ALV 의 시스템 서비스 메뉴에 GOS 가 자동 등록됩니다.
다건 시나리오는 더블클릭 이벤트에서 각 행마다 재호출, 단일 객체는 START-OF-SELECTION 에서 한 번만. 자체 Dynpro 화면에 GOS 아이콘을 직접 박을 때는 CL_GOS_MANAGER 가 더 적합하고, ALV 조회 + 메뉴 통합에는 이 FM 이 더 가볍습니다.
Disclaimer — 이 포스트는 실무 정리 노트를 바탕으로 AI 보조로 정리되었습니다.
SWU_OBJECT_PUBLISH Function Module 시그니처 · SRGBRBREL 테이블 · BOR 객체(BUS2012 등) 동작은 SAP NetWeaver 표준(패키지 SWUG / SGOS · ECC 6.0 / S/4HANA on-premise) 기준이며, Z 자체 BOR 객체 · OAC0/OAC3 저장소 설정 · 권한 그룹에 따라 일부 동작이 다를 수 있으니 운영 시스템 적용 전 개발·QA 환경에서 검증하시기 바랍니다.