ABAP

아직도 MARA 직접 JOIN? I_Product 3가지 핵심 #shorts #SAP #ABAP

▶ YouTube에서 보기

개요 및 학습 체크리스트

I_Product는 SAP S/4HANA의 VDM(Virtual Data Model) 계층에서 제품 마스터를 표현하는 대표적인 Basic Interface View입니다. 전통적으로 ABAP 개발자들은 MARA, MAKT, MARC 같은 테이블을 직접 SELECT/JOIN해서 제품 정보를 조회했지만, S/4HANA로 넘어오면서 이런 저수준 접근은 권장되지 않습니다. 이 글에서는 I_Product가 어떤 테이블들을 조인하고, VDM 계층에서 어떤 역할을 하는지, 그리고 실무 코드에서 어떻게 활용하는지를 단계별로 살펴봅니다.

  • I_Product CDS View의 기본 구조와 MARA 기반 필드 매핑 이해
  • I_Product가 조인하는 주요 테이블(MARA, MARC, MARD, MAKT 등)의 역할 파악
  • VDM Basic / Composite / Consumption 계층에서 I_Product의 위치
  • 실전 CDS View에서 I_Product를 association으로 활용하는 방법
  • 확장(Extension)과 권한 체크 적용 시 주의점

이 글을 시작하기 전에 알아두면 좋은 것들

ABAP CDS View의 기본 문법(define view, association, @ObjectModel annotation), S/4HANA 제품 마스터 테이블 구조(MARA, MAKT, MARC), 그리고 VDM 개념에 대한 기초가 있으면 이해가 빠릅니다. 또한 ADT(ABAP Development Tools in Eclipse) 사용 경험과 SELECT 문에서 JOIN을 다뤄본 경험을 전제로 설명합니다.

실습 환경과 버전 정보

이 글의 내용은 S/4HANA On-Premise 2022 / 2023 및 S/4HANA Cloud Public Edition을 기준으로 작성되었습니다. I_Product는 S/4HANA 1610부터 도입되었으며, 릴리스에 따라 필드 구성과 조인 대상 테이블이 일부 다를 수 있습니다. 일반적으로 다음 환경을 권장합니다.

  • S/4HANA 2022 이상 (Basic Interface View 안정성 확보)
  • ABAP Development Tools (ADT) for Eclipse 3.30 이상
  • SAP HANA DB (CDS View의 코드 푸시다운 활용)
  • SE11/SE16에서 MARA, MAKT, MARC 테이블 접근 권한
  • I_Product, I_ProductText, I_ProductPlant 등 SAP 표준 CDS View 조회 권한

Cloud 환경에서는 Released State의 CDS View만 사용 가능하므로, ABAP API_PRODUCT_SRV 또는 I_Product를 통해 접근해야 합니다.

I_Product의 핵심 개념과 동작 원리

I_Product를 이해하려면 먼저 VDM(Virtual Data Model)의 3계층 구조를 떠올려야 합니다. VDM은 Basic View, Composite View, Consumption View로 나뉩니다. 비유하자면 Basic View는 원재료(raw material), Composite View는 반제품(semi-finished), Consumption View는 완제품(finished goods)에 해당합니다.

I_Product는 Basic Interface View로, MARA 테이블에 1:1로 매핑되는 가장 기초적인 제품 마스터 뷰입니다. "Interface"라는 접두어는 외부 소비자(다른 CDS View, OData 서비스, ABAP 프로그램)가 안정적으로 사용할 수 있도록 SAP가 계약(contract)을 보장한다는 의미입니다.

I_Product의 핵심 동작은 다음과 같이 정리할 수 있습니다.

  • MARA 중심: 기본 SELECT 절은 MARA의 컬럼들을 의미론적으로 명확한 이름으로 alias 합니다. 예를 들어 MARA-MATNR은 Product, MARA-MTART는 ProductType으로 매핑됩니다.
  • Association 기반 조인: 실제 JOIN 대신 _ProductText, _ProductPlant, _ProductStorageLocation 같은 association을 노출합니다. 호출자가 필요한 필드를 SELECT 할 때만 조인이 발생하는 "ad-hoc join" 방식입니다.
  • 의미론적 어노테이션: @Semantics, @ObjectModel.representativeKey, @UI.lineItem 등의 어노테이션을 통해 메타데이터를 풍부하게 제공합니다.

