개요 및 이 글에서 다루는 범위
SAP S/4HANA 환경에서 생산 오더(Production Order) 데이터를 ABAP으로 다룰 때, 과거에는 AUFK, AFKO, AFPO 같은 클러스터 테이블을 직접 JOIN하여 조회하는 방식이 일반적이었습니다. 그러나 S/4HANA 1909 이후 SAP는 가상 데이터 모델(VDM, Virtual Data Model)을 표준화하면서 I_ProductionOrder라는 인터페이스 CDS View를 제공합니다. 이 글은 해당 뷰의 내부 구조와 AUFK 테이블 추상화 방식, 그리고 상태(Status)와 실적(Actual) 데이터를 안정적으로 읽어오는 실무 패턴을 다룹니다.
- AUFK 기반 오더 헤더가 I_ProductionOrder로 노출되는 원리 이해
- 시스템 상태(I_STAT)와 사용자 상태(E_STAT) 조회 방법
- RAP(ABAP RESTful Application Programming Model)에서 소비 패턴 적용
- 성능 함정과 권한 객체 처리에 대한 점검
읽기 전 갖추면 좋은 배경 지식
이 글은 ABAP 7.55 이상 문법과 CDS View 정의 경험이 있다는 가정 하에 작성되었습니다. @AbapCatalog.sqlViewName과 @VDM.viewType 어노테이션의 차이, association(_) vs join의 동작 방식, 그리고 PP 모듈의 오더 카테고리(10=PP, 30=CO 등) 개념을 이미 알고 있다면 흐름을 더 쉽게 따라올 수 있습니다. AUFK, AFKO, AFPO, JEST 테이블의 키 구조를 한 번이라도 본 적이 있으면 도움이 됩니다.
환경, 버전, 사전 준비
본 예제는 SAP S/4HANA 2022 Cloud Private Edition 및 On-Premise 2023 기준으로 검증된 패턴을 기반으로 합니다. ABAP Development Tools(ADT) 3.42 이상이 권장되며, Eclipse 2024-03 버전에서 안정적으로 동작합니다. I_ProductionOrder는 표준 SAP 제공 인터페이스 뷰이므로 별도 설치 없이 시스템에 존재해야 합니다. 만약 ADT의 Open CDS Source에서 해당 뷰가 보이지 않는다면 PP 컴포넌트(BS_FND 또는 S4CORE)의 패치 레벨을 확인해야 합니다.
- SAP S/4HANA 2022 이상 (Cloud Private Edition 또는 On-Premise)
- ABAP 플랫폼 2023 이상 권장
- 권한: S_TABU_DIS의 AU 권한 그룹, S_CARRID 대신 PP 모듈 권한 객체(C_AFKO_AWK)
- 테스트 데이터: Fiori 앱 Manage Production Orders(F2336)로 샘플 오더 생성
핵심 개념: AUFK가 I_ProductionOrder로 추상화되는 방식
AUFK 테이블은 SAP의 모든 오더 타입(PP, CO, PM, QM 등)을 통합 저장하는 헤더 테이블입니다. 즉, 같은 테이블 안에 생산 오더, 내부 오더, 정비 오더가 섞여 있습니다. 이를 구분하는 핵심 필드가 AUTYP(오더 카테고리)입니다. AUTYP=10이 PP의 생산 오더에 해당합니다. I_ProductionOrder는 이 필터링을 내부적으로 수행하면서 동시에 AFKO(오더 헤더 PP 확장), AFPO(오더 아이템), JEST(상태 레코드)를 association으로 묶어 노출합니다.
비유하자면, AUFK는 모든 종류의 차량 등록 정보가 들어 있는 거대한 자동차 등록부이고, I_ProductionOrder는 "이 등록부에서 트럭(생산 오더)만 보여주는 창구"입니다. 창구 직원은 차량 등록부와 트럭 전용 부가 정보를 자동으로 합쳐서 제시하므로, 사용자는 더 이상 AUFK + AFKO를 직접 JOIN할 필요가 없어집니다.
I_ProductionOrder의 association은 보통 다음과 같은 형태로 구성됩니다.
// 개념적 도식 (실제 표준 정의와는 다를 수 있음)
define view I_ProductionOrder
as select from aufk
association [0..*] to I_ProductionOrderItem as _Item
association [0..*] to I_ProductionOrderStatus as _Status
association [0..1] to I_Plant as _Plant
{
key aufk.aufnr as ProductionOrder,
aufk.auart as ProductionOrderType,
aufk.werks as Plant,
aufk.erdat as CreationDate,
_Item,
_Status
}
where aufk.autyp = '10'
여기서 주목할 점은 where autyp = '10' 조건이 뷰 정의에 박혀 있다는 것입니다. 덕분에 ABAP 소비자는 오더 카테고리를 따로 신경 쓰지 않아도 됩니다. 단, 외주 가공 오더(AUTYP=40)나 공정 오더(PI Sheet)는 별도 뷰(I_ProcessOrder)로 분리되어 있으므로 혼동하지 않아야 합니다.
실전 예제 1단계: 기본 조회 패턴
가장 단순한 사용법은 Open SQL로 I_ProductionOrder를 SELECT하는 것입니다. AUFK를 직접 읽을 때와 비교해 코드량이 크게 줄어듭니다.
REPORT z_pp_order_simple_read.
DATA: lt_orders TYPE TABLE OF i_productionorder.
" Plant 1710, 최근 30일 내 생성된 생산 오더 목록
SELECT productionorder,
productionordertype,
plant,
mrpcontroller,
productionplant,
creationdate,
material
FROM i_productionorder
WHERE plant = '1710'
AND creationdate >= @( cl_abap_context_info=>get_system_date( ) - 30 )
INTO TABLE @lt_orders
UP TO 200 ROWS.
LOOP AT lt_orders ASSIGNING FIELD-SYMBOL(<ls_ord>).
WRITE: / <ls_ord>-productionorder,
<ls_ord>-material,
<ls_ord>-creationdate.
ENDLOOP.
AUFK를 직접 다뤘다면 WHERE autyp = '10' AND erdat >= ... 같은 필터를 직접 작성하고, AFKO와의 JOIN으로 Material을 끌어와야 했을 것입니다. CDS View는 이 부분을 모두 흡수합니다.
실전 예제 2단계: 상태와 실적 데이터 결합
실무에서는 단순 목록보다 "현재 진행 중인 오더", "기술적으로 완료된 오더(TECO)", "취소된 오더(LKD)" 같이 상태별로 필터링하는 요구가 많습니다. SAP의 상태는 두 가지로 나뉘는데, 시스템 상태(예: REL, TECO, CNF)는 I_STAT에, 사용자 상태(예: ZQC1, ZRDY)는 E_STAT에 저장되며, 둘 다 JEST 테이블을 통해 활성/비활성 플래그로 관리됩니다. SAP는 이를 I_ProductionOrderStatus 또는 I_OrderStatusByOrderInternalID 같은 뷰로 노출합니다.
CLASS zcl_pp_order_status_reader DEFINITION
PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
BEGIN OF ty_order_overview,
production_order TYPE i_productionorder-productionorder,
material TYPE i_productionorder-material,
plant TYPE i_productionorder-plant,
target_quantity TYPE i_productionorder-totalquantity,
confirmed_quantity TYPE i_productionorder-confirmedyieldquantity,
is_released TYPE abap_bool,
is_teco TYPE abap_bool,
END OF ty_order_overview.
METHODS read_active_orders
IMPORTING iv_plant TYPE werks_d
RETURNING VALUE(rt_result) TYPE STANDARD TABLE OF ty_order_overview
RAISING cx_sy_open_sql_db.
ENDCLASS.
CLASS zcl_pp_order_status_reader IMPLEMENTATION.
METHOD read_active_orders.
SELECT ord~productionorder,
ord~material,
ord~plant,
ord~totalquantity AS target_quantity,
ord~confirmedyieldquantity AS confirmed_quantity,
CASE WHEN st_rel~statusisactive = 'X' THEN 'X' ELSE ' ' END AS is_released,
CASE WHEN st_tec~statusisactive = 'X' THEN 'X' ELSE ' ' END AS is_teco
FROM i_productionorder AS ord
LEFT OUTER JOIN i_productionorderstatus AS st_rel
ON st_rel~productionorder = ord~productionorder
AND st_rel~status = 'REL'
LEFT OUTER JOIN i_productionorderstatus AS st_tec
ON st_tec~productionorder = ord~productionorder
AND st_tec~status = 'TECO'
WHERE ord~plant = @iv_plant
AND ord~orderisdeleted = ' '
INTO TABLE @rt_result.
" 진행 중(릴리즈됐고 TECO 안 됨)만 남기기
DELETE rt_result WHERE is_released = abap_false
OR is_teco = abap_true.
ENDMETHOD.
ENDCLASS.
위 코드는 두 가지 시스템 상태(REL, TECO)를 좌측 외부 조인으로 가져온 뒤, 활성 상태 플래그를 기준으로 "현재 진행 중인 오더"만 추려냅니다. 직접 JEST를 읽는다면 OBJNR(객체 키)을 만들고 OBTYP='OR'로 필터링하고, 상태 코드는 TJ02T에서 다시 텍스트로 매핑해야 합니다. CDS 인터페이스 뷰는 이 변환을 내장하므로 코드가 훨씬 깨끗해집니다.
실전 예제 3단계: RAP 서비스로 노출하면서 권한·로깅 적용
실무에서는 Fiori Elements 화면이나 외부 시스템(MES, IIoT 게이트웨이)에 OData로 노출하는 경우가 많습니다. ABAP RESTful Application Programming Model을 활용해 read-only consumption 뷰로 한 번 더 감싸는 패턴을 권장합니다.
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Production Order Monitoring'
@Metadata.ignorePropagatedAnnotations: true
@VDM.viewType: #CONSUMPTION
@OData.publish: true
define root view entity ZC_ProdOrderMonitor
as select from I_ProductionOrder as Ord
association [0..*] to I_ProductionOrderStatus as _Status
on _Status.ProductionOrder = Ord.ProductionOrder
{
key Ord.ProductionOrder,
Ord.Material,
Ord.Plant,
Ord.MRPController,
Ord.TotalQuantity,
Ord.ConfirmedYieldQuantity,
Ord.ProductionUnit,
Ord.ScheduledStartDate,
Ord.ScheduledFinishDate,
cast(
case
when Ord.TotalQuantity = 0 then 0
else division( Ord.ConfirmedYieldQuantity * 100, Ord.TotalQuantity, 2 )
end as abap.dec(5,2)
) as CompletionRatePct,
_Status
}
where Ord.OrderIsDeleted = ' '
위 consumption 뷰에는 완료율 계산 필드(CompletionRatePct)를 추가했습니다. 이렇게 파생 필드를 뷰 단에서 만들어 두면 OData 클라이언트나 분석 도구에서 동일한 계산을 반복하지 않아도 됩니다. 또한 @AccessControl.authorizationCheck: #CHECK 어노테이션은 DCL(Data Control Language)을 통해 Plant/Order Type 단위로 접근 통제를 적용하라는 신호입니다. PP 권한 객체 C_AFKO_AWK의 BUKRS, WERKS 필드를 DCL로 매핑하면 사용자별로 노출 범위를 자동 제한할 수 있습니다.
@EndUserText.label: 'DCL for ZC_ProdOrderMonitor'
@MappingRole: true
define role ZC_ProdOrderMonitor {
grant select on ZC_ProdOrderMonitor
where ( Plant ) = aspect pfcg_auth ( C_AFKO_AWK, WERKS, ACTVT = '03' );
}
로깅 측면에서는 BAL(Application Log) 또는 cl_bali_log 인스턴스에 SELECT 건수와 응답 시간을 기록해 두면 운영 단계에서 병목 분석이 수월해집니다. 일반적으로 I_ProductionOrder는 association을 통한 lazy join을 활용하므로, 필요한 컬럼만 명시적으로 선택하는 것이 권장됩니다.
자주 마주치는 실수와 점검 사항
첫째, AUFK에는 PP 외 다른 오더가 함께 들어 있다는 점을 잊고 자체 CDS에서 autyp 필터 없이 AUFK를 직접 사용하는 경우가 있습니다. 그 결과 정비 오더(PM)나 내부 오더(CO)가 섞여 들어와 비즈니스 로직이 깨집니다. I_ProductionOrder를 쓰면 자동 해결되지만, 부득이 AUFK를 직접 다뤄야 한다면 반드시 autyp = '10'을 명시하세요.
둘째, 상태 조회 시 시스템 상태와 사용자 상태를 혼동하는 사례입니다. 시스템 상태 키는 'I' + 상태번호이고, 사용자 상태는 'E' + 번호로 저장됩니다. I_ProductionOrderStatus에서 StatusType 필드를 함께 확인하지 않으면 동명의 사용자 상태가 끼어들 수 있습니다.
FAQ 1. I_ProductionOrder에 ORDER 번호로 단건 조회했는데 결과가 비어 있습니다.
대부분 AUFK에는 존재하지만 AUTYP가 10이 아닌 경우입니다. SE16N에서 AUFK-AUFNR로 조회 후 AUTYP를 확인하세요. PM 오더라면I_MaintenanceOrder를, 공정 오더라면I_ProcessOrder를 사용해야 합니다.
FAQ 2. 실적 수량(ConfirmedYieldQuantity)이 AFRU의 합과 일치하지 않습니다.
I_ProductionOrder의 confirmed 필드는 AFPO 또는 헤더 집계 시점에 갱신된 값을 보여줍니다. 실시간 부분 실적까지 보려면I_ProductionOrderConfirmation을 association으로 추가 조회해야 합니다.
FAQ 3. SELECT 성능이 갑자기 느려졌습니다.
WHERE 절에 인덱스 컬럼(PLANT, ORDER_TYPE, CREATION_DATE)이 빠진 경우가 흔합니다. 또한 association(_Status, _Item)을 SELECT 절에 노출했는데 실제로는 사용하지 않는다면 옵티마이저가 join을 수행해 비용이 늘어납니다. 사용하지 않는 association은 제거하거나$expand없이 호출하세요.
셋째, OrderIsDeleted 플래그를 빠뜨리는 실수도 잦습니다. 삭제 표시된 오더가 결과에 포함되어 KPI 집계가 부풀려질 수 있으니, 분석용 쿼리에서는 항상 OrderIsDeleted = ' '를 포함하세요.
이어서 살펴보면 좋은 주제
I_ProductionOrder를 익혔다면 다음으로는 I_ProductionOrderComponent(부품 소요량), I_ProductionOrderOperation(공정), I_ProductionOrderConfirmation(실적 전표)을 association으로 묶어 종단간 PP 데이터 모델을 구성해 보길 권장합니다. 또한 분석용으로는 SAP Analytics Cloud와 연계 가능한 C_ProductionOrderQuery(CDS Analytical Query)를, 트랜잭션 처리용으로는 RAP의 unmanaged scenario에서 BAPI BAPI_PRODORD_CHANGE_STATUS를 호출하는 패턴을 학습하면 실무 적용 범위가 넓어집니다.
관련 자료 링크
- SAP Help Portal — Production Order in SAP S/4HANA
- SAP Help Portal — ABAP CDS Views (ABAP Platform)
- SAP Help Portal — Virtual Data Model (VDM) for S/4HANA
- SAP Help Portal — ABAP RESTful Application Programming Model
- SAP Business Accelerator Hub — S/4HANA Cloud Production Order APIs
- SAP Community — ABAP CDS Views Topic Page
- SAP Blogs — Production Planning Tag
댓글 0
아직 댓글이 없습니다.