ABAP 으로 자동화·인터페이스 코드를 짜다 보면 "특정 사용자 ID 의 이메일·이름·전화번호·소속 회사를 한 번에 가져오고 싶다" 는 요구가 자주 들어옵니다. 결재 시스템 연동에서 결재자 이메일이 필요할 때, 자체 알림 발송 프로그램에서 사용자 정보가 필요할 때, 로그에 사용자 풀네임을 같이 남겨야 할 때 — SAP 의 사용자 마스터 테이블(USR02·USR21·ADRP·ADR6 등) 을 직접 조인해 가져올 수도 있지만, 표준 BAPI 한 번 호출이 훨씬 깔끔합니다.
이 역할을 하는 BAPI 가 BAPI_USER_GET_DETAIL 입니다. 사용자 ID 하나 넣으면 주소·로그온 데이터·역할·프로파일·라이선스·생성자 정보까지 14개 EXPORTING 구조체 + 22개 TABLES 파라미터로 한 번에 받아옵니다. 그중 실무에서 가장 자주 쓰는 부분은 ADDRESS(이름·이메일·전화) + ADMINDATA(생성자·생성일) + COMPANY(회사) + DEFAULTS(언어·타임존) 4개. 노트의 사용 패턴과도 일치합니다.
이 글은 BAPI_USER_GET_DETAIL 의 시그니처·핵심 EXPORTING 구조체 4개·요청한 파라미터만 채워주는 동작 원리·이메일이 ADDRESS 와 ADDSMTP 두 곳에 있는 이유·관련 BAPI 패밀리까지 한 화면에 모은 메모입니다.
핵심 — EXPORTING 구조체 4개 + TABLES 통신 데이터
자주 쓰는 EXPORTING 구조체 4개로 95% 의 사용자 정보 요건이 커버됩니다.
| 파라미터 | 타입 | 담는 정보 |
|---|---|---|
ADDRESS (★) |
BAPIADDR3 |
이름(firstname/lastname) · 대표 이메일(e_mail) · 대표 전화(tel1_numbr/ext) · 부서 · 직책 |
ADMINDATA |
BAPIUSERADMIN |
생성자(aname) · 생성일(erdat) · 마지막 로그온일(trdat) |
COMPANY |
BAPIUSCOMP |
소속 회사 (company) |
DEFAULTS |
BAPIDEFAUL |
언어(langu) · 시간대(tzone) · 날짜·소수점 형식 · 프린터 · 코스트센터(kostl) |
LOGONDATA |
BAPILOGOND |
사용자 유형(ustyp) · 유효기간(gltgv/gltgb) · 클래스 |
ISLOCKED |
BAPISLOCKD |
락 상태 (관리자 락·글로벌 락·실패 로그온 락) |
ACTIVITYGROUPS (TABLES) |
BAPIAGR |
할당된 역할 목록 (agr_name) |
핵심 한 줄: 사용자 ID 만 넘기면 ADDRESS · ADMINDATA · COMPANY · DEFAULTS 4개로 99% 의 정보 요건 해결. 호출 시점에 IMPORTING 으로 받은 EXPORTING 만 BAPI 가 채워주는 패턴이라 사용 안 할 파라미터는 안 받으면 그만큼 빠릅니다.
1단계 — 기본 호출 패턴 (이메일·이름·회사 받기)
가장 단순한 케이스. 사용자 ID 하나로 풀네임 + 이메일 + 회사 받기.
DATA: ls_address TYPE bapiaddr3,
ls_admindata TYPE bapiuseradmin,
ls_company TYPE bapiuscomp,
ls_userdefault TYPE bapidefaul,
lt_return TYPE bapirettab.
CALL FUNCTION 'BAPI_USER_GET_DETAIL'
EXPORTING
username = 'TESTUSER01'
IMPORTING
address = ls_address
admindata = ls_admindata
company = ls_company
defaults = ls_userdefault
TABLES
return = lt_return.
" 결과 출력
WRITE: / |풀네임 : { ls_address-firstname } { ls_address-lastname }|,
/ |이메일 : { ls_address-e_mail }|,
/ |전화 : { ls_address-tel1_numbr } { ls_address-tel1_ext }|,
/ |회사 : { ls_company-company }|,
/ |언어 : { ls_userdefault-langu }|,
/ |시간대 : { ls_userdefault-tzone }|,
/ |생성자 : { ls_admindata-aname }|,
/ |생성일 : { ls_admindata-erdat }|.
핵심 동작:
USERNAME은 BAPI 내부에서 자동으로 대문자 변환됨 — 소문자로 넘겨도 OK- IMPORTING 으로 받은 파라미터만 BAPI 내부에서 채워줌 → 사용 안 할 것은 안 받기
CACHE_RESULTS = 'X'(기본값) 으로 같은 사용자 반복 호출 시 캐시 활용
2단계 — ADDRESS(BAPIADDR3) 의 자주 쓰는 필드
ADDRESS 구조는 BAPI 중에 가장 풍부한 정보를 담고 있어 알아두면 좋습니다.
| 필드 | 의미 |
|---|---|
FIRSTNAME · LASTNAME |
이름 / 성 |
FULLNAME |
표시용 풀네임 (한국어 환경은 보통 비어 있을 수 있음) |
E_MAIL |
대표 이메일 (SU01 에서 등록된 첫 번째) |
TEL1_NUMBR · TEL1_EXT |
대표 전화 / 내선 |
DEPARTMENT |
부서 |
FUNCTION |
직책 / 직무 |
LANGU_P |
개인 통신 언어 (이메일 발송 시 활용) |
COUNTRY · CITY |
국가 / 도시 (회사 주소 정보) |
대표 이메일 외에 사용자가 등록한 모든 이메일을 받고 싶으면 ADDRESS 가 아니라 ADDSMTP(TABLES) 를 같이 받습니다 — 다음 단계에서 다룹니다.
3단계 — 모든 이메일 목록 받기 (ADDSMTP)
ADDRESS-E_MAIL 은 한 명의 사용자의 대표 이메일 한 개. 만약 한 사용자에게 여러 이메일이 등록되어 있고 그것을 다 받으려면 ADDSMTP TABLES 파라미터를 추가로 받습니다.
DATA: lt_addsmtp TYPE TABLE OF bapiadsmtp.
CALL FUNCTION 'BAPI_USER_GET_DETAIL'
EXPORTING
username = 'TESTUSER01'
IMPORTING
address = ls_address
TABLES
addsmtp = lt_addsmtp " ★ 모든 이메일
return = lt_return.
" 대표 이메일 1개
WRITE: / |대표: { ls_address-e_mail }|.
" 등록된 모든 이메일 (R_3_USER = '1' 이 표준 이메일)
LOOP AT lt_addsmtp INTO DATA(ls_smtp).
WRITE: / |{ COND #(
WHEN ls_smtp-r_3_user = '1' THEN '★ 대표'
ELSE ' 추가'
) } { ls_smtp-e_mail }|.
ENDLOOP.
BAPIADSMTP 의 R_3_USER = '1' 인 행이 SU01 의 "Std." 박스에 체크된 표준 이메일이며, ADDRESS-E_MAIL 과 같은 값입니다. 전화(ADDTEL)·팩스(ADDFAX) 도 동일한 패턴.
4단계 — 역할(Role) · 프로파일 받기
권한 분석이나 결재선 자동 결정 같은 시나리오에서는 사용자의 역할 목록이 필요합니다.
DATA: lt_roles TYPE TABLE OF bapiagr,
lt_profiles TYPE TABLE OF bapiprof.
CALL FUNCTION 'BAPI_USER_GET_DETAIL'
EXPORTING
username = 'TESTUSER01'
TABLES
activitygroups = lt_roles " 할당된 역할 목록
profiles = lt_profiles " 할당된 프로파일
return = lt_return.
" 역할 출력
WRITE: / '=== 할당된 역할 ==='.
LOOP AT lt_roles INTO DATA(ls_role).
WRITE: / |{ ls_role-agr_name } { ls_role-from_dat } ~ { ls_role-to_dat } - { ls_role-agr_text }|.
ENDLOOP.
" 프로파일 출력
WRITE: / '=== 할당된 프로파일 ==='.
LOOP AT lt_profiles INTO DATA(ls_prof).
WRITE: / |{ ls_prof-bapiprof } - { ls_prof-bapiptext }|.
ENDLOOP.
FROM_DAT·TO_DAT 는 역할의 유효기간. 결재선 자동 결정 시 "현재 유효한 역할" 만 필터링하려면 sy-datum BETWEEN from_dat AND to_dat 분기.
5단계 — 락 상태 확인 (ISLOCKED)
자동화 프로그램에서 "락 걸린 사용자에게는 메일 보내지 않기" 같은 분기에 사용.
DATA: ls_islocked TYPE bapislockd.
CALL FUNCTION 'BAPI_USER_GET_DETAIL'
EXPORTING
username = 'TESTUSER01'
IMPORTING
islocked = ls_islocked
TABLES
return = lt_return.
" 락 상태 4종 확인
WRITE: / |로컬 락 (관리자) : { ls_islocked-local_lock }|, " L = Locked, U = Unlocked
/ |글로벌 락 (CUA) : { ls_islocked-glob_lock }|,
/ |실패 로그온 락 : { ls_islocked-wrng_logon }|,
/ |비밀번호 비활성 : { ls_islocked-no_user_pw }|.
" 전체 락 여부 한 줄 판단
IF ls_islocked-local_lock = 'L'
OR ls_islocked-glob_lock = 'L'
OR ls_islocked-wrng_logon = 'L'
OR ls_islocked-no_user_pw = 'L'.
WRITE: / '❌ 이 사용자는 락 상태입니다 — 자동 처리 제외'.
ENDIF.
BAPISLOCKD 의 4개 락 필드 중 하나라도 'L'(Locked) 이면 사용자가 로그온 불가 상태. 'U'(Unlocked) 가 정상.
6단계 — BAPI 호출 결과 메시지 처리
RETURN 테이블에서 에러·경고 메시지 분리.
" 사용자 존재 안 함 / 권한 없음 / 락 등 에러 분리
READ TABLE lt_return INTO DATA(ls_return) WITH KEY type = 'E'.
IF sy-subrc = 0.
WRITE: / |❌ 조회 실패: { ls_return-message }|.
RETURN.
ENDIF.
" 경고 메시지도 같이 확인
LOOP AT lt_return INTO ls_return WHERE type CA 'EWAI'.
WRITE: / |[{ ls_return-type }] { ls_return-message }|.
ENDLOOP.
자주 만나는 RETURN 메시지:
- 사용자 없음 —
'User XXX does not exist' - 권한 없음 —
'No authorization to display users'(S_USER_GRP권한 객체 필요) - 주소 정보 부분 누락 — 경고(
'W') 로 들어옴 / 다른 필드는 정상
7단계 — 관련 BAPI 패밀리
BAPI_USER_GET_DETAIL 은 단일 사용자 조회. 다른 시나리오에는 다른 BAPI 가 표준입니다.
| BAPI | 용도 |
|---|---|
BAPI_USER_GETLIST |
사용자 목록 검색 (조건별 필터링 — 부서·이름·이메일 등) |
BAPI_USER_EXISTENCE_CHECK |
사용자 존재 여부만 빠르게 확인 (가벼움) |
BAPI_USER_CREATE1 |
사용자 신규 생성 |
BAPI_USER_CHANGE |
사용자 정보 변경 (BATCHATTRIBUTESX 같은 X-구조체 패턴 사용) |
BAPI_USER_LOCK · BAPI_USER_UNLOCK |
사용자 락 / 해제 |
BAPI_USER_PROFILES_ASSIGN |
프로파일 할당 |
BAPI_USER_ACTGROUPS_ASSIGN |
역할(Activity Group) 할당 |
대량 조회는 BAPI_USER_GETLIST 로 후보 사용자 ID 를 먼저 받고, 각 사용자 상세는 BAPI_USER_GET_DETAIL 로 보조하는 패턴이 표준.
흔히 빠뜨리는 함정
RETURN 안 보고 다음 단계 진행
CALL FUNCTION 'BAPI_USER_GET_DETAIL' ...
" ❌ lt_return 안 보고 ls_address-e_mail 바로 사용
SEND MAIL TO ls_address-e_mail.
사용자가 존재하지 않으면 ls_address 가 비어 있어 빈 이메일로 발송 시도됨. RETURN 의 TYPE = 'E' 체크 필수.
S_USER_GRP 권한 누락
자동화 프로그램 실행 사용자에게 S_USER_GRP (Activity 03 = Display) 권한이 없으면 BAPI 가 RETURN 에 권한 에러를 채워 돌려줍니다. 자동 잡 / RFC 호출용 사용자에게 이 권한 미리 부여.
대문자/소문자 혼동
username = 'testuser01'. " 소문자
" → BAPI 가 내부에서 'TESTUSER01' 로 변환해 처리
" → 결과는 정상이지만 다른 코드에서 sy-uname 비교 시 헷갈림
BAPI 내부에서 자동으로 대문자 변환됨. 호출 측에서 명시적으로 TRANSLATE ... TO UPPER CASE 후 호출하는 패턴이 안전.
CACHE_RESULTS 의 효과 무시
" ❌ LOOP 안에서 같은 사용자 N 번 호출 — 캐시 효과 제대로 활용 X
LOOP AT lt_users INTO lv_user.
CALL FUNCTION 'BAPI_USER_GET_DETAIL'
EXPORTING username = lv_user
cache_results = ' '. " ❌ 캐시 끔
ENDLOOP.
CACHE_RESULTS = 'X'(기본) 유지하면 같은 사용자에 대한 반복 호출이 빠릅니다. 명시적으로 끄지 마세요.
ADDRESS-E_MAIL 하나만 보고 끝
사용자에게 여러 이메일이 등록된 경우 ADDRESS 의 E_MAIL 은 그중 표준 한 개. 다른 이메일이 필요하면 ADDSMTP 도 같이 받기.
락 상태 무시한 자동 발송
이메일 발송 자동화에서 락 걸린 사용자한테까지 발송하면 의미 없는 메일이 쌓이거나 그룹웨어 측 에러. ISLOCKED 체크 후 분기.
한국어 환경 FULLNAME 비어있음
" ❌ 풀네임을 FULLNAME 으로만 받음 → 빈 값
WRITE: / ls_address-fullname.
" ✅ 한국어 환경에서는 LASTNAME + FIRSTNAME 조합
WRITE: / |{ ls_address-lastname }{ ls_address-firstname }|.
한국어 사용자 마스터는 FULLNAME 이 비어 있는 경우가 흔합니다. LASTNAME + FIRSTNAME 조합으로 직접 만드는 게 안전. 영어 환경은 보통 자동 조합되어 있음.
전체 코드 — 복사용 통합본
자주 쓰는 4개 정보(이메일·이름·회사·역할) + 락 상태 + 메시지 처리 한 사이클.
REPORT zr_user_detail_demo.
PARAMETERS p_uname TYPE bapibname-bapibname OBLIGATORY DEFAULT sy-uname.
DATA: ls_address TYPE bapiaddr3,
ls_admin TYPE bapiuseradmin,
ls_company TYPE bapiuscomp,
ls_default TYPE bapidefaul,
ls_locked TYPE bapislockd,
lt_smtp TYPE TABLE OF bapiadsmtp,
lt_roles TYPE TABLE OF bapiagr,
lt_return TYPE bapirettab,
ls_return TYPE bapiret2.
" === BAPI 호출 ===
CALL FUNCTION 'BAPI_USER_GET_DETAIL'
EXPORTING
username = p_uname
IMPORTING
address = ls_address
admindata = ls_admin
company = ls_company
defaults = ls_default
islocked = ls_locked
TABLES
addsmtp = lt_smtp
activitygroups = lt_roles
return = lt_return.
" === 에러 체크 ===
READ TABLE lt_return INTO ls_return WITH KEY type = 'E'.
IF sy-subrc = 0.
WRITE: / |❌ 조회 실패: { ls_return-message }|.
RETURN.
ENDIF.
" === 기본 정보 ===
WRITE: / '=== 사용자 정보 ===',
/ |ID : { p_uname }|,
/ |이름 : { ls_address-lastname }{ ls_address-firstname }|,
/ |대표 이메일 : { ls_address-e_mail }|,
/ |전화 : { ls_address-tel1_numbr } { ls_address-tel1_ext }|,
/ |부서 : { ls_address-department }|,
/ |직책 : { ls_address-function }|,
/ |회사 : { ls_company-company }|,
/ |언어 : { ls_default-langu }|,
/ |시간대 : { ls_default-tzone }|,
/ |코스트센터 : { ls_default-kostl }|.
" === 생성자 정보 ===
WRITE: /, / '=== 관리 정보 ===',
/ |생성자 : { ls_admin-aname }|,
/ |생성일 : { ls_admin-erdat }|,
/ |마지막 로그온 : { ls_admin-trdat }|.
" === 락 상태 ===
WRITE: /, / '=== 락 상태 ===',
/ |로컬 락(관리자) : { ls_locked-local_lock }|,
/ |글로벌 락(CUA) : { ls_locked-glob_lock }|,
/ |실패 로그온 락 : { ls_locked-wrng_logon }|,
/ |비밀번호 비활성 : { ls_locked-no_user_pw }|.
IF ls_locked-local_lock = 'L'
OR ls_locked-glob_lock = 'L'
OR ls_locked-wrng_logon = 'L'
OR ls_locked-no_user_pw = 'L'.
WRITE: / |⚠️ 이 사용자는 락 상태입니다 — 자동 처리 시 제외 검토|.
ENDIF.
" === 등록된 모든 이메일 ===
WRITE: /, / '=== 등록된 이메일 목록 ==='.
LOOP AT lt_smtp INTO DATA(ls_smtp).
WRITE: / | { COND #(
WHEN ls_smtp-r_3_user = '1' THEN '★'
ELSE '·'
) } { ls_smtp-e_mail }|.
ENDLOOP.
" === 할당된 역할 ===
WRITE: /, / '=== 할당된 역할 ==='.
LOOP AT lt_roles INTO DATA(ls_role)
WHERE from_dat <= sy-datum
AND to_dat >= sy-datum. " 현재 유효한 역할만
WRITE: / | { ls_role-agr_name } - { ls_role-agr_text }|.
ENDLOOP.
" === 경고 메시지 ===
LOOP AT lt_return INTO ls_return WHERE type = 'W'.
WRITE: / |⚠️ { ls_return-message }|.
ENDLOOP.
이 미니 리포트를 SE38 에 그대로 붙이고 실행하면 사용자 ID 만 입력해서 풀 정보를 한 번에 받을 수 있습니다. 결재 시스템 / 알림 발송 / 사용자 분석 같은 자동화에 그대로 응용 가능.
요약
| 단계 | 파라미터 | 핵심 |
|---|---|---|
| 1 | ADDRESS | 이름·이메일·전화·부서·직책 (가장 자주 쓰는 한 구조체) |
| 2 | ADMINDATA | 생성자·생성일·마지막 로그온일 |
| 3 | COMPANY + DEFAULTS | 소속 회사 · 언어 · 시간대 · 코스트센터 |
| 4 | ADDSMTP | 모든 이메일 (R_3_USER='1' 이 표준) |
| 5 | ACTIVITYGROUPS + PROFILES | 할당된 역할·프로파일 (유효기간 확인) |
| 6 | ISLOCKED | 4종 락 상태 ('L' / 'U') — 자동 발송 분기에 활용 |
| 7 | RETURN | TYPE = 'E' 체크 필수 / 'W' 는 부분 누락 경고 |
BAPI_USER_GET_DETAIL 은 SAP 사용자 정보를 한 번에 가져오는 가장 깔끔한 방법입니다. USR02/USR21/ADRP/ADR6 같은 테이블을 직접 조인하는 코드는 SAP 버전·필드 변경에 약하지만, 이 BAPI 는 SAP 가 호환성을 보장합니다. ADDRESS · ADMINDATA · COMPANY · DEFAULTS 네 EXPORTING 만 익숙해지면 결재 자동화 / 메일 발송 / 권한 분석 같은 시나리오에 그대로 재사용 가능. IMPORTING 으로 받은 파라미터만 BAPI 가 채워주는 동작 원리를 이해하면, 필요한 정보만 받아 호출 비용도 줄일 수 있습니다.
Disclaimer — 이 포스트는 실무 정리 노트를 바탕으로 AI 보조로 정리되었습니다.
BAPI_USER_GET_DETAIL 은 SAP NetWeaver 표준 BAPI(Function Group SU_USER, Package SUSR) 로 ECC 6.0 / S/4HANA on-premise 환경에서 동일하게 동작합니다. 호출 사용자에게 S_USER_GRP 권한 객체(Activity 03 = Display) 가 부여되어 있어야 사용자 정보 조회가 가능하며, 권한이 없으면 RETURN 테이블에 에러 메시지가 채워집니다.
ADDRESS 구조(BAPIADDR3) 의 FULLNAME 필드는 한국어 환경에서 비어 있는 경우가 흔하므로 LASTNAME + FIRSTNAME 조합으로 직접 구성하는 것이 안전합니다. 호출 시 IMPORTING 으로 받지 않은 EXPORTING 구조체는 BAPI 내부에서 채우지 않으므로(IS SUPPLIED 분기) 필요한 정보만 받는 것이 성능 면에서 권장됩니다. 본문의 사용자 ID(TESTUSER01) 는 일반화한 예시이며, 사내 환경에서는 실제 사용자 ID 로 교체하여 사용하시기 바랍니다.