I_Product가 직간접적으로 연결되는 주요 테이블은 다음과 같습니다.

테이블역할접근 방식
MARA제품 마스터 일반 데이터(기본 키 MATNR)I_Product 본체
MAKT언어별 제품 설명 텍스트_ProductText association
MARC플랜트별 제품 데이터_ProductPlant association → I_ProductPlant
MARD저장 위치별 재고/마스터_ProductStorageLocation
MVKE판매 조직별 제품 데이터_ProductSalesDelivery
MBEW평가 영역별 가치 데이터_ProductValuation
MLAN국가별 세금 분류_ProductTaxClassification

이런 구조 덕분에 호출자는 MARA만 필요하면 가볍게, 플랜트 정보까지 필요하면 association을 따라가는 방식으로 비용을 통제할 수 있습니다.

실전 코드 1단계: 기본 SELECT 예제

가장 단순한 사용 형태부터 시작해봅니다. 특정 제품 ID로 마스터 데이터를 조회하는 예제입니다.

REPORT z_product_lookup_demo.

DATA: ls_product TYPE i_product,
      lt_product TYPE STANDARD TABLE OF i_product.

" 단일 제품 조회 - MARA 핵심 필드 매핑 확인
SELECT SINGLE
    Product,
    ProductType,
    BaseUnit,
    ProductGroup,
    CreationDate,
    LastChangeDate,
    IsMarkedForDeletion
  FROM I_Product
  WHERE Product = 'FG-2200-001'
  INTO @DATA(ls_simple).

IF sy-subrc = 0.
  WRITE: / 'Product:', ls_simple-Product,
         / 'Type   :', ls_simple-ProductType,
         / 'Unit   :', ls_simple-BaseUnit.
ENDIF.

여기서 Product 필드는 MARA-MATNR을, ProductType은 MARA-MTART를 alias 한 것입니다. SAP는 헝가리안 표기나 약어 대신 풀네임 CamelCase를 사용하므로, 처음 보는 개발자도 필드 의미를 짐작할 수 있습니다.

실전 코드 2단계: Association으로 다국어 텍스트와 플랜트 데이터 결합

실무에서는 제품 마스터만으로 끝나지 않습니다. 한국어 설명, 플랜트별 MRP 그룹, 저장 조건 등을 함께 조회해야 하는 경우가 대부분입니다. 자체 CDS View를 만들어 I_Product의 association을 활용해봅니다.

@AbapCatalog.sqlViewName: 'ZIPRODMASTER'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Product Master with Plant Info'
@VDM.viewType: #COMPOSITE

define view ZI_ProductMasterEnriched
  as select from I_Product as Prod

  association [0..*] to I_ProductText  as _Text
    on \$projection.Product = _Text.Product

  association [0..*] to I_ProductPlant as _Plant
    on \$projection.Product = _Plant.Product

{
  key Prod.Product,
      Prod.ProductType,
      Prod.BaseUnit,
      Prod.ProductGroup,
      Prod.GrossWeight,
      Prod.WeightUnit,

      @Semantics.text: true
      _Text[ 1: where Language = \$session.system_language ]
        .ProductDescription as ProductDescription,

      cast( case Prod.IsMarkedForDeletion
              when 'X' then 'DELETED'
              else 'ACTIVE'
            end as abap.char(8) )           as LifecycleStatus,

      Prod.CreationDate,
      Prod.LastChangeDate,

      _Text,
      _Plant
}
where Prod.IsMarkedForDeletion = ''

이 View를 ABAP에서 호출하면서 에러/로깅을 추가한 패턴은 다음과 같습니다.

CLASS zcl_product_reader DEFINITION PUBLIC FINAL CREATE PUBLIC.
  PUBLIC SECTION.
    METHODS read_with_plants
      IMPORTING iv_product TYPE matnr
                iv_plant   TYPE werks_d
      EXPORTING es_product TYPE zi_productmasterenriched
                et_plants  TYPE STANDARD TABLE OF i_productplant
      RAISING   cx_sy_open_sql_db.
ENDCLASS.

