개요 및 이 글에서 다루는 내용
SAP S/4HANA 환경에서 자재 마스터를 다루다 보면 자재 유형(Material Type, MTART)이 거의 모든 비즈니스 로직의 분기점이 됩니다. 완제품(FERT), 원자재(ROH), 반제품(HALB), 서비스(DIEN) 등 자재 유형에 따라 수량 관리, 가치 관리, 구매 허용 여부가 완전히 달라지기 때문입니다. 이 글에서는 자재 유형 코드 마스터를 표준화된 방식으로 조회하는 CDS 뷰 I_MaterialType의 구조와 활용 방법을 다룹니다.
- I_MaterialType 뷰가 T134 테이블과 어떻게 연결되는지 이해
- 주요 필드(MaterialType, IsPurchaseAllowed, MaterialIsInventoryManaged 등) 의미 파악
- ABAP 코드에서 SELECT 문으로 자재 유형 조건 분기 처리
- _Text association을 통한 다국어 텍스트 결합
- 실무 시나리오: 판매오더/구매요청에서 자재 유형 검증 로직 구현
알아두면 좋은 배경 지식
이 글을 편하게 따라가려면 ABAP Open SQL 문법(SELECT, JOIN, INTO TABLE), CDS 뷰의 기본 개념(@AbapCatalog, association), 그리고 자재 마스터의 기본 구조(MARA, MAKT 등) 정도는 알고 있는 것이 좋습니다. 자재 유형이 무엇인지 모르는 경우라면 SE16에서 T134, T134T 테이블을 한번 열어보고 오시는 것을 권장합니다. CDS 뷰를 ADT(ABAP Development Tools, Eclipse 기반)에서 열어볼 수 있는 환경이면 더욱 좋습니다.
실행 환경과 준비물
이 글의 예제는 다음 환경을 기준으로 작성되었습니다.
- SAP S/4HANA 2022 On-Premise 또는 SAP S/4HANA Cloud Private Edition (2023 권장)
- ABAP Platform 2022 이상 (CDS 뷰 표준 가상 데이터 모델 지원)
- ABAP Development Tools (ADT) for Eclipse 2024-03 버전 이상
- 권한 객체: S_DEVELOP (READ), S_TABU_DIS (T134 조회용)
I_MaterialType은 SAP 표준으로 제공되는 Basic Interface View로, 별도 설치나 활성화 작업은 필요 없습니다. 다만 일부 구버전(예: S/4HANA 1909 이하)에서는 필드 구성이 다를 수 있으므로 ADT에서 직접 뷰 정의를 확인한 후 사용하시기 바랍니다. 테스트 데이터는 표준 출고된 자재 유형(FERT, ROH, HALB, HAWA, DIEN 등)을 그대로 활용합니다.
I_MaterialType의 구조와 동작 원리
SAP의 자재 유형 정보는 전통적으로 T134(자재 유형) 테이블과 T134T(자재 유형 텍스트) 테이블에 저장되어 있었습니다. ABAP 개발자라면 누구나 한 번쯤 다음과 같은 코드를 짜본 경험이 있을 겁니다.
SELECT a~mtart, b~mtbez
FROM t134 AS a
INNER JOIN t134t AS b ON a~mtart = b~mtart
WHERE b~spras = sy-langu
INTO TABLE @DATA(lt_mtype).
문제는 이 코드가 데이터베이스 테이블에 직접 의존한다는 것입니다. SAP가 향후 테이블 구조를 변경하거나, 클라우드 환경에서 직접 접근이 막히면 모든 코드를 수정해야 합니다. 이 문제를 해결하기 위해 SAP는 가상 데이터 모델(VDM, Virtual Data Model)이라는 CDS 뷰 계층을 도입했고, 그 중 자재 유형 마스터를 추상화한 뷰가 바로 I_MaterialType입니다.
비유하자면 T134는 "원재료 창고"이고, I_MaterialType은 "잘 손질되어 진열된 상품"입니다. 개발자는 더 이상 창고로 가서 직접 박스를 뜯을 필요 없이, 진열대에서 필요한 것을 골라오기만 하면 됩니다. SAP가 창고를 옮기든, 박스 포장을 바꾸든, 진열대 인터페이스만 유지하면 개발자 코드는 안전합니다.
I_MaterialType의 주요 필드 구성은 다음과 같습니다.
| 필드명 | 설명 | 원본 컬럼 |
|---|---|---|
| MaterialType | 자재 유형 코드 (Key) | T134-MTART |
| IsPurchaseAllowed | 외부 구매 허용 플래그 | T134-EKALV |
| IsInternalProductionAllowed | 사내 생산 허용 | T134-FBKZ |
| MaterialIsInventoryManaged | 재고 수량 관리 여부 | T134-MNGAS |
| MaterialIsValueManaged | 가치 관리 여부 | T134-WRTAS |
| AuthorizationGroup | 권한 그룹 | T134-BEGRU |
그리고 가장 강력한 무기는 _Text association입니다. 별도로 T134T를 JOIN하지 않고도 association 한 줄로 다국어 텍스트를 가져올 수 있습니다. SAP는 내부적으로 현재 로그온 언어(sy-langu)를 자동으로 매칭하므로, 개발자는 언어 코드 조건문을 작성할 필요가 없습니다.
실전 예제 1단계 — 자재 유형 목록 조회
먼저 가장 기본적인 형태로 자재 유형 전체 목록과 텍스트를 가져와보겠습니다. 사내 시스템에 등록된 자재 유형이 몇 종류이고, 각각이 어떤 속성을 가지는지 확인하는 코드입니다.
REPORT zr_mattype_basic.
DATA: lt_mat_type TYPE TABLE OF i_materialtype.
SELECT MaterialType,
IsPurchaseAllowed,
IsInternalProductionAllowed,
MaterialIsInventoryManaged,
MaterialIsValueManaged
FROM i_materialtype
ORDER BY MaterialType
INTO TABLE @lt_mat_type.
cl_demo_output=>display( lt_mat_type ).
실행하면 FERT, ROH, HALB, HAWA, DIEN, NLAG(비재고 자재) 등의 코드가 각 속성 플래그와 함께 출력됩니다. 예를 들어 DIEN(서비스)은 MaterialIsInventoryManaged가 비활성화되어 있고, FERT(완제품)는 IsInternalProductionAllowed가 활성화되어 있는 식입니다. 이 결과만 봐도 자재 유형이 단순한 분류 코드가 아니라 비즈니스 규칙의 묶음임을 알 수 있습니다.
실전 예제 2단계 — 판매오더 아이템 검증 로직
이번에는 좀 더 실무에 가까운 시나리오입니다. 판매오더 아이템(VBAP)에 등록된 자재가 "판매 가능한 유형"인지 검증해야 한다고 가정해봅시다. 일반적으로 NLAG(비재고)나 일부 내부용 자재 유형은 판매 라인에 들어가면 안 됩니다. _Text association을 활용해 로그 메시지에 사람이 읽을 수 있는 자재 유형명까지 함께 남깁니다.
CLASS zcl_so_mattype_validator DEFINITION
PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES: BEGIN OF ty_invalid_item,
sales_order TYPE vbeln_va,
item_no TYPE posnr_va,
material TYPE matnr,
mat_type TYPE mtart,
type_text TYPE mtbez,
reason TYPE string,
END OF ty_invalid_item.
METHODS validate_sales_items
IMPORTING iv_sales_order TYPE vbeln_va
RETURNING VALUE(rt_errors) TYPE STANDARD TABLE OF ty_invalid_item.
ENDCLASS.
CLASS zcl_so_mattype_validator IMPLEMENTATION.
METHOD validate_sales_items.
SELECT so_item~vbeln AS sales_order,
so_item~posnr AS item_no,
so_item~matnr AS material,
mara~mtart AS mat_type,
mtype~_Text~MaterialTypeName AS type_text
FROM vbap AS so_item
INNER JOIN mara ON mara~matnr = so_item~matnr
INNER JOIN i_materialtype AS mtype
ON mtype~MaterialType = mara~mtart
WHERE so_item~vbeln = @iv_sales_order
AND mtype~MaterialIsInventoryManaged = @abap_false
INTO TABLE @DATA(lt_suspect).
LOOP AT lt_suspect ASSIGNING FIELD-SYMBOL(<ls>).
APPEND VALUE #(
sales_order = <ls>-sales_order
item_no = <ls>-item_no
material = <ls>-material
mat_type = <ls>-mat_type
type_text = <ls>-type_text
reason = |Non-inventory material type cannot be sold|
) TO rt_errors.
ENDLOOP.
ENDMETHOD.
ENDCLASS.
핵심은 두 가지입니다. 첫째, MARA-MTART와 I_MaterialType의 MaterialType을 JOIN하여 자재 유형 속성에 즉시 접근합니다. 둘째, mtype~_Text~MaterialTypeName처럼 association을 통해 텍스트를 가져오므로 T134T를 별도로 JOIN할 필요가 없습니다. SAP가 내부적으로 sy-langu 매칭과 fallback 처리를 알아서 해 줍니다.
실전 예제 3단계 — 구매요청 일괄 처리와 성능 튜닝
마지막으로 대량 데이터를 다루는 프로덕션 수준의 코드입니다. 야간 배치로 구매요청(EBAN)을 대량 생성할 때, 각 자재가 "외부 구매가 허용된 유형"인지 사전 검증하는 시나리오를 가정합니다. 수십만 건의 자재가 입력으로 들어올 수 있으므로 성능과 트랜잭션 안전성이 중요합니다.
CLASS zcl_pr_batch_validator DEFINITION
PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES: BEGIN OF ty_pr_input,
tracking_id TYPE char20,
material TYPE matnr,
quantity TYPE menge_d,
plant TYPE werks_d,
END OF ty_pr_input,
tt_pr_input TYPE STANDARD TABLE OF ty_pr_input WITH KEY material.
METHODS filter_purchasable
IMPORTING it_input TYPE tt_pr_input
EXPORTING et_passed TYPE tt_pr_input
et_rejected TYPE tt_pr_input.
ENDCLASS.
CLASS zcl_pr_batch_validator IMPLEMENTATION.
METHOD filter_purchasable.
DATA(lo_log) = cl_bali_log=>create_with_header(
header = cl_bali_header_setter=>create(
object = 'ZPR_BATCH'
subobject = 'MATTYPE_CHK' ) ).
" 입력에서 중복 제거된 자재 목록 추출
DATA(lt_unique_mat) = VALUE matnr_tab(
FOR <in> IN it_input ( <in>-material ) ).
SORT lt_unique_mat.
DELETE ADJACENT DUPLICATES FROM lt_unique_mat.
" 자재 -> 자재유형 -> 구매허용 여부를 한 번에 조회
SELECT mara~matnr,
mtype~MaterialType,
mtype~IsPurchaseAllowed
FROM mara
INNER JOIN i_materialtype AS mtype
ON mtype~MaterialType = mara~mtart
FOR ALL ENTRIES IN @lt_unique_mat
WHERE mara~matnr = @lt_unique_mat-table_line
INTO TABLE @DATA(lt_check).
" 빠른 조회를 위해 hashed table 변환
DATA lh_check TYPE HASHED TABLE OF
line_of( lt_check ) WITH UNIQUE KEY matnr.
lh_check = CORRESPONDING #( lt_check ).
LOOP AT it_input ASSIGNING FIELD-SYMBOL(<in>).
READ TABLE lh_check
WITH KEY matnr = <in>-material
ASSIGNING FIELD-SYMBOL(<chk>).
IF sy-subrc = 0 AND <chk>-IsPurchaseAllowed = abap_true.
APPEND <in> TO et_passed.
ELSE.
APPEND <in> TO et_rejected.
lo_log->add_item(
item = cl_bali_free_text_setter=>create(
severity = if_bali_constants=>c_severity_warning
text = |Material { <in>-material } rejected: |
&& |purchase not allowed for its material type| ) ).
ENDIF.
ENDLOOP.
cl_bali_log_db=>get_instance( )->save_log( log = lo_log ).
ENDMETHOD.
ENDCLASS.
성능 측면에서 주목할 포인트는 세 가지입니다. 우선 입력 자재 리스트를 중복 제거하여 SELECT 카디널리티를 줄였고, FOR ALL ENTRIES로 단일 라운드트립에 데이터를 모았으며, HASHED TABLE로 O(1) 조회를 보장했습니다. 보안 측면에서는 BAL(Business Application Log) 인프라를 사용해 거부된 자재의 흔적을 감사 로그로 남깁니다. ABAP Unit Test로는 mock 입력 테이블을 만들어 et_passed/et_rejected 비율을 검증하면 됩니다.
자주 마주치는 실수와 해결책
Q1. I_MaterialType을 조회했는데 텍스트가 영어로만 나옵니다. _Text association은 로그온 언어를 우선 시도하고, 없으면 fallback 언어로 채워집니다. 한국어 텍스트가 시스템에 등록되어 있지 않다면 SE63에서 자재 유형 텍스트 번역을 추가하거나, SPRAS 파라미터를 명시적으로 지정한 _Text association 호출을 사용해야 합니다.
Q2. FOR ALL ENTRIES에서 빈 테이블 체크를 빼먹어 전체 데이터가 조회됩니다. ABAP의 고전적인 함정입니다. FOR ALL ENTRIES의 driver table이 비어 있으면 WHERE 절이 무시되어 전체 테이블이 반환됩니다. 위 예제에서는 입력 검증을 메서드 진입부에 추가하여 lt_unique_mat이 비어 있으면 즉시 return하는 가드를 두는 것을 권장합니다.
Q3. 자재 유형 코드를 하드코딩해도 되나요? (예: IF mtart = 'FERT') 일반적으로 비권장합니다. 고객사에 따라 Z자재 유형(예: ZFER, ZSVC)을 추가로 운영하는 경우가 많기 때문에, 코드값보다는 I_MaterialType의 속성 플래그(IsPurchaseAllowed 등)로 분기하는 것이 유지보수에 유리합니다. 표준 코드값을 꼭 써야 한다면 상수 클래스로 분리해 관리하시기 바랍니다.
Q4. T134를 직접 읽던 기존 코드를 모두 바꿔야 하나요? 새로 작성하는 코드는 I_MaterialType을 권장하지만, 운영 중인 레거시는 위험도와 ROI를 봐가며 단계적으로 마이그레이션하면 됩니다. 특히 S/4HANA Cloud로 이전 계획이 있다면 우선순위를 높이는 것이 좋습니다.
이후 활용과 연관 주제
I_MaterialType에 익숙해졌다면 자재 마스터 전체를 추상화한 I_Product, I_ProductText, I_ProductPlant 같은 상위 뷰들로 학습을 확장해보시기 바랍니다. 또한 자재 그룹 마스터인 I_MaterialGroup, 단위 마스터인 I_UnitOfMeasure도 함께 익혀두면 자재 관련 보고서나 OData 서비스를 만들 때 강력한 무기가 됩니다. 한 단계 더 나아간다면 RAP(RESTful Application Programming Model) 위에서 Behavior Definition과 결합하여 자재 유형 검증을 표준 EML 액션으로 노출하는 패턴까지 다뤄볼 만합니다.
댓글 0
아직 댓글이 없습니다.