ABAP

T006 없이 단위 텍스트 연결 3가지 #shorts #SAP #ABAP

개요 및 학습 포인트

SAP S/4HANA의 ABAP CDS 모델에서 단위(Unit of Measure)는 거의 모든 트랜잭션 데이터에 따라붙는 핵심 속성입니다. 그러나 데이터베이스 테이블 T006에는 "EA", "KG", "L"과 같은 내부 코드만 저장되어 있고, 사용자가 보는 텍스트("개", "킬로그램", "리터")는 T006A에 언어별로 분리되어 있습니다. 이 글에서는 표준 CDS View인 I_UnitOfMeasure를 사용해 코드와 텍스트를 한 번에 연결하는 방법을 다룹니다.

  • I_UnitOfMeasure의 구조와 동작 원리 파악
  • T006/T006A 직접 JOIN과의 차이 이해
  • Association을 통한 텍스트 연결 패턴 습득
  • 실무 시나리오(배송, 판매오더) 적용
  • 언어 필터링 및 성능 고려사항

읽기 전에 알아두면 좋은 내용

이 글은 ABAP CDS View의 기본 문법(define view, association, annotation)을 어느 정도 접해본 독자를 대상으로 합니다. 추가로 SAP의 도메인/데이터 엘리먼트 개념, $session.system_language와 같은 세션 변수, 그리고 ADT(ABAP Development Tools) 사용 경험이 있으면 이해가 빠릅니다. T006 테이블이 단위 마스터, T006A가 단위 텍스트라는 점만 알고 있어도 충분합니다.

실습 환경과 준비물

이 글의 예제는 다음 환경을 가정합니다.

  • SAP S/4HANA 2022 이상 (On-Premise 또는 Private Cloud)
  • ABAP Platform 2022 (SAP BTP ABAP Environment에서도 유사하게 동작)
  • Eclipse 2024-03 + ABAP Development Tools (ADT) 3.36 이상
  • SAP_BS_FND 계층의 Virtual Data Model(VDM) 활성화 상태
  • 패키지 권한 및 CDS View 생성 권한(S_DEVELOP)

SAP BTP ABAP Environment(스팀팩)에서는 I_UnitOfMeasure가 Released API로 노출되어 있으므로, 객체 검색 시 Release Contract가 "Use System-Internally" 또는 "Use in Cloud Development"로 표시되는지 확인하세요. 일반적으로 Released CDS View를 쓰면 향후 업그레이드 호환성이 보장되는 편입니다.

핵심 개념: 단위 코드와 텍스트의 분리 구조

SAP는 다국어 환경을 위해 마스터 테이블과 텍스트 테이블을 분리해 관리합니다. 단위(UOM)의 경우 다음과 같이 구성됩니다.

  • T006: 단위 마스터. MSEHI(내부 단위 코드, 예: "ST"), 차원, 환산 계수 등 언어 비종속 정보 저장
  • T006A: 단위 텍스트. SPRAS(언어 키), MSEHI, MSEHL(긴 텍스트), MSEH3(짧은 텍스트 "개", "EA" 등)

비유하자면 T006은 "여권 번호"이고 T006A는 "여러 나라 언어로 인쇄된 이름표"입니다. 같은 사람이지만 한국에서는 "김철수", 영어권에서는 "Kim, Cheol-Su"로 표기되는 것과 같죠. 따라서 화면에 "킬로그램"이라고 띄우려면 두 테이블을 JOIN하면서 언어 필터까지 걸어야 합니다.

이 패턴이 반복되니 SAP는 VDM 계층에서 I_UnitOfMeasure(기본 뷰)와 I_UnitOfMeasureText(텍스트 뷰)를 미리 만들어 두었습니다. I_UnitOfMeasure는 단위 마스터를 깔끔하게 노출하면서, 내부적으로 _Text Association을 통해 텍스트 뷰와 연결되어 있습니다. 즉 개발자는 더 이상 SPRAS 필터를 직접 쓸 필요 없이, Association만 활용해도 현재 로그온 언어 기준의 텍스트를 얻을 수 있습니다.

도식으로 표현하면 다음과 같습니다.

[T006] ────────────────► I_UnitOfMeasure (마스터)
                                │
                                │ _Text Association
                                ▼
[T006A] ──────────────► I_UnitOfMeasureText (언어별 텍스트)
                                │
                                ▼
                         사용자 화면 / Fiori App

1단계: 가장 단순한 형태로 단위 텍스트 가져오기

