글의 목적과 확인 포인트
이 글은 SAP S/4HANA 환경에서 판매 조직(Sales Organization) 마스터 데이터를 조회할 때 전통적인 TVKO 테이블 대신 I_SalesOrganization CDS 뷰를 사용하는 방법을 다룹니다. S/4HANA로 전환한 조직에서는 클래식 SD 테이블 접근이 아니라 Virtual Data Model(VDM) 계층의 기본(Basic) 뷰를 활용하는 접근이 권장되며, 이 글은 그 실질적인 이유와 코드 레벨의 구현을 함께 설명합니다.
- I_SalesOrganization의 위치와 역할 이해
- TVKO 직접 SELECT 대비 CDS 접근의 이점 파악
- 기본 SELECT부터 클래스 캡슐화, 필터/조인까지 3단계 실습
- 권한(DCL), 언어 텍스트, 성능 튜닝 관점 검토
- 흔한 실수와 해결책, 후속 학습 방향 정리
사전에 알고 있어야 할 내용
ABAP Open SQL 기본 문법(SELECT, INTO TABLE, WHERE), CDS 뷰의 기본 구조와 어노테이션 개념, SAP GUI/ADT(Eclipse ABAP Development Tools) 사용 경험이 있으면 좋습니다. 판매 조직(VKORG)이 조직 구조에서 어떤 계층에 위치하는지에 대한 SD 모듈의 기초 이해도 도움이 됩니다. RAP나 BOPF 지식은 필수가 아닙니다.
환경, 버전, 준비 도구
다음 환경을 기준으로 설명합니다. 온프레미스 S/4HANA 2022 이상 또는 S/4HANA Cloud Public Edition(2023 이후) 릴리스에서 동일한 뷰명을 확인할 수 있으며, 이전 릴리스에서는 필드 일부가 다를 수 있습니다.
- SAP S/4HANA 2022 FPS02 이상(온프레미스) 또는 S/4HANA Cloud 최신 릴리스
- ABAP Platform 2022 이상, ABAP for Cloud Development(RAP) 프로파일 지원
- ADT(Eclipse) 최신 버전 또는 SAP GUI 7.70+ (SE11, SE16N, SE38)
- 테스트용 클라이언트에 최소 하나 이상의 판매 조직이 정의되어 있어야 함(SPRO → Enterprise Structure → Definition → Sales and Distribution)
- 권한: S_DEVELOP(개발), S_TABU_DIS(TVKO 비교용), 그리고 CDS 접근용 DCL 역할
온프레미스에서는 클래식 SELECT도 여전히 가능하지만, ABAP for Cloud Development(스티어드 개발 모델)에서는 화이트리스트되지 않은 테이블 접근이 차단되므로 CDS 접근이 사실상 유일한 표준 경로가 됩니다.
핵심 개념과 동작 원리
SAP의 Virtual Data Model은 데이터베이스 테이블 위에 놓인 3계층 구조입니다. 가장 아래에 Basic View가 있고, 그 위에 Composite View, 최상단에 Consumption View가 놓입니다. I_SalesOrganization은 접두어 I_가 알려주듯 Basic 계층(Interface View)에 해당하며, 판매 조직 마스터 정보를 여러 언어/시점/버전 논리와 결합해 노출하는 재사용 인터페이스입니다.
TVKO는 물리 테이블로서 판매 조직 코드와 통화, 회사 코드 정도의 최소 필드만 갖고 있고, 텍스트는 TVKOT, 조직 할당은 TVKOV/TVTA 등으로 흩어져 있습니다. 개발자가 매번 이 조각들을 JOIN해야 합니다.
반면 I_SalesOrganization은 판매 조직 코드, 통화, 회사 코드, 언어별 이름(SalesOrganizationName)까지 한 번의 SELECT로 얻을 수 있게 미리 조립되어 있습니다. 비유하자면 TVKO는 "부품 상자"이고, I_SalesOrganization은 "이미 조립된 완제품"입니다. 소비자는 언제나 완제품을 참조해야 SAP가 하부 테이블을 개편하더라도 애플리케이션이 깨지지 않습니다.
또한 CDS 뷰에는 검색 도움말(Search Help), 확장 가능성(Extension), 접근 제어(DCL, Data Control Language)가 어노테이션으로 붙어 있어, ABAP 코드는 별도의 처리 없이도 언어 자동 필터링, 세션 클라이언트 자동 반영, 사용자 권한 자동 적용이라는 이점을 얻습니다.
1단계 - 기본 SELECT 예제
가장 단순한 형태로 특정 회사 코드에 속한 판매 조직 목록을 가져옵니다. TVKO 직접 SELECT와 비교해 코드가 얼마나 간결한지 확인해 보세요.
REPORT zdemo_salesorg_read.
DATA: lt_sales_org TYPE TABLE OF i_salesorganization,
ls_sales_org LIKE LINE OF lt_sales_org.
* CDS 뷰를 통해 회사 코드 '1010'에 속한 판매 조직 조회
SELECT salesorganization,
salesorganizationname,
companycode,
salesorganizationcurrency
FROM i_salesorganization
WHERE companycode = '1010'
ORDER BY salesorganization
INTO CORRESPONDING FIELDS OF TABLE @lt_sales_org.
LOOP AT lt_sales_org INTO ls_sales_org.
WRITE: / ls_sales_org-salesorganization,
ls_sales_org-salesorganizationname,
ls_sales_org-salesorganizationcurrency.
ENDLOOP.
여기서 주목할 점은 두 가지입니다. 첫째, salesorganizationname이 별도 JOIN 없이 이미 결과에 포함됩니다. 뷰 내부에서 언어(sy-langu) 기반 텍스트 조인이 자동 수행됩니다. 둘째, 클라이언트 컬럼(MANDT)은 신경 쓸 필요가 없습니다. VDM 계층에서 이미 클라이언트 처리가 완료됩니다.
2단계 - 클래스 캡슐화와 예외 처리
실무에서는 조회 로직을 클래스로 감싸 재사용성과 테스트 가능성을 확보합니다. 아래는 판매 조직 조회 전담 클래스로, 존재하지 않는 조직을 요청받았을 때 명확한 예외를 던지고, 접근 로그를 애플리케이션 로그(BAL)에 남기는 형태입니다.
CLASS zcl_sales_org_reader DEFINITION
PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES: BEGIN OF ty_sales_org,
sales_org TYPE i_salesorganization-salesorganization,
sales_org_name TYPE i_salesorganization-salesorganizationname,
company_code TYPE i_salesorganization-companycode,
currency TYPE i_salesorganization-salesorganizationcurrency,
END OF ty_sales_org.
TYPES tt_sales_org TYPE STANDARD TABLE OF ty_sales_org WITH EMPTY KEY.
METHODS get_by_company_code
IMPORTING iv_company_code TYPE bukrs
RETURNING VALUE(rt_result) TYPE tt_sales_org
RAISING cx_sy_open_sql_db.
METHODS get_single
IMPORTING iv_sales_org TYPE vkorg
RETURNING VALUE(rs_result) TYPE ty_sales_org
RAISING zcx_sales_org_not_found.
ENDCLASS.
CLASS zcl_sales_org_reader IMPLEMENTATION.
METHOD get_by_company_code.
SELECT salesorganization AS sales_org,
salesorganizationname AS sales_org_name,
companycode AS company_code,
salesorganizationcurrency AS currency
FROM i_salesorganization
WHERE companycode = @iv_company_code
ORDER BY salesorganization
INTO TABLE @rt_result.
ENDMETHOD.
METHOD get_single.
SELECT SINGLE
salesorganization AS sales_org,
salesorganizationname AS sales_org_name,
companycode AS company_code,
salesorganizationcurrency AS currency
FROM i_salesorganization
WHERE salesorganization = @iv_sales_org
INTO @rs_result.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE zcx_sales_org_not_found
EXPORTING sales_org = iv_sales_org.
ENDIF.
ENDMETHOD.
ENDCLASS.
이 패턴의 장점은 호출자가 CDS 뷰명이나 필드 매핑을 몰라도 도메인 언어로 조회를 요청할 수 있다는 점입니다. 나중에 I_SalesOrganization의 상위 뷰인 I_SalesArea로 교체하거나 확장 뷰로 이동해도 인터페이스는 그대로 유지됩니다.
3단계 - 필터/조인과 프로덕션 고려
실무에서는 판매 조직 단독보다 판매 문서, 판매 지역과 결합해 사용하는 경우가 많습니다. 아래는 판매 문서(I_SalesOrder)와 조인하여 회사 코드별 판매 조직 이름을 함께 표시하는 예제입니다.
SELECT so~salesorder,
so~salesorganization,
org~salesorganizationname,
org~salesorganizationcurrency,
so~totalnetamount
FROM i_salesorder AS so
INNER JOIN i_salesorganization AS org
ON so~salesorganization = org~salesorganization
WHERE so~creationdate >= @lv_cutoff_date
AND org~companycode = @iv_company_code
ORDER BY so~creationdate DESCENDING
INTO TABLE @DATA(lt_order_with_org)
UP TO 500 ROWS.
프로덕션 코드에서는 다음 사항을 추가로 점검하세요.
- DCL 권한 적용:
I_SalesOrganization은 표준 DCL이 부착되어 있어, 사용자가 접근 권한 없는 판매 조직은 결과에서 자동으로 배제됩니다. WHERE 조건과 별개로 권한 필터가 동작한다는 점을 인지해야 결과 건수 불일치 이슈에 당황하지 않습니다. - 대량 조회 시 UP TO/PACKAGE SIZE: 판매 조직 자체는 수십~수백 건이지만, 조인 대상이 판매 문서라면 결과가 폭발적으로 늘어납니다. 반드시 상한을 두거나 커서 처리하세요.
- 테스트 더블: ABAP Unit에서
i_salesorganization을 대체할 때는CDS Test Double Framework(cl_cds_test_environment)를 사용해 테스트 데이터를 주입합니다. 실제 DB를 건드리지 않고 순수 로직만 검증할 수 있습니다. - 모니터링: HANA DB에서 CDS 뷰는 컬럼 스토어에 최적화되어 있지만, 어노테이션
@AbapCatalog.buffering.status: #NOT_ALLOWED가 걸린 뷰는 테이블 버퍼링이 되지 않습니다. 빈번 조회 시에는 애플리케이션 레벨 캐시(Shared Objects 등)를 고려하세요.
자주 겪는 실수와 해결책
Q1. TVKO를 그대로 SELECT하면 안 되나요?
온프레미스 커스텀 개발에서는 문법적으로 가능하지만, S/4HANA 전환 가이드에서 클래식 테이블 직접 접근은 지양하도록 안내됩니다. 특히 ABAP Cloud 개발 모델에서는 릴리스 컨트랙트에 포함된 CDS 뷰만 접근 가능하므로 TVKO 접근이 컴파일 단계에서 차단됩니다.
Q2. 판매 조직 텍스트가 빈 값으로 나옵니다. 왜 그런가요?
salesorganizationname은 로그온 언어(sy-langu) 기준으로 조인됩니다. 해당 언어로 텍스트가 유지관리되지 않은 조직은 이름이 공란이 됩니다. 다국어 조회가 필요하면 텍스트 전용 뷰인 I_SalesOrganizationText를 직접 조인해 원하는 Language 조건을 명시하세요.
Q3. 예상보다 결과 건수가 적습니다.
앞서 언급한 DCL 권한 필터가 원인인 경우가 많습니다. ADT의 Data Preview에서 뷰를 열 때 나오는 결과는 개발자 권한이 반영된 결과입니다. 실제 실행 사용자 컨텍스트로 확인하려면 해당 사용자로 로그인해 테스트하거나, 관리자에게 DCL 역할 매핑을 요청하세요.
Q4. 성능이 느려요.
WHERE 조건 없이 전체 스캔을 하는 경우가 많습니다. SalesOrganization 또는 CompanyCode를 반드시 필터에 넣고, 필요한 컬럼만 명시적으로 SELECT하는 것이 권장됩니다. SELECT *는 텍스트 조인까지 전부 수행하므로 피해야 합니다.
이후 학습해 볼 주제
이 글의 내용을 확장하려면 다음 주제를 순서대로 살펴보길 권장합니다. 첫째, I_SalesArea와 I_SalesOrganizationText를 활용해 유통 채널/판매 부문까지 아우르는 조회 로직을 구성해 보세요. 둘째, RAP 기반의 사용자 정의 서비스에서 이 뷰를 Value Help로 사용하는 방법을 익히면 Fiori Elements에서 검색 도움말이 자동으로 동작합니다. 셋째, CDS Test Double Framework를 도입해 조회 로직의 단위 테스트를 구현하면 리팩터링 안전성이 크게 향상됩니다.
더 읽을 문서와 링크
- SAP S/4HANA on-premise 도움말 포털 - VDM 계층 및 표준 뷰 문서
- ABAP Platform - ABAP CDS Views 개발자 가이드
- SAP S/4HANA Cloud 도움말 포털 - Public Cloud에서의 릴리스된 뷰 목록
- SAP API Business Hub - Sales Organization 관련 OData 서비스 검색
- SAP Community - ABAP 및 CDS 토픽 - 실무 사례 및 Q&A
- SAP Blogs - Virtual Data Model 태그 - VDM 설계 원칙 관련 블로그 시리즈
댓글 0
아직 댓글이 없습니다.