개요 및 이 글에서 다루는 범위
SAP S/4HANA 환경에서 모든 금액 필드는 반드시 통화 코드(Currency Key)와 짝을 이뤄야 합니다. 이때 사용되는 표준 마스터 데이터 뷰가 I_Currency입니다. 이 글은 TCURC 테이블 기반의 I_Currency CDS 뷰가 어떻게 설계되어 있는지, 그리고 판매 주문이나 송장 처리 같은 실무 시나리오에서 어떻게 활용되는지를 단계별로 설명합니다.
- I_Currency 뷰의 필드 구조와 TCURC 매핑 이해
- I_CurrencyText 등 텍스트 뷰와의 연결 구조 파악
- 판매 주문 처리 시 통화 코드 검증 패턴 작성
- 환율(TCURR), 환율 유형(TCURV)과의 연계 구조 이해
- 버퍼링 및 성능 최적화 전략 적용
이 글을 읽기 전 알아두면 좋은 것
ABAP CDS(Core Data Services) 뷰의 기본 문법, @ObjectModel.dataCategory와 같은 어노테이션의 의미, 그리고 SAP 마스터 데이터의 일반적인 구조(텍스트 분리, 클라이언트 종속성)에 대한 기초 이해가 있으면 도움이 됩니다. SE16/SE11에서 TCURC, TCURR, TCURT 테이블을 한 번이라도 조회해 본 경험이 있으면 더욱 좋습니다.
환경 및 시스템 요건
이 글의 예제는 다음 환경을 기준으로 작성되었습니다.
- SAP S/4HANA 2022 또는 2023 (On-Premise / Private Cloud)
- ABAP Development Tools (ADT) for Eclipse 2023-06 이상
- ABAP Platform 7.58 이상 (CDS View Entity 지원)
- HANA DB 2.0 SPS 06 이상 권장
SAP BTP ABAP Environment(Steampunk)에서는 일부 Public 릴리스 상태가 다를 수 있으니, API_HUB와 ADT의 Release Contract 정보를 확인하는 것이 일반적으로 권장됩니다. I_Currency는 Foundation Layer에 속하는 기본 뷰로, 대부분의 S/4HANA 시스템에서 별도 설정 없이 사용할 수 있습니다.
핵심 개념: TCURC와 I_Currency의 관계
SAP의 통화 관련 마스터 데이터는 네 개의 핵심 테이블로 구성되어 있습니다. 이를 이해하는 것이 I_Currency를 제대로 활용하는 출발점입니다.
| 테이블 | 역할 | 대응 CDS 뷰 |
|---|---|---|
| TCURC | 통화 코드 마스터 (ISO 코드 포함) | I_Currency |
| TCURT | 통화 코드 언어별 텍스트 | I_CurrencyText |
| TCURR | 환율 정보 (날짜별) | I_ExchangeRate |
| TCURV | 환율 유형 (M, B, G 등) | I_ExchangeRateType |
| TCURX | 통화별 소수점 자리수 | I_CurrencyDecimal |
I_Currency는 TCURC 테이블을 1차 소스로 삼는 마스터 데이터 뷰입니다. 비유하자면 TCURC는 "은행 금고"이고 I_Currency는 "은행 창구"입니다. 금고에 직접 접근하는 대신, 표준화된 창구(CDS 뷰)를 통해 데이터를 가져오면 어노테이션, 권한, 라벨, 연관 관계가 일관되게 적용됩니다.
주요 필드 구조는 다음과 같습니다.
- Currency (WAERS): 내부 통화 코드 (예: USD, KRW, EUR)
- ISOCurrency (ISOCD): ISO 4217 표준 코드
- CurrencyISOCode: ISO 코드 별칭
- Decimals (DECIMALS): 소수점 자리수
- AlternativeCurrencyKey: 대체 통화 키
- PrimaryCurrencyForCountry: 국가별 주통화 여부
주의할 점은 I_Currency 자체에는 텍스트(통화 이름)가 포함되지 않는다는 것입니다. "미국 달러", "대한민국 원" 같은 설명 텍스트는 I_CurrencyText 뷰에서 Language 키와 함께 별도로 관리됩니다. 이는 SAP가 다국어 환경을 일관되게 처리하기 위해 텍스트를 분리한 설계 철학입니다.
1단계: 기본 조회 예제
가장 단순한 형태로, 시스템에 등록된 모든 통화 코드를 조회하면서 한국어 텍스트를 함께 가져오는 CDS 뷰를 만들어 봅니다.
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Currency with Korean Text'
define view entity ZC_CurrencyWithText
as select from I_Currency as Curr
association [0..1] to I_CurrencyText as _Text
on _Text.Currency = Curr.Currency
and _Text.Language = 'K'
{
key Curr.Currency,
Curr.ISOCurrency,
Curr.Decimals,
_Text.CurrencyName,
_Text.CurrencyShortName,
_Text._Language
}
위 예제는 한국어('K') 텍스트만 조인합니다. 이렇게 작성하면 다음과 같은 ABAP 코드에서 손쉽게 사용할 수 있습니다.
SELECT Currency, ISOCurrency, Decimals, CurrencyName
FROM ZC_CurrencyWithText
WHERE Currency IN ( 'USD', 'KRW', 'EUR', 'JPY' )
INTO TABLE @DATA(lt_currency).
LOOP AT lt_currency INTO DATA(ls_currency).
WRITE: / ls_currency-Currency,
ls_currency-ISOCurrency,
ls_currency-Decimals,
ls_currency-CurrencyName.
ENDLOOP.
2단계: 판매 주문에서 통화 코드 검증하기
실무에서 가장 흔히 마주치는 시나리오는 외부 시스템에서 들어온 판매 주문 데이터의 통화 코드가 유효한지 검증하는 작업입니다. 예를 들어 EDI나 외부 e-Commerce 플랫폼에서 받은 주문에 잘못된 통화 코드가 섞여 들어올 수 있습니다.
CLASS zcl_sales_order_validator DEFINITION
PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES: BEGIN OF ty_validation_result,
order_id TYPE c LENGTH 10,
currency TYPE waers,
is_valid TYPE abap_bool,
error_msg TYPE string,
END OF ty_validation_result.
METHODS validate_currencies
IMPORTING it_orders TYPE STANDARD TABLE
RETURNING VALUE(rt_result) TYPE STANDARD TABLE OF ty_validation_result.
ENDCLASS.
CLASS zcl_sales_order_validator IMPLEMENTATION.
METHOD validate_currencies.
DATA: lt_currency_codes TYPE STANDARD TABLE OF waers.
LOOP AT it_orders ASSIGNING FIELD-SYMBOL(<fs_ord>).
ASSIGN COMPONENT 'CURRENCY' OF STRUCTURE <fs_ord> TO FIELD-SYMBOL(<fv_cur>).
IF sy-subrc = 0.
APPEND <fv_cur> TO lt_currency_codes.
ENDIF.
ENDLOOP.
SORT lt_currency_codes.
DELETE ADJACENT DUPLICATES FROM lt_currency_codes.
SELECT Currency
FROM I_Currency
FOR ALL ENTRIES IN @lt_currency_codes
WHERE Currency = @lt_currency_codes-table_line
INTO TABLE @DATA(lt_valid).
LOOP AT it_orders ASSIGNING <fs_ord>.
ASSIGN COMPONENT 'CURRENCY' OF STRUCTURE <fs_ord> TO <fv_cur>.
DATA(ls_res) = VALUE ty_validation_result( currency = <fv_cur> ).
IF line_exists( lt_valid[ Currency = <fv_cur> ] ).
ls_res-is_valid = abap_true.
ELSE.
ls_res-is_valid = abap_false.
ls_res-error_msg = |Invalid currency code: { <fv_cur> }|.
ENDIF.
APPEND ls_res TO rt_result.
ENDLOOP.
ENDMETHOD.
ENDCLASS.
핵심 포인트는 주문 라인마다 SELECT를 던지지 않고 중복 제거된 통화 코드 리스트로 한 번만 조회하는 것입니다. TCURC 자체는 작은 테이블이지만, 트랜잭션 처리량이 많을 때는 이런 패턴이 일반적으로 권장됩니다.
3단계: 환율 변환과 OData 노출까지 포함한 프로덕션 패턴
실제 운영 환경에서는 통화 코드 검증에 그치지 않고, 주문 통화를 회사 통화로 환산하는 로직까지 함께 구현해야 합니다. 다음 CDS 뷰는 I_Currency를 마스터로 두고 I_ExchangeRate를 연관으로 가져오는 프로덕션 수준의 예제입니다.
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Order with Currency Conversion'
@VDM.viewType: #CONSUMPTION
@OData.publish: true
@ObjectModel.usageType: {
serviceQuality: #D,
sizeCategory: #L,
dataClass: #TRANSACTIONAL
}
define view entity ZC_SalesOrderEnriched
as select from zsalesorder as SO
association [1..1] to I_Currency as _Currency
on _Currency.Currency = SO.doc_currency
association [0..1] to I_CurrencyText as _CurrencyText
on _CurrencyText.Currency = SO.doc_currency
and _CurrencyText.Language = $session.system_language
{
key SO.order_id,
SO.customer_id,
SO.doc_currency,
_Currency.ISOCurrency,
_Currency.Decimals,
_CurrencyText.CurrencyName as CurrencyDescription,
@Semantics.amount.currencyCode: 'doc_currency'
SO.net_amount,
currency_conversion(
amount => SO.net_amount,
source_currency => SO.doc_currency,
target_currency => cast( 'USD' as abap.cuky ),
exchange_rate_date => SO.order_date,
exchange_rate_type => 'M',
error_handling => 'SET_TO_NULL'
) as NetAmountInUSD,
_Currency,
_CurrencyText
}
이 뷰의 핵심 설계 포인트는 다음과 같습니다.
currency_conversionCDS 함수로 DB 레벨에서 환산 수행 → ABAP 레벨 루프 제거error_handling => 'SET_TO_NULL'로 환율이 없을 때 NULL 반환, 예외 발생 방지$session.system_language로 사용자 로그온 언어에 맞춘 텍스트 자동 선택@Semantics.amount.currencyCode로 금액 필드와 통화 필드 의미 연결@OData.publish: true로 Fiori/외부 시스템에서 즉시 소비 가능
단위 테스트에서는 CL_OSQL_TEST_ENVIRONMENT를 사용해 I_Currency 데이터를 가짜로 주입하면 안정적인 검증이 가능합니다.
DATA(lt_curr_mock) = VALUE i_currency_t(
( Currency = 'KRW' ISOCurrency = 'KRW' Decimals = 0 )
( Currency = 'USD' ISOCurrency = 'USD' Decimals = 2 )
).
mo_osql_env->insert_test_data( lt_curr_mock ).
자주 마주치는 실수와 트러블슈팅
Q1. WAERS와 ISOCD 중 어떤 것을 외부 인터페이스 키로 써야 하나요?
SAP 내부에서는 WAERS(예: USD)를 사용하지만, ISO 표준에 맞춰야 하는 외부 시스템(REST API, ISO 20022 페이먼트)과의 통신에서는 ISOCurrency를 매핑하는 것이 일반적으로 권장됩니다. 일부 SAP 내부 코드(예: 러시아 루블의 RUB vs RUR)는 ISO 코드와 다를 수 있습니다.
Q2. I_Currency 조회가 느린데 버퍼링이 작동하지 않는 것 같습니다.
TCURC는 표준적으로 단일 레코드 버퍼링이 설정되어 있어 매우 빠릅니다. 그런데도 느리다면 (1) FOR ALL ENTRIES가 빈 테이블로 호출되어 전체 스캔이 일어났는지, (2) CDS 뷰에 추가된 조인이 buffer를 우회시키는지 확인해야 합니다. SELECT SINGLE 또는 WHERE Currency = ... 단일 조건이 가장 안전합니다.
Q3. CurrencyText에서 한국어 텍스트가 비어 있어요.
TCURT 테이블은 언어별로 데이터가 입력되어야 하는데, 일부 통화는 한국어(K) 텍스트가 마스터에 채워지지 않은 경우가 있습니다. 이때는 COALESCE 패턴으로 fallback을 둡니다.
coalesce( _TextKO.CurrencyName, _TextEN.CurrencyName ) as CurrencyName
Q4. ABAP Cloud(Steampunk)에서 TCURC를 직접 SELECT하면 syntax 오류가 납니다.
ABAP Cloud에서는 DDIC 테이블 직접 접근이 제한됩니다. 반드시 I_Currency와 같은 Released CDS 뷰를 통해서만 접근해야 합니다. ADT의 Release Contract 탭에서 "Use System-Internally"가 아닌 "Use in Cloud Development"인지 확인하세요.
I_Currency 연관 뷰 생태계 이해하기
I_Currency를 이해했다면 자연스럽게 I_ExchangeRate(TCURR), I_ExchangeRateType(TCURV) 뷰로 확장할 수 있습니다. 또한 RAP(RESTful ABAP Programming Model)에서 @Semantics.amount.currencyCode 어노테이션이 Behavior Definition의 validation과 어떻게 연동되는지 살펴보면 통화 처리의 전체 그림이 완성됩니다. Fiori Elements 앱에서는 이 어노테이션 덕분에 별도 코딩 없이 통화 포맷팅이 자동 적용된다는 점도 흥미로운 확장 주제입니다.
댓글 0
아직 댓글이 없습니다.