먼저 I_UnitOfMeasure를 직접 조회하는 가장 기본적인 CDS View를 작성해봅시다. 시나리오는 "사내에서 사용하는 모든 단위 코드와 한국어/영어 텍스트를 함께 보고 싶다"입니다.

@AbapCatalog.sqlViewName: 'ZDEMOUOMV1'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'UOM 코드와 텍스트 기본 조회'
define view ZDEMO_UOM_BASIC
  as select from I_UnitOfMeasure as Uom
  association [0..*] to I_UnitOfMeasureText as _Text
    on $projection.UnitOfMeasure = _Text.UnitOfMeasure
{
  key Uom.UnitOfMeasure,           // 내부 단위 코드 (예: 'ST')
      Uom.UnitOfMeasureISOCode,    // ISO 코드 (예: 'PCE')
      Uom.UnitOfMeasureDimension,  // 차원 (LENGTH, MASS 등)
      _Text                        // 모든 언어 텍스트를 노출
}

위 예제는 단위 마스터를 그대로 노출하면서 _Text Association을 외부로 공개합니다. ADT의 Data Preview에서 결과를 펼쳐보면 각 단위마다 다국어 텍스트가 트리 형태로 표시됩니다.

2단계: 실무 시나리오 — 판매 오더 품목과 단위 텍스트 결합

실무에서는 단위 자체가 아니라 다른 비즈니스 객체와 결합해서 활용합니다. 가상의 판매 오더 품목 테이블 ZSALES_ITEM이 있고, 사용자에게 "오더 번호 + 품목 + 수량 + 단위 텍스트(현재 로그온 언어)"를 표시해야 한다고 가정해봅시다.

@AbapCatalog.sqlViewName: 'ZDEMOSOITEMTXT'
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Item with Unit Text'
@VDM.viewType: #COMPOSITE
define view ZDEMO_SO_ITEM_WITH_UOM
  as select from zsales_item as Item
  association [0..1] to I_UnitOfMeasure     as _Uom
    on  $projection.SalesUnit = _Uom.UnitOfMeasure
  association [0..1] to I_UnitOfMeasureText as _UomText
    on  $projection.SalesUnit = _UomText.UnitOfMeasure
    and _UomText.Language     = $session.system_language
{
  key Item.sales_order_id   as SalesOrderID,
  key Item.item_no          as ItemNumber,
      Item.material_id      as Material,
      Item.order_quantity   as OrderQuantity,

      Item.sales_unit       as SalesUnit,
      _UomText.UnitOfMeasureShortName as UnitShortText,
      _UomText.UnitOfMeasureName      as UnitLongText,

      _Uom,
      _UomText
}

핵심 포인트는 두 가지입니다.

  • Association 두 개 분리: 마스터(_Uom)와 텍스트(_UomText)를 따로 둬서, 필요 시 차원·환산계수도 활용 가능하게 합니다.
  • 언어 조건은 ON 절에 포함: $session.system_language를 WHERE가 아니라 Association ON 조건에 두면, 텍스트가 없는 단위도 NULL로 안전하게 처리됩니다.

이렇게 만든 뷰는 OData 서비스로 노출했을 때 Fiori Elements가 자동으로 단위 텍스트를 라벨로 표시해 줍니다.

3단계: 프로덕션 패턴 — 어노테이션·성능·테스트

실서비스에서는 단순 JOIN을 넘어 메타데이터 어노테이션, 캐시 전략, 단위 테스트까지 함께 고려해야 합니다.

@AbapCatalog.sqlViewName: 'ZDLVITEMUOM'
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Delivery Item - Production VDM'
@VDM.viewType: #CONSUMPTION
@Metadata.allowExtensions: true
@ObjectModel.usageType.serviceQuality: #D
@ObjectModel.usageType.sizeCategory: #L
@ObjectModel.usageType.dataClass: #TRANSACTIONAL
define view entity ZC_DELIVERY_ITEM_UOM
  as select from zdlv_item as Dlv
  association [1..1] to I_UnitOfMeasure as _Uom
    on $projection.DeliveryUnit = _Uom.UnitOfMeasure
{
  key Dlv.delivery_id            as DeliveryID,
  key Dlv.item_no                as ItemNumber,

      @Semantics.quantity.unitOfMeasure: 'DeliveryUnit'
      Dlv.delivered_qty          as DeliveredQuantity,

      @ObjectModel.foreignKey.association: '_Uom'
      @Consumption.valueHelpDefinition: [{ entity:
        { name: 'I_UnitOfMeasureStdVH', element: 'UnitOfMeasure' } }]
      Dlv.delivery_unit          as DeliveryUnit,

      _Uom.UnitOfMeasureISOCode  as IsoUnit,
      _Uom._Text[ 1: Language = $session.system_language ]
          .UnitOfMeasureName     as UnitText,

      _Uom
}

