ABAP

아직도 T001W 직접 쓰는 실수 3가지 #shorts #SAP #ABAP

I_Plant CDS View가 필요한 이유

SAP S/4HANA 환경에서 플랜트(Plant)는 생산, 조달, 재고, 물류, 회계 모듈 전반의 기준 마스터 데이터입니다. 전통적으로 ABAP 개발자는 T001W 테이블에 직접 SELECT 문을 작성하여 플랜트 정보를 조회했지만, 이 방식은 회사코드(BUKRS), 국가(LAND1), 통화 등 연관 마스터와 매번 JOIN을 반복해야 하는 비효율을 동반합니다. SAP는 이러한 중복을 줄이고 의미론적 데이터 모델을 제공하기 위해 Virtual Data Model(VDM) 기반의 CDS View 계층을 표준으로 제공합니다. 그중 I_Plant는 플랜트 마스터의 인터페이스 뷰(Interface View)로서 RAP(RESTful ABAP Programming Model), Fiori Elements, Embedded Analytics, OData 서비스 등 다양한 소비 계층에서 재사용됩니다.

  • T001W 직접 접근 → I_Plant 통한 의미론적 접근으로 전환
  • Association을 통해 회사코드/국가/주소 연결을 선언적으로 처리
  • S/4HANA Cloud 및 On-Premise 양쪽에서 일관된 모델 활용
  • Embedded Analytics 큐브 및 Fiori 앱과 호환성 확보

T001W 테이블과 플랜트 마스터 구조

T001W는 SAP R/3 시절부터 존재해 온 플랜트 마스터의 핵심 투명 테이블입니다. 주요 키 필드는 클라이언트(MANDT)와 플랜트 코드(WERKS)이며, 부가적으로 플랜트 명칭(NAME1), 회사코드(BWKEY 또는 별도 BUKRS 연결), 평가영역(BWKEY), 주소 번호(ADRNR), 공장 캘린더(FABKL), 구매조직(EKORG), 판매조직 연결 정보 등이 포함됩니다.

특히 주목할 필드는 다음과 같습니다.

  • WERKS — 플랜트 코드(4자리), 비즈니스 키
  • BWKEY — 평가영역, 회계 통합 시 회사코드와 매핑
  • ADRNR — 주소 마스터(ADRC) 연결 키
  • LAND1 — 국가 코드(주소 또는 직접 보관)
  • HOUSE_NUM_1, STREET, CITY1, REGION — 일부 버전에서 캐싱된 주소 정보

플랜트는 회사코드와 직접 1:1 관계가 아니라 평가영역(Valuation Area)을 매개로 연결됩니다. 평가영역이 플랜트 단위일 경우 BWKEY = WERKS이며, T001K(평가영역) 테이블을 통해 BUKRS와 매핑됩니다. 이러한 다단계 연결을 ABAP 코드 안에서 매번 풀어내는 대신, CDS View에서 Association으로 추상화한 것이 I_Plant의 핵심 가치입니다.

I_Plant 정의와 필드 구성

I_Plant는 SAP 표준으로 제공되는 인터페이스 레이어 CDS View이며, 명명 규칙상 접두어 I_는 Interface View를 의미합니다. 이 뷰는 BASIC 계층의 뷰와 결합되어 클라이언트 코드 없이도 멀티테넌트 환경에서 안전하게 사용할 수 있도록 설계되어 있습니다.

일반적으로 제공되는 주요 필드는 다음과 같습니다.

  • Plant — WERKS의 의미론적 이름
  • PlantName — 플랜트 명칭
  • CompanyCode — 평가영역을 통해 결정된 회사코드
  • Country — 주소 마스터에서 가져온 국가 코드
  • Region, CityName, PostalCode, StreetName — 주소 정보
  • FactoryCalendar — 가용일 계산용 캘린더
  • CustomerOfPlant, SupplierOfPlant — 플랜트 간 거래 처리용

또한 다수의 Association이 노출되어 있으며, 이를 통해 후속 뷰나 Fiori 앱이 손쉽게 연관 데이터를 가져올 수 있습니다.

국가·회사코드 연결 원리

플랜트는 운영 단위이고, 회사코드는 법적 단위입니다. 한 회사코드가 여러 플랜트를 거느릴 수 있으며, 글로벌 기업의 경우 한국 회사코드(KR01) 아래 인천 생산사이트, 평택 물류 거점을 둘 수 있습니다. I_Plant는 이 연결을 다음 흐름으로 풀어냅니다.

T001W.WERKS → T001K.BWKEY → T001K.BUKRS → T001.BUKRS → T001.LAND1

CDS 모델에서는 이 흐름이 Association 체인으로 표현됩니다. _CompanyCode Association을 펼치면 회사코드 마스터의 모든 필드에 접근 가능하고, 다시 _CompanyCode._Country 형태로 국가 마스터까지 도달할 수 있습니다. 이로써 ABAP 개발자는 더 이상 다단계 JOIN을 직접 작성하지 않습니다.