CLASS zcl_product_reader IMPLEMENTATION.
  METHOD read_with_plants.
    TRY.
        SELECT SINGLE *
          FROM zi_productmasterenriched
          WHERE Product = @iv_product
          INTO @es_product.

        IF sy-subrc <> 0.
          MESSAGE |Product { iv_product } not found| TYPE 'E'.
        ENDIF.

        SELECT Product, Plant, MRPType, ProcurementType,
               PurchasingGroup, MRPController
          FROM I_ProductPlant
          WHERE Product = @iv_product
            AND Plant   = @iv_plant
          INTO TABLE @et_plants.

      CATCH cx_sy_open_sql_db INTO DATA(lx_sql).
        cl_demo_output=>write( |DB error: { lx_sql->get_text( ) }| ).
        RAISE EXCEPTION lx_sql.
    ENDTRY.
  ENDMETHOD.
ENDCLASS.

실전 코드 3단계: 영업 주문 라인과 결합한 프로덕션 시나리오

마지막으로 영업 주문 아이템(I_SalesOrderItem)과 제품 마스터를 결합해 OData 서비스로 노출하는 시나리오를 살펴봅니다.

@AccessControl.authorizationCheck: #CHECK
@VDM.viewType: #CONSUMPTION
@OData.publish: true
@EndUserText.label: 'Sales Order Item with Product Master'

define view entity ZC_SalesOrderItemWithProduct
  as select from I_SalesOrderItem as Item

  association [1..1] to I_Product as _Product
    on \$projection.Material = _Product.Product

{
  key Item.SalesOrder,
  key Item.SalesOrderItem,

      Item.Material,
      _Product.ProductType,
      _Product.BaseUnit,
      _Product.ProductGroup,

      @Semantics.text: true
      _Product._Text[ 1: where Language = \$session.system_language ]
        .ProductDescription                   as ProductDescription,

      Item.RequestedQuantity,
      Item.RequestedQuantityUnit,
      Item.NetAmount,

      @Semantics.currencyCode: true
      Item.TransactionCurrency,

      _Product._Plant[ 1: where Plant = Item.Plant ]
        .MRPController                        as ResponsibleMrpController,

      _Product,
      Item._SalesOrder
}

현장에서 자주 마주치는 실수와 대응

Q1. I_Product에서 MAKT의 한국어 설명만 가져오고 싶은데 빈 값이 나옵니다.
A. _ProductText association을 path filter 없이 그대로 사용하면 모든 언어 레코드가 곱연산으로 펼쳐집니다. 반드시 _Text[ 1: where Language = '1' ] 또는 \$session.system_language 필터를 적용해야 합니다. 또한 한국어 코드는 SAP 언어키 '3' 또는 'KO'임을 혼동하지 않도록 주의합니다.

Q2. MARC 필드(MRPType, ProcurementType)가 I_Product에서 직접 보이지 않습니다.
A. I_Product는 MARA만 직접 매핑하고, MARC 데이터는 별도 View인 I_ProductPlant로 분리되어 있습니다. _ProductPlant association을 통해 접근하거나, I_ProductPlant를 별도로 SELECT 해야 합니다.

Q3. 자체 View에서 I_Product를 확장하고 싶은데 어떻게 하나요?
A. SAP 표준 View를 직접 수정하면 업그레이드 시 손실됩니다. 대신 extend view I_Product with ZE_Product_Extension 형태의 CDS Extension을 활용하거나, I_Product를 source로 하는 자체 Composite View를 만드는 것이 권장됩니다.

Q4. MATNR 길이가 18자에서 40자로 늘어났는데 코드 호환성은?
A. S/4HANA에서 MARA-MATNR은 CHAR40으로 확장되었습니다. I_Product의 Product 필드도 40자입니다. 기존 ECC 코드에서 가져온 18자 변수와 직접 비교하면 문제가 발생할 수 있으므로, 새로 작성하는 코드는 항상 MATNR 데이터 엘리먼트를 그대로 사용하길 권장합니다.

이어서 살펴볼 만한 주제들

  • I_ProductBasicText, I_ProductDescription: 텍스트 처리의 세분화된 View
  • RAP(RESTful ABAP Programming Model): I_Product를 기반으로 한 Behavior Definition과 Fiori Elements 앱 구축
  • CDS Analytical View: @Analytics.dataCategory 어노테이션으로 분석용 큐브 생성
  • API_PRODUCT_SRV OData v2 API: 외부 시스템 연동 시의 표준 인터페이스

댓글 0

아직 댓글이 없습니다.