개요 및 활용 시나리오
SAP S/4HANA Customer Service(CS) 모듈에서 서비스 오더는 고객 장비의 수리, 점검, 정기 유지보수 같은 현장 서비스 업무를 처리하는 핵심 트랜잭션 문서입니다. I_ServiceOrder는 이러한 서비스 오더 헤더 데이터를 가상 데이터 모델(VDM, Virtual Data Model) 관점에서 노출하는 인터페이스 CDS View입니다. 이 글에서는 I_ServiceOrder의 필드 구조, 연관(Association) 관계, 그리고 고객 정보와의 연계 패턴을 살펴보고 실전 ABAP/CDS 예제로 보고서 개발 방법을 정리합니다.
- I_ServiceOrder의 주요 필드와 키 구조 파악
- SoldToParty, ShipToParty 등 고객 파트너 정보 연계
- I_BusinessPartner, I_Product Association 활용
- 서비스 오더 분석 보고서 CDS View 작성 패턴
- RAP/ODATA 노출 시 고려 사항
알아 두면 좋은 배경
이 글은 ABAP CDS View 기본 문법(define view, association, annotation)과 CS 모듈의 기본 트랜잭션(IW31/IW32, S/4HANA에서는 Manage Service Orders Fiori 앱)을 한 번이라도 접해 본 개발자를 대상으로 합니다. 또한 비즈니스 파트너(BP) 통합 모델에서 Customer가 Business Partner로 일원화되었다는 점, S/4HANA에서 CS 데이터가 어떻게 BP 중심으로 재편되었는지에 대한 이해가 있으면 본문 이해가 빠릅니다.
실행 환경과 사전 점검
이 글의 코드는 다음 환경을 기준으로 작성되었습니다.
- SAP S/4HANA 2022 FPS01 또는 2023 (On-Premise) — 클라우드 에디션의 경우 일부 필드명이 다를 수 있음
- ABAP Development Tools (ADT) for Eclipse 2023-06 이상
- CDS Annotation:
@AbapCatalog.sqlViewName(구식) 또는 어노테이션 없는 CDS Entity 문법 모두 사용 가능 - 권한: S_DEVELOP(ABAP 개발), CS 모듈 데이터 조회를 위한
I_KK관련 권한 오브젝트 - 참고 트랜잭션: SE11(테이블 확인용
AUFK,AFIH), SEGW(서비스 노출 시)
S/4HANA Cloud Public Edition에서는 I_ServiceOrder가 Released 상태인지 Object API의 Released Objects에서 먼저 확인하는 것을 권장합니다. 일반적으로 C1 릴리스 상태여야 ABAP 코드에서 직접 사용 가능합니다.
핵심 개념과 데이터 모델 구조
서비스 오더는 전통적으로 PM(Plant Maintenance)과 동일한 오더 헤더 테이블 AUFK, CS/PM 확장 테이블 AFIH, 오퍼레이션 AFVC/AFVV를 기반으로 합니다. I_ServiceOrder는 이 분산된 테이블을 비즈니스 의미 단위로 묶어 단일 뷰로 추상화한 인터페이스 레이어입니다.
CDS View 계층 구조를 비유로 풀면 다음과 같습니다. 데이터베이스 테이블(AUFK, AFIH)은 원자재 창고, I_ServiceOrder는 가공된 부품, C_ServiceOrderTP나 Fiori용 Consumption View는 완제품에 해당합니다. 개발자는 가공된 부품 단계(I_ 레벨)에서 시작해 자신의 보고서 요구사항에 맞춰 조립합니다.
주요 필드 그룹은 다음과 같이 정리할 수 있습니다.
- 식별자:
ServiceOrder(오더 번호),ServiceOrderType(SM01 등 오더 유형),ServiceOrderUUID - 조직 단위:
MaintenancePlanningPlant,MainWorkCenter,ResponsibleCostCenter,CompanyCode - 비즈니스 파트너:
SoldToParty,ShipToParty,BillToParty,ContactPerson— 모두 BP 번호로 통일 - 장비/기능위치:
TechnicalObject,TechnicalObjectType,Equipment,FunctionalLocation - 일정/상태:
ServiceOrderPlannedStartDateTime,ServiceOrderActualEndDateTime,ServiceProcessingStatus - 금액:
EstimatedCostAmount,NetAmount,CurrencyCode
연관(Association)으로 노출되는 대표 엔티티에는 _BusinessPartner(SoldToParty 기준), _ServiceOrderItem(아이템), _ServiceOrderPartner(파트너 함수 전체), _FunctionalLocation, _Equipment, _ServiceOrderOperation 등이 있습니다. 이를 점 표기법(_BusinessPartner.BusinessPartnerName)으로 한 줄에 펼쳐 쓸 수 있는 것이 CDS View 활용의 핵심입니다.
1단계 — 기본 조회 예제
먼저 I_ServiceOrder를 그대로 사용해 특정 플랜트의 오픈 서비스 오더를 가져오는 가장 단순한 예제입니다. 시나리오는 "수도권 지원센터(플랜트 1010)에서 오늘 기준 미완료 서비스 오더 목록"을 뽑는 것입니다.
REPORT z_cs_open_svc_orders.
DATA: lt_svc_orders TYPE TABLE OF i_serviceorder,
lv_today TYPE dats.
lv_today = sy-datum.
SELECT serviceorder,
serviceordertype,
serviceorderdescription,
soldtoparty,
maintenanceplanningplant,
serviceorderplannedstartdatetime,
serviceprocessingstatus
FROM i_serviceorder
WHERE maintenanceplanningplant = '1010'
AND serviceprocessingstatus <> 'CLSD'
INTO TABLE @lt_svc_orders.
LOOP AT lt_svc_orders ASSIGNING FIELD-SYMBOL(<fs>).
WRITE: / <fs>-serviceorder,
<fs>-serviceorderdescription,
<fs>-soldtoparty.
ENDLOOP.
주의 깊게 볼 점은 두 가지입니다. 첫째, I_ServiceOrder는 인터페이스 뷰이므로 SELECT 문에 직접 사용해도 되지만, 화면 표시용 텍스트 변환(예: 상태 코드 → 설명)은 별도로 처리해야 합니다. 둘째, SoldToParty 필드는 BP 번호(10자리) 형식으로 반환되므로 화면 출력 시 고객명 매핑이 필요합니다.
2단계 — 고객 정보 연계와 로깅이 포함된 보고서
실무에서는 "서비스 오더 + 고객명 + 장비 정보"를 함께 표시해야 합니다. CDS View를 새로 정의해 _BusinessPartner와 _Equipment Association을 활용합니다.
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'CS Service Order with Customer'
define view entity ZC_CsServiceOrderCustomer
as select from I_ServiceOrder as ServiceOrder
association [0..1] to I_BusinessPartner as _Customer
on $projection.SoldToParty = _Customer.BusinessPartner
association [0..1] to I_EquipmentByEquipment as _Equipment
on $projection.Equipment = _Equipment.Equipment
{
key ServiceOrder,
ServiceOrderType,
ServiceOrderDescription,
SoldToParty,
_Customer.BusinessPartnerFullName as CustomerName,
_Customer.BusinessPartnerCategory as CustomerCategory,
Equipment,
_Equipment.EquipmentName as EquipmentDescription,
MaintenancePlanningPlant,
ServiceOrderPlannedStartDateTime,
ServiceOrderActualEndDateTime,
ServiceProcessingStatus,
_Customer,
_Equipment
}
이제 ABAP 측에서는 단일 SELECT만으로 고객명까지 한 번에 가져올 수 있습니다. 운영 환경을 가정해 예외 처리와 Application Log 기록을 추가합니다.
CLASS zcl_cs_svc_report DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES: BEGIN OF ty_result,
service_order TYPE zc_csserviceordercustomer-serviceorder,
customer_name TYPE zc_csserviceordercustomer-customername,
equipment_desc TYPE zc_csserviceordercustomer-equipmentdescription,
planned_start TYPE zc_csserviceordercustomer-serviceorderplannedstartdatetime,
END OF ty_result.
METHODS fetch
IMPORTING iv_plant TYPE werks_d
iv_from_date TYPE dats
RETURNING VALUE(rt_result) TYPE STANDARD TABLE OF ty_result
RAISING cx_sy_open_sql_db.
ENDCLASS.
CLASS zcl_cs_svc_report IMPLEMENTATION.
METHOD fetch.
DATA(lv_from_ts) = CONV timestamp( |{ iv_from_date }000000| ).
TRY.
SELECT serviceorder,
customername,
equipmentdescription,
serviceorderplannedstartdatetime
FROM zc_csserviceordercustomer
WHERE maintenanceplanningplant = @iv_plant
AND serviceorderplannedstartdatetime >= @lv_from_ts
AND serviceprocessingstatus <> 'CLSD'
ORDER BY serviceorderplannedstartdatetime
INTO CORRESPONDING FIELDS OF TABLE @rt_result.
cl_demo_output=>write( |Fetched { lines( rt_result ) } orders for plant { iv_plant }| ).
CATCH cx_sy_open_sql_db INTO DATA(lx_db).
MESSAGE lx_db->get_text( ) TYPE 'E'.
RAISE EXCEPTION lx_db.
ENDTRY.
ENDMETHOD.
ENDCLASS.
로깅은 cl_bali_* 클래스(신 Application Log API)나 BAL_LOG_* 함수 모듈로 대체하는 것을 권장합니다. 위 예제는 데모 출력으로 단순화했습니다.
3단계 — 프로덕션 수준의 분석 뷰와 ODATA 노출
경영진 리포트나 Fiori Analytical List Page(ALP)에 노출할 때는 집계 기능과 어노테이션을 추가한 Composite/Consumption 뷰가 필요합니다. 다음은 고객별 미처리 서비스 오더 건수와 평균 처리일을 집계하는 분석 뷰 예시입니다.
@Analytics.dataCategory: #CUBE
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'CS Service Order KPIs by Customer'
@OData.publish: true
define view entity ZC_CsServiceOrderKpi
as select from ZC_CsServiceOrderCustomer
{
key SoldToParty,
key MaintenancePlanningPlant,
CustomerName,
@DefaultAggregation: #COUNT
ServiceOrder as OrderCount,
@DefaultAggregation: #SUM
cast(
case when ServiceProcessingStatus <> 'CLSD' then 1 else 0 end
as abap.int4 ) as OpenOrderCount,
@DefaultAggregation: #AVG
cast(
dats_days_between(
cast( ServiceOrderPlannedStartDateTime as abap.dats ),
cast( ServiceOrderActualEndDateTime as abap.dats )
) as abap.dec(7,2) ) as AvgLeadTimeDays
}
group by SoldToParty, MaintenancePlanningPlant, CustomerName
프로덕션에서는 다음을 추가로 점검합니다.
- 성능:
I_ServiceOrder는 다수의 Association을 펼치므로, 큰 데이터셋에서는 필요한 필드만 SELECT하고 WHERE 절에 키 필드(ServiceOrder,MaintenancePlanningPlant) 또는 인덱스 컬럼을 우선 배치합니다. - 권한:
@AccessControl.authorizationCheck: #CHECK는 DCL(Access Control)이 정의된 경우에만 효력이 있습니다. CS 권한 오브젝트(예:I_INGRP,I_QMEL)를 매핑한 DCL을 별도로 작성하는 것이 권장됩니다. - 테스트: ABAP Unit Test에서
cl_osql_test_environment를 활용해I_ServiceOrder를 더블(Double)로 치환하면 실제 DB 의존 없이 로직 검증이 가능합니다. - 버전 호환: 일부 필드(예:
ServiceOrderUUID)는 S/4HANA 2021 이후 도입되어 구버전과 코드 호환에 주의가 필요합니다.
자주 마주치는 함정과 해결
Q1. I_ServiceOrder에서 SoldToParty가 비어 있는 레코드가 많습니다. 왜 그런가요?
A. 모든 서비스 오더 유형이 외부 고객을 가지지는 않습니다. 내부 수리(자사 장비 정기점검) 오더는 SoldToParty가 비어 있을 수 있습니다. 이 경우 파트너 함수 전체를 보려면 _ServiceOrderPartner Association을 사용해 PartnerFunction 별로 조회하세요. 또한 BP 통합이 완료되지 않은 마이그레이션 직후 데이터에도 결측이 나타날 수 있습니다.
Q2. CDS View에서 _Customer.BusinessPartnerFullName을 가져왔는데 항상 NULL입니다.
A. I_BusinessPartner의 BusinessPartnerFullName은 BP 카테고리가 Person(1)일 때만 채워지는 경우가 많고, Organization(2)은 OrganizationBPName1~4 필드를 조합해야 합니다. 일반적으로 두 케이스를 case로 분기 처리하거나 I_BusinessPartnerWithName 같은 별도 뷰를 사용하는 것이 권장됩니다.
Q3. SELECT FROM i_serviceorder가 너무 느립니다.
A. 인터페이스 뷰는 다수의 JOIN/UNION을 내포할 수 있습니다. (1) WHERE에 키 필드 사용, (2) 필요한 Association만 펼치기, (3) 화면 페이지네이션이 필요하다면 UP TO n ROWS와 키 기반 keyset pagination 적용, (4) 대량 분석은 @Analytics.dataCategory: #CUBE 뷰를 별도로 만들어 HANA 엔진의 OLAP 최적화 경로를 타도록 분리하는 방식을 권장합니다.
Q4. RAP Business Object로 만들고 싶은데 가능한가요?
A. 읽기 전용 시나리오라면 I_ServiceOrder를 Projection View로 감싸 Read-only RAP BO를 손쉽게 만들 수 있습니다. 다만 생성/변경은 API_SERVICE_ORDER_SRV(SOAP) 또는 BAPI BAPI_ALM_ORDER_MAINTAIN을 호출하는 Managed/Unmanaged 시나리오로 설계하는 것이 일반적입니다.
이어서 살펴볼 주제
이 글에서 다룬 I_ServiceOrder 헤더 모델을 이해했다면, 다음 단계로는 (1) I_ServiceOrderItem과 I_ServiceOrderOperation을 함께 묶어 작업 단위 분석 뷰 만들기, (2) I_ServiceConfirmation으로 실적 확인 데이터까지 확장, (3) Embedded Analytics의 Query View(@Analytics.query: true)로 Fiori KPI 타일 만들기, (4) RAP 기반 Custom Service Order Extension Field 추가, (5) Event Mesh와 연계해 서비스 오더 상태 변경 이벤트를 외부 시스템으로 푸시하는 패턴을 권장합니다.
더 읽어볼 자료
- SAP Help Portal — SAP S/4HANA On-Premise: Customer Service
- SAP Help Portal — ABAP CDS: Defining Associations
- SAP Help Portal — Virtual Data Model (VDM) for SAP S/4HANA
- SAP API Business Hub — S/4HANA Customer Service APIs
- SAP Community Blogs — Customer Service tag
댓글 0
아직 댓글이 없습니다.