실전 예제: 생산 사이트 기반 조회 CDS View 작성

아시아 지역의 생산 사이트 정보를 회사코드, 국가, 통화와 함께 조회하는 분석용 Consumption View를 작성한다고 가정해 보겠습니다. 표준 I_Plant를 소비하여 새로운 뷰 ZC_AsiaProductionSite를 만듭니다.

@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Asia Production Site Overview'
@VDM.viewType: #CONSUMPTION
@Analytics.dataCategory: #DIMENSION

define view entity ZC_AsiaProductionSite
  as select from I_Plant as Site

  association [0..1] to I_CompanyCode as _Company
    on $projection.CompanyCode = _Company.CompanyCode

  association [0..1] to I_Country as _Country
    on $projection.Country = _Country.Country

{
  key Site.Plant                       as ProductionSite,
      Site.PlantName                   as SiteName,
      Site.CompanyCode                 as CompanyCode,
      _Company.CompanyCodeName         as CompanyName,
      Site.Country                     as Country,
      _Country.CountryName             as CountryName,
      Site.Region                      as Region,
      Site.CityName                    as CityName,
      Site.FactoryCalendar             as FactoryCalendar,

      /* Association 노출 */
      _Company,
      _Country
}
where Site.Country in ( 'KR', 'JP', 'CN', 'VN', 'TH', 'ID' )

이 뷰는 표준 인터페이스 뷰를 직접 참조하므로 T001W, T001K, T001, T005T를 수기로 JOIN할 필요가 없습니다. where 절은 ABAP SQL에서와 동일한 의미로 동작하며, HANA에서 push-down되어 성능이 최적화됩니다.

Association 확장: I_CompanyCode, I_Country 연결

위 예제에서 사용한 I_CompanyCodeI_Country는 각각 T001과 T005/T005T를 기반으로 한 표준 인터페이스 뷰입니다. Association 노출이 중요한 이유는 OData 서비스로 게시했을 때 $expand 쿼리로 클라이언트가 연관 데이터를 한 번에 가져올 수 있기 때문입니다.

/* 확장 시나리오: 통화와 회계 캘린더까지 묶기 */
define view entity ZC_PlantFinanceContext
  as select from I_Plant as P

  association [0..1] to I_CompanyCode as _Co
    on $projection.CompanyCode = _Co.CompanyCode

{
  key P.Plant                          as PlantId,
      P.PlantName                      as PlantDescription,
      _Co.CompanyCode                  as CompanyCode,
      _Co.CompanyCodeName              as CompanyName,
      _Co.Currency                     as LocalCurrency,
      _Co.ChartOfAccounts              as ChartOfAccounts,
      _Co.FiscalYearVariant            as FiscalYearVariant,
      P.Country                        as Country,
      _Co
}

실무에서는 회사코드의 통화와 회계연도 변형을 미리 함께 가져오면, 후속 보고서나 Analytical Query에서 환산 로직을 단순화할 수 있습니다. 분석용 뷰는 @Analytics.dataCategory: #DIMENSION으로 선언하여 큐브에서 차원으로 인식되도록 합니다.

ABAP 프로그램에서 I_Plant 활용

CDS View는 ABAP SQL의 1급 시민입니다. 클래식 SELECT 문에서 T001W 대신 I_Plant를 직접 호출할 수 있으며, Association은 path expression으로 자연스럽게 풀어 쓸 수 있습니다.

REPORT z_plant_overview.

CLASS lcl_plant_reader DEFINITION.
  PUBLIC SECTION.
    TYPES:
      BEGIN OF ty_site,
        plant         TYPE i_plant-plant,
        plant_name    TYPE i_plant-plantname,
        company_code  TYPE i_plant-companycode,
        company_name  TYPE i_companycode-companycodename,
        country       TYPE i_plant-country,
      END OF ty_site,
      tt_site TYPE STANDARD TABLE OF ty_site WITH EMPTY KEY.

    METHODS read_sites
      IMPORTING iv_country TYPE land1
      RETURNING VALUE(rt_sites) TYPE tt_site
      RAISING   cx_sy_open_sql_db.
ENDCLASS.

CLASS lcl_plant_reader IMPLEMENTATION.
  METHOD read_sites.
    SELECT
        site~plant,
        site~plantname     AS plant_name,
        site~companycode   AS company_code,
        site~\_CompanyCode-companycodename AS company_name,
        site~country
      FROM i_plant AS site
      WHERE site~country = @iv_country
      INTO TABLE @rt_sites.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  DATA(lo_reader) = NEW lcl_plant_reader( ).
  TRY.
      DATA(lt_kr_sites) = lo_reader->read_sites( 'KR' ).
      LOOP AT lt_kr_sites INTO DATA(ls_site).
        WRITE: / ls_site-plant,
                 ls_site-plant_name,
                 ls_site-company_code,
                 ls_site-company_name.
      ENDLOOP.
    CATCH cx_sy_open_sql_db INTO DATA(lx_db).
      MESSAGE lx_db->get_text( ) TYPE 'E'.
  ENDTRY.