이 예제에서 주목할 부분.

  • @Semantics.quantity.unitOfMeasure: 수량 필드가 어떤 단위 필드를 참조하는지 명시. Fiori 클라이언트가 자동으로 "10 EA"처럼 포맷합니다.
  • @ObjectModel.foreignKey.association: 단위 필드가 Association을 통해 마스터를 참조한다고 선언. F4 검색 도움말과 라벨 처리가 자동화됩니다.
  • 인라인 Association 필터 _Uom._Text[ 1: Language = ... ]: 텍스트 한 건만 가져오므로 카디널리티가 명확해져 옵티마이저가 효율적인 플랜을 선택합니다.

단위 테스트는 CL_CDS_TEST_ENVIRONMENT를 활용해 작성합니다.

CLASS ltc_delivery_uom DEFINITION FOR TESTING
  DURATION SHORT RISK LEVEL HARMLESS.

  PRIVATE SECTION.
    CLASS-DATA environment TYPE REF TO if_cds_test_environment.
    CLASS-METHODS class_setup.
    METHODS test_unit_text_korean FOR TESTING.
ENDCLASS.

CLASS ltc_delivery_uom IMPLEMENTATION.
  METHOD class_setup.
    environment = cl_cds_test_environment=>create(
        i_for_entity = 'ZC_DELIVERY_ITEM_UOM' ).
  ENDMETHOD.

  METHOD test_unit_text_korean.
    " 테스트 더블에 단위 'EA'를 삽입하고 한국어 텍스트 검증
    DATA(double_data) = VALUE ztt_dlv_item(
      ( delivery_id = '8000001' item_no = '10'
        delivered_qty = '5.000' delivery_unit = 'EA' ) ).
    environment->insert_test_data( double_data ).

    SELECT SINGLE UnitText FROM zc_delivery_item_uom
      WHERE DeliveryID = '8000001'
      INTO @DATA(text).

    cl_abap_unit_assert=>assert_not_initial( text ).
  ENDMETHOD.
ENDCLASS.

자주 마주치는 문제와 해결법

Q1. 단위 텍스트가 비어 있는 행이 생깁니다. 해당 언어로 T006A에 텍스트가 등록되어 있지 않은 경우입니다. COALESCE로 영어 또는 ISO 코드를 fallback으로 사용하거나, I_UnitOfMeasureStdVH 같은 표준 Value Help 뷰를 참고하세요.

Q2. T006/T006A를 직접 JOIN하면 안 되나요? 기술적으로는 가능하지만 권장하지 않습니다. 표준 VDM이 향후 단위 모델 변경(예: ISO 단위 확장)을 흡수해 주기 때문에, 직접 테이블을 참조하면 업그레이드 시 수정 부담이 커집니다.

Q3. I_UnitOfMeasure와 I_UnitOfMeasureText의 차이는? 전자는 단위 마스터(언어 비종속), 후자는 단위별 다국어 텍스트입니다. 화면에 텍스트만 필요하면 I_UnitOfMeasureText에 언어 필터를 걸어 사용하고, 차원·ISO 코드 등 부가 정보가 필요하면 I_UnitOfMeasure를 기준으로 두는 편이 일반적입니다.

Q4. $session.system_language가 아닌 다른 언어로 보고 싶어요. Parameter를 정의해 입력받거나, I_UnitOfMeasureText를 직접 select하면서 Language를 WHERE에 명시하면 됩니다. 다만 미리보기 모드에서는 ADT가 사용자 언어를 자동 주입하므로 결과가 달라 보일 수 있습니다.

이어서 살펴보면 좋은 주제

단위 처리를 마스터했다면 통화(Currency)를 다루는 I_Currency, 국가 코드를 다루는 I_Country도 같은 패턴으로 쉽게 익힐 수 있습니다. 더 나아가 단위 환산이 필요하면 ABAP SQL의 UNIT_CONVERSION 함수, 그리고 Released API인 CL_UOM_CONVERSION 클래스를 함께 학습해 보세요. RAP(RESTful Application Programming Model)에서 단위 필드를 Behavior Definition에 통합하는 패턴도 자연스러운 다음 단계입니다.

참고로 확인하면 좋은 링크

댓글 0

아직 댓글이 없습니다.