📖 개요 — 이 글에서 다루는 것
SAP ERP 시절부터 유통 채널(Distribution Channel)은 TVTW 테이블에 저장되고, 텍스트는 TVTWT에서 별도로 조회하는 방식이 일반적이었습니다. S/4HANA(온프레미스 및 Cloud 에디션)에서는 이 방식 대신 VDM(Virtual Data Model) 기반 CDS 뷰인 I_DistributionChannel을 통해 표준화된 방식으로 접근하는 것이 권장됩니다. 이 글은 초급 ABAP 개발자를 대상으로, TVTW 직접 조회에서 벗어나 CDS 뷰 기반 조회로 전환하는 방법을 실전 예제 중심으로 설명합니다.
- TVTW 직접 접근이 왜 문제가 되는지 이해한다
I_DistributionChannel의 구조와 텍스트 어소시에이션을 파악한다- 기본 조회 → 실무 시나리오 → 프로덕션 수준 코드까지 3단계로 작성해 본다
- 영업 조직과 유통 채널 조합으로 가격 정책을 조회하는 패턴을 익힌다
📚 미리 알아두면 좋은 배경
ABAP의 기본 SELECT 구문과 내부 테이블 처리 경험이 있으면 충분합니다. SD(Sales and Distribution) 모듈에서 영업 조직(Sales Organization), 유통 채널, 제품군(Division)이 영업 영역(Sales Area)을 구성한다는 개념을 알고 있다면 실무 시나리오를 더 빠르게 이해할 수 있습니다. CDS 뷰를 직접 만들어 본 경험은 없어도 됩니다.
🔧 환경과 준비물
이 글의 예제는 다음 환경을 기준으로 작성되었습니다.
- 시스템: SAP S/4HANA 2022 이상(온프레미스) 또는 SAP S/4HANA Cloud.
I_DistributionChannel은 두 에디션 모두에서 릴리스된 인터페이스 뷰입니다. - 개발 도구: ABAP Development Tools(ADT) for Eclipse — CDS 뷰의 정의와 어소시에이션을 확인하려면 ADT가 사실상 필수입니다. SE80/SE38에서도 SELECT 자체는 동작합니다.
- 확인 방법: ADT에서
Ctrl+Shift+A로I_DistributionChannel을 열어 릴리스 계약(Release Contract, 일반적으로 C1 - Use in Cloud Development)을 확인해 두는 것이 좋습니다. - 테스트 데이터: 예제에서는 유통 채널
10(직판),30(온라인) 등을 가정합니다. 실제 값은 시스템 구성(SPRO)에 따라 다릅니다.
💡 핵심 개념 — TVTW에서 I_DistributionChannel로
비유하자면 TVTW를 직접 조회하는 것은 식당 주방에 들어가 냉장고를 직접 여는 것과 같습니다. 지금 당장은 재료를 꺼낼 수 있지만, 주방 구조가 바뀌면(업그레이드) 내 코드는 깨집니다. 반면 I_DistributionChannel은 주문 카운터입니다. 주방 내부가 어떻게 바뀌든 카운터의 메뉴판(필드 이름과 시맨틱)은 안정적으로 유지됩니다.
TVTW 직접 접근의 문제점
- 의존성: 물리 테이블 구조에 코드가 직접 묶여, SAP 내부 구조 변경 시 영향을 받습니다.
- 텍스트 처리 이원화: 채널 이름을 얻으려면
TVTWT를 언어 키(SPRAS)와 함께 별도 조인해야 하며, 이 로직이 프로그램마다 중복됩니다. - 업그레이드 위험: 클라우드 환경에서는 릴리스되지 않은 테이블 직접 접근이 아예 제한되며, 온프레미스에서도 Clean Core 관점에서 지양됩니다.
I_DistributionChannel의 구조
I_DistributionChannel은 VDM의 Basic Interface View로, 데이터 소스는 TVTW이지만 필드 이름이 시맨틱하게 재정의되어 있습니다.
| 구분 | 전통 방식 | CDS 방식 |
|---|---|---|
| 테이블/뷰 | TVTW | I_DistributionChannel |
| 키 필드 | VTWEG | DistributionChannel |
| 텍스트 | TVTWT-VTEXT 수동 조인 | _Text 어소시에이션 (I_DistributionChannelText) |
| 언어 처리 | SPRAS = sy-langu 직접 작성 | Language 필드 필터 또는 로그온 언어 자동 처리 |
핵심은 어소시에이션입니다. CDS 뷰는 텍스트 뷰 I_DistributionChannelText를 _Text라는 이름으로 미리 연결해 두었기 때문에, 조인 조건을 매번 작성할 필요 없이 경로 표현식(\_Text-DistributionChannelName)으로 접근할 수 있습니다. 이것이 VDM이 말하는 "재사용 가능한 데이터 모델"의 실체이며, 개발자 간 코드 일관성을 만들어 줍니다.
💻 실전 코드 3단계
1단계 — 기본 조회: TVTW 없이 유통 채널 읽기
가장 단순한 형태부터 시작합니다. 아래는 시스템에 정의된 모든 유통 채널을 CDS 뷰로 읽는 예제입니다.
REPORT zdemo_dist_channel_basic.
" 전통 방식(지양): SELECT vtweg FROM tvtw INTO TABLE @DATA(lt_old).
" CDS 방식(권장):
SELECT DistributionChannel
FROM I_DistributionChannel
ORDER BY DistributionChannel
INTO TABLE @DATA(lt_channels).
LOOP AT lt_channels INTO DATA(ls_channel).
cl_demo_output=>write( |채널 코드: { ls_channel-DistributionChannel }| ).
ENDLOOP.
cl_demo_output=>display( ).
텍스트가 필요하면 어소시에이션 경로를 사용합니다. 로그온 언어의 채널 이름을 함께 가져오는 예제입니다.
SELECT dc~DistributionChannel,
dc~\_Text-DistributionChannelName AS ChannelName
FROM I_DistributionChannel AS dc
WHERE dc~\_Text-Language = @sy-langu
ORDER BY dc~DistributionChannel
INTO TABLE @DATA(lt_channel_texts).
TVTWT를 언급조차 하지 않고 언어별 텍스트를 얻었다는 점에 주목하세요. 조인 조건은 CDS 모델 안에 이미 정의되어 있습니다.
2단계 — 실무 시나리오: 영업 조직 + 유통 채널 조합으로 가격 정책 판정
실무에서는 유통 채널 단독보다 영업 조직과의 조합이 중요합니다. 아래 예제는 온라인 채널 주문에 대해 채널 유효성을 검증하고, 조합별 가격 정책 코드를 결정하는 서비스 메서드입니다. 존재하지 않는 채널이 들어오면 예외를 발생시키고 로그를 남깁니다.
CLASS zcl_channel_pricing_svc DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
METHODS get_pricing_policy
IMPORTING iv_sales_org TYPE vkorg
iv_dist_channel TYPE vtweg
RETURNING VALUE(rv_policy) TYPE string
RAISING zcx_channel_not_found.
ENDCLASS.
CLASS zcl_channel_pricing_svc IMPLEMENTATION.
METHOD get_pricing_policy.
" 1) 유통 채널 존재 여부를 CDS 뷰로 검증
SELECT SINGLE DistributionChannel,
\_Text[ Language = @sy-langu ]-DistributionChannelName AS ChannelName
FROM I_DistributionChannel
WHERE DistributionChannel = @iv_dist_channel
INTO @DATA(ls_channel).
IF sy-subrc <> 0.
" 애플리케이션 로그 기록 후 예외
DATA(lo_log) = cl_bali_log=>create_with_header(
header = cl_bali_header_setter=>create(
object = 'ZSD_CHANNEL'
subobject = 'VALIDATION' ) ).
lo_log->add_item( cl_bali_free_text_setter=>create(
severity = if_bali_constants=>c_severity_error
text = |유통 채널 { iv_dist_channel } 미존재| ) ).
cl_bali_log_db=>get_instance( )->save_log( lo_log ).
RAISE EXCEPTION TYPE zcx_channel_not_found
EXPORTING channel = iv_dist_channel.
ENDIF.
" 2) 영업조직 + 채널 조합으로 가격 정책 결정 (커스텀 정책 테이블)
SELECT SINGLE pricing_policy
FROM zsd_channel_policy
WHERE sales_org = @iv_sales_org
AND dist_channel = @iv_dist_channel
INTO @rv_policy.
IF sy-subrc <> 0.
rv_policy = 'STANDARD'. " 조합 미정의 시 기본 정책
ENDIF.
ENDMETHOD.
ENDCLASS.
여기서 눈여겨볼 부분은 \_Text[ Language = @sy-langu ] 필터드 어소시에이션 문법입니다. 조인 카디널리티를 명시적으로 1건으로 좁혀 주기 때문에 SELECT SINGLE과 함께 안전하게 사용할 수 있습니다.
3단계 — 프로덕션: 성능, 테스트 가능성, 보안
프로덕션 코드에서는 세 가지를 추가로 고려합니다. 첫째, 성능 — 필요한 필드만 명시하고, 다건 검증은 FOR ALL ENTRIES 대신 범위 조건이나 조인으로 DB에 위임합니다. 둘째, 테스트 — CDS Test Double Framework로 뷰를 모킹하면 실제 TVTW 데이터 없이 단위 테스트가 가능합니다. 셋째, 보안 — 릴리스된 CDS 뷰는 접근 제어(DCL)가 함께 적용될 수 있으므로 권한 설계가 단순해집니다.
CLASS ltc_channel_pricing DEFINITION FINAL FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
CLASS-DATA go_env TYPE REF TO if_cds_test_environment.
METHODS: setup,
valid_channel_returns_policy FOR TESTING.
ENDCLASS.
CLASS ltc_channel_pricing IMPLEMENTATION.
METHOD setup.
" I_DistributionChannel을 테스트 더블로 대체
go_env = cl_cds_test_environment=>create(
i_for_entity = 'I_DISTRIBUTIONCHANNEL' ).
DATA(lt_mock) = VALUE ztt_dist_channel_mock(
( DistributionChannel = '30' ) ). " 온라인 채널만 존재한다고 가정
go_env->insert_test_data( i_data = lt_mock ).
ENDMETHOD.
METHOD valid_channel_returns_policy.
DATA(lo_cut) = NEW zcl_channel_pricing_svc( ).
DATA(lv_policy) = lo_cut->get_pricing_policy(
iv_sales_org = '1010'
iv_dist_channel = '30' ).
cl_abap_unit_assert=>assert_not_initial( lv_policy ).
ENDMETHOD.
ENDCLASS.
TVTW를 직접 조회하는 코드였다면 이런 모킹이 불가능하거나 OSQL Test Double로 우회해야 합니다. 릴리스된 CDS 뷰를 데이터 접근 계층으로 삼는 것만으로 테스트 전략이 한 단계 깔끔해집니다. 또한 다건 조회 시에는 아래처럼 한 번의 왕복으로 처리해 네트워크 비용을 줄입니다.
" 주문 목록의 채널을 한 번에 검증 (건별 SELECT SINGLE 반복 금지)
SELECT DISTINCT dc~DistributionChannel
FROM I_DistributionChannel AS dc
FOR ALL ENTRIES IN @lt_orders
WHERE dc~DistributionChannel = @lt_orders-dist_channel
INTO TABLE @DATA(lt_valid_channels).
⚠️ 흔한 실수와 트러블슈팅
Q1. 어소시에이션 필드를 SELECT했는데 구문 오류가 납니다.
경로 표현식은
\_Text-필드명처럼 백슬래시로 시작해야 하며, ABAP SQL(7.50 이상)에서만 지원됩니다. 구버전 Open SQL 문법이나 낮은 릴리스에서는I_DistributionChannelText를 명시적으로 조인하세요.
Q2. 텍스트가 여러 건 중복되어 나옵니다.
언어 필터를 빼먹은 경우입니다. 텍스트 뷰는 언어별로 1행씩 존재하므로
Language = @sy-langu조건 또는 필터드 어소시에이션\_Text[ Language = $session.system_language ]를 반드시 지정해야 합니다.
Q3. 조회 결과가 0건인데 SM30에서는 채널이 보입니다.
클라이언트(MANDT) 불일치이거나, 조회 값에 선행 공백/소문자가 섞인 경우가 많습니다.
VTWEG은 CHAR 2 도메인이므로 입력값을 변환 루틴에 맞춰 정규화한 뒤 조회하세요.
Q4. 클라우드 환경에서 TVTW SELECT가 아예 실패합니다.
SAP S/4HANA Cloud의 ABAP Cloud 개발 모델에서는 릴리스되지 않은 오브젝트 접근이 구문 검사 단계에서 차단됩니다. 이것은 오류가 아니라 의도된 동작이며, 릴리스된
I_DistributionChannel로 전환하는 것이 유일한 정공법입니다. 온프레미스에서도 ABAP Cloud 언어 버전을 선택하면 동일하게 동작합니다.
🚀 이어서 살펴볼 주제
- I_SalesOrganization — 영업 조직 마스터의 CDS 인터페이스 뷰. 이 글의 가격 정책 시나리오를 조합 뷰로 확장할 때 필요합니다.
- VDM 뷰 계층 구조 — Basic / Composite / Consumption 뷰의 역할 분담을 이해하면 어떤 뷰를 조회 대상으로 삼을지 판단이 빨라집니다.
- CDS Access Control(DCL) — 유통 채널·영업 조직 단위 권한을 뷰 계층에서 처리하는 방법.
- RAP(ABAP RESTful Application Programming Model) — 릴리스된 인터페이스 뷰를 Value Help와 검증 로직에 연결하는 실전 활용.
📚 더 읽어볼 자료
- SAP Help Portal — SAP S/4HANA Cloud 제품 문서 (VDM/CDS 뷰 레퍼런스 포함)
- SAP Help Portal — ABAP Cloud 개발 가이드 (릴리스 계약과 오브젝트 사용 규칙)
- SAP Help Portal — ABAP Keyword Documentation (ABAP SQL 경로 표현식, CDS 어소시에이션 문법)
- SAP Business Accelerator Hub — I_DistributionChannel 등 릴리스된 CDS 뷰 검색
- SAP Community — VDM 및 CDS 뷰 마이그레이션 실무 사례
댓글 0
아직 댓글이 없습니다.