위 코드에서 site~\_CompanyCode-companycodename이 path expression입니다. ABAP 컴파일러가 자동으로 LEFT OUTER JOIN을 생성하므로 개발자는 회사코드 마스터를 명시적으로 JOIN할 필요가 없습니다. RAP 환경에서는 동일한 I_Plant를 Behavior Definition의 참조 모델이나 Value Help로도 활용할 수 있습니다.

/* Value Help 시나리오에서 I_Plant를 검색 도움으로 사용 */
@Search.searchable: true
define view entity ZC_PlantValueHelp
  as select from I_Plant
{
  @Search.defaultSearchElement: true
  key Plant,
  @Search.defaultSearchElement: true
  PlantName,
  CompanyCode,
  Country
}

운영 실무에서의 주의 사항

표준 CDS View라고 해서 무조건 신뢰할 수 있는 것은 아닙니다. 실제 프로젝트에서 자주 겪는 함정을 정리하면 다음과 같습니다.

  • 릴리스 상태 확인 — 표준 뷰의 C1/C2/C3 릴리스 컨트랙트를 확인해야 합니다. C1만 클라우드 확장에서 안전하게 사용 가능합니다.
  • 평가영역 ≠ 플랜트 케이스 — 평가영역이 회사코드 단위로 설정된 경우 BWKEY = BUKRS가 되어, T001K를 통한 매핑이 다르게 동작할 수 있습니다. I_Plant의 CompanyCode가 비어 보이는 사례를 점검할 때 가장 먼저 확인할 지점입니다.
  • 주소 캐싱 차이 — 일부 시스템에서는 T001W 자체에 주소 필드가 캐싱되어 있고, 다른 환경에서는 ADRC를 통해 조회됩니다. CountryName이 누락되어 보인다면 ADRC와의 연결 또는 국가 텍스트 언어 필터링을 확인합니다.
  • 권한 체크@AccessControl.authorizationCheck: #CHECK가 활성화되어 있으면 DCL 규칙에 따라 사용자가 접근할 수 있는 플랜트만 반환됩니다. 배치 사용자가 데이터 누락을 호소한다면 DCL 권한 객체를 먼저 점검해야 합니다.
  • 버퍼링 전략 — T001W는 전통적으로 완전 버퍼링되는 마스터이지만, CDS View는 SQL push-down 특성상 버퍼를 우회할 수 있습니다. 고빈도 조회 시 ABAP 측에서 명시적인 캐싱 패턴을 고려합니다.
  • 성능 모니터링 — Association을 과도하게 펼친 Consumption View는 HANA에서 비효율적인 실행 계획을 만들 수 있으므로 SQL Trace(ST05)와 PlanViz로 검증하는 것이 권장됩니다.

FAQ 형태로 자주 묻는 세 가지 질문을 정리합니다.

  1. Q. I_Plant와 P_Plant, C_Plant 중 무엇을 써야 하나요? — 재사용 목적으로 가져다 쓸 때는 인터페이스 뷰인 I_Plant가 권장됩니다. P_(Private)는 SAP 내부용, C_(Consumption)는 특정 Fiori/Analytical 시나리오용입니다.
  2. Q. 커스텀 필드를 추가하려면 어떻게 하나요? — 표준 뷰를 직접 수정하지 않고, Extension View 또는 자체 Consumption View에서 Custom Field를 SELECT하는 패턴이 안전합니다. S/4HANA Cloud에서는 Custom Fields and Logic 앱과 연동합니다.
  3. Q. 회사코드가 NULL로 나오는 플랜트가 있어요. — 평가영역 설정(T001K) 누락, 또는 해당 플랜트가 회계와 연결되지 않은 순수 물류 거점일 가능성이 있습니다. T001W-BWKEY와 T001K의 매핑을 SE16에서 우선 확인합니다.

관련 주제와 확장 방향

I_Plant에 익숙해졌다면 다음 영역으로 시야를 넓혀볼 수 있습니다. 첫째, I_StoragLocation(저장위치, T001L 기반)을 결합하여 플랜트-저장위치 계층을 모델링합니다. 둘째, RAP Managed BO를 작성하여 플랜트 기반 마스터를 직접 편집하는 Fiori 앱을 구성합니다. 셋째, Embedded Analytics에서 I_Plant를 차원으로 활용하여 매출/생산 KPI 큐브를 만듭니다. 넷째, CDS Access Control을 사용해 사용자별 플랜트 권한 모델을 선언적으로 적용합니다. 다섯째, Service Binding을 통해 OData V4 서비스로 외부 시스템에 노출합니다.

댓글 0

아직 댓글이 없습니다.