개요 및 이 글에서 다루는 범위
이 글은 SAP S/4HANA의 CDS View인 I_ActivityType을 중심으로 CO(Controlling) 모듈의 활동 유형 마스터 데이터를 어떻게 조회하고 실무 시나리오에 활용하는지 다룹니다. CSLA는 원가 센터가 제공하는 서비스 단위(기계 시간, 인건비 시간 등)와 배부 요율을 관리하는 객체이며, I_ActivityType은 이 마스터 데이터를 CDS 계층에서 표준 방식으로 노출하는 뷰입니다.
- I_ActivityType 뷰의 필드 구조와 연관 뷰 파악
- ABAP CDS에서 원가 센터 뷰와 조인해 배부 요율 조회
- Fiori Elements/RAP 소비 시나리오에 맞는 서비스 정의
- 성능·권한·로깅을 고려한 프로덕션 수준 코드 작성
사전에 알고 있으면 좋은 것들
이 글은 ABAP CDS View 문법(@AbapCatalog, @ObjectModel), CO 모듈의 기본 개념(원가 센터, 활동 유형, 내부 배부), 그리고 SAP S/4HANA의 Virtual Data Model(VDM) 계층(Basic/Composite/Consumption) 구분을 이해하고 있다는 전제 하에 진행합니다. RAP(ABAP RESTful Application Programming Model) 기본 흐름을 알면 3단계 예제 이해가 수월합니다.
환경 및 버전 준비물
실습에 사용한 환경은 다음과 같습니다.
- SAP S/4HANA 2022 또는 2023 On-Premise (Cloud Private/Public Edition에서도 유사한 뷰 제공, 단 필드 노출 범위 차이 있음)
- ABAP Development Tools (ADT) 3.36 이상, Eclipse 2023-09 기반
- SAP GUI 8.00 (CSKB/CSKA/CSLA 테이블 확인용)
- 테스트용 CO 조직: 원가 센터(KOSTL), 활동 유형(LSTAR), 컨트롤링 영역(KOKRS)이 마스터 데이터로 세팅되어 있어야 합니다
- 권한:
S_TCODE(SE16, KL03),K_CSKS,K_CSLA조회 권한
테이블 관점에서 활동 유형 마스터는 CSLA(기본 정보)/CSLT(텍스트)에 저장되며, 배부 요율은 COST/COKS 관련 계획 테이블에 시간의존적으로 관리됩니다. I_ActivityType은 이 중 CSLA/CSLT를 조합해 노출한 Basic 뷰로 이해하면 됩니다.
핵심 개념 짚어보기
CO 모듈에서 "활동(Activity)"은 원가 센터가 다른 원가 객체에 제공하는 서비스 단위입니다. 예를 들어 생산 원가 센터 MECH-01이 "기계 시간(MHR)" 활동을 시간당 45,000원의 배부 요율로 제공하면, 제조 오더가 기계를 3시간 사용했을 때 135,000원이 원가 센터에서 오더로 배부됩니다. 이때 "MHR"이 활동 유형이며, "45,000원/시간"이 배부 요율(Activity Rate)입니다.
이 관계를 카페 원두 도매로 비유하면 이해가 쉽습니다. 원가 센터는 로스팅 공장, 활동 유형은 원두 종류(에스프레소용/드립용), 배부 요율은 kg당 단가, 소비하는 원가 객체는 각 카페 지점에 해당합니다. I_ActivityType은 이 중 "원두 종류 카탈로그"만 뽑아 보여주는 뷰라고 볼 수 있습니다.
계층 관점에서 I_ActivityType은 Basic Interface View(I_ 접두어)에 속하고, 상위에서 C_ActivityType과 같은 Consumption 뷰나 Fiori 앱이 이를 참조합니다. 주요 필드는 대략 다음과 같습니다.
ControllingArea: 컨트롤링 영역 (KOKRS)ActivityType: 활동 유형 코드 (LSTAR)ActivityTypeName: 활동 유형 명칭ActivityUnit: 활동 단위 (예: HR, MIN, KG)ActivityTypeCategory: 활동 유형 범주 (1=수동, 2=간접 결정 등)ValidityStartDate/ValidityEndDate: 유효 기간
배부 요율 자체는 I_ActivityType에는 직접 포함되지 않는 것이 일반적이며, 계획 데이터를 노출하는 별도 CDS 뷰(예: I_ActivityTypePrice 계열)와 조인해서 얻습니다. 이 점이 초보자가 자주 혼동하는 부분입니다.
1단계: 활동 유형 목록을 조회하는 기본 예제
가장 단순한 형태로 특정 컨트롤링 영역의 활동 유형 목록을 뽑아봅니다. 실무에서는 마스터 데이터 검증이나 F4 도움말 소스로 자주 사용됩니다.
@AbapCatalog.sqlViewName: 'ZVACTTYPBASIC'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Activity Type Basic List'
define view Z_ActivityTypeBasic
as select from I_ActivityType
{
key ControllingArea,
key ActivityType,
ActivityTypeName,
ActivityUnit,
ActivityTypeCategory,
ValidityStartDate,
ValidityEndDate
}
where
ControllingArea = 'A000'
and ValidityEndDate >= $session.system_date
실행 후 ADT의 Data Preview에서 유효한 활동 유형만 필터링되어 조회되는지 확인합니다. 이 뷰만으로도 "현재 유효한 활동 유형 목록"이라는 최소 기능은 충족됩니다.
2단계: 원가 센터·배부 요율과 조인하는 실무 시나리오
실무에서는 활동 유형 자체보다 "특정 원가 센터가 어떤 활동 유형을 어떤 요율로 제공하는가"가 훨씬 자주 필요합니다. 여기서는 원가 센터 뷰(I_CostCenter) 및 활동 요율 뷰와 조인하고, ABAP 클래스에서 예외 처리·로깅을 추가한 형태를 보여줍니다.
@AbapCatalog.sqlViewName: 'ZVCCACTRATE'
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Cost Center x Activity Type Rate'
define view Z_CostCenterActivityRate
as select from I_ActivityType as at
inner join I_CostCenterActivityTypeCombination as cc
on cc.ControllingArea = at.ControllingArea
and cc.ActivityType = at.ActivityType
left outer to one join I_ActivityTypePrice as pr
on pr.ControllingArea = at.ControllingArea
and pr.ActivityType = at.ActivityType
and pr.CostCenter = cc.CostCenter
{
key at.ControllingArea,
key cc.CostCenter,
key at.ActivityType,
at.ActivityTypeName,
at.ActivityUnit,
pr.FiscalYear,
pr.FiscalPeriod,
pr.PlannedActivityPrice,
pr.Currency
}
where
at.ValidityEndDate >= $session.system_date
주의할 점은 조합 뷰 이름과 요율 뷰 이름은 릴리즈에 따라 다르게 제공된다는 점입니다. On-Premise에서는 I_ActivityTypePrice가 없을 수 있으므로, 없다면 COST 테이블 기반의 커스텀 Basic 뷰를 먼저 만든 뒤 조인하는 방식으로 우회합니다.
이 뷰를 ABAP에서 소비하는 클래스는 다음과 같이 작성합니다.
CLASS zcl_activity_rate_reader DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES: BEGIN OF ty_rate,
cost_center TYPE kostl,
activity_type TYPE lstar,
activity_name TYPE text40,
planned_price TYPE p LENGTH 15 DECIMALS 2,
currency TYPE waers,
END OF ty_rate,
tt_rate TYPE STANDARD TABLE OF ty_rate WITH KEY cost_center activity_type.
METHODS read_rates
IMPORTING iv_controlling_area TYPE kokrs
iv_cost_center TYPE kostl OPTIONAL
RETURNING VALUE(rt_rates) TYPE tt_rate
RAISING cx_sy_open_sql_db.
ENDCLASS.
CLASS zcl_activity_rate_reader IMPLEMENTATION.
METHOD read_rates.
TRY.
SELECT cost_center,
activity_type,
activitytypename AS activity_name,
plannedactivityprice AS planned_price,
currency
FROM z_costcenteractivityrate
WHERE controllingarea = @iv_controlling_area
AND ( @iv_cost_center IS INITIAL OR cost_center = @iv_cost_center )
INTO CORRESPONDING FIELDS OF TABLE @rt_rates.
IF rt_rates IS INITIAL.
cl_bali_log_db_writer=>log_message(
iv_severity = 'W'
iv_text = |No activity rates found for { iv_controlling_area }| ).
ENDIF.
CATCH cx_sy_open_sql_db INTO DATA(lx_sql).
cl_bali_log_db_writer=>log_message(
iv_severity = 'E'
iv_text = lx_sql->get_text( ) ).
RAISE EXCEPTION lx_sql.
ENDTRY.
ENDMETHOD.
ENDCLASS.
로깅 부분은 실제 프로젝트에서는 if_bali_log 인터페이스를 통한 Application Log(SLG1) 기록으로 대체하는 편이 운영 관점에서 안전합니다.
3단계: RAP 서비스로 노출하는 프로덕션 예제
운영 환경에서는 위 뷰를 RAP 기반 OData 서비스로 노출하고, DCL(Data Control Language)로 권한을 걸며, 성능을 위해 인덱싱/버퍼링을 고려합니다.
@AccessControl.authorizationCheck: #CHECK
@Metadata.allowExtensions: true
@EndUserText.label: 'Activity Rate Consumption'
@Search.searchable: true
define root view entity Z_C_ActivityRate
provider contract transactional_query
as projection on Z_CostCenterActivityRate
{
key ControllingArea,
key CostCenter,
key ActivityType,
@Search.defaultSearchElement: true
ActivityTypeName,
ActivityUnit,
FiscalYear,
FiscalPeriod,
@Semantics.amount.currencyCode: 'Currency'
PlannedActivityPrice,
@Semantics.currencyCode: true
Currency
}
@EndUserText.label: 'DCL for Activity Rate'
@MappingRole: true
define role Z_ActivityRate_Role {
grant select on Z_C_ActivityRate
where (ControllingArea) = aspect pfcg_auth( K_TKA, KOKRS, ACTVT = '03' )
and (CostCenter) = aspect pfcg_auth( K_CSKS, KOSTL, ACTVT = '03' );
}
서비스 정의와 바인딩까지 마치면 Fiori Elements List Report로 즉시 소비 가능합니다. 추가로 다음을 권장합니다.
- 단위 테스트는
CL_CDS_TEST_ENVIRONMENT를 이용해I_ActivityType과 관련 뷰를 더블(double)로 대체한 뒤, 특정 요율 시나리오에서 프로젝션 뷰가 기대한 값을 반환하는지 검증합니다. - 성능 관점에서는 대량 조회 시
ControllingArea + CostCenter를 반드시 필터에 포함시키고, 필요하면@ObjectModel.usageType.dataClass: #MASTER힌트로 마스터 성격을 명시합니다. - 보안 관점에서는 DCL 없이 배포하지 않도록 CI 파이프라인에서
@AccessControl.authorizationCheck: #NOT_REQUIRED인 뷰를 자동 검출해 리뷰 게이트를 겁니다.
흔한 실수와 트러블슈팅
Q1. I_ActivityType에서 배부 요율(Price) 필드가 안 보입니다.
A. I_ActivityType은 마스터 성격의 Basic 뷰라 요율은 포함하지 않는 것이 일반적입니다. 요율은 I_ActivityTypePrice 계열, 없다면 COST 테이블 기반 커스텀 뷰와 조인해야 합니다.
Q2. 유효 기간 필터를 걸었는데 만료된 활동 유형이 계속 조회됩니다.
A. CSLA는 시간의존적(time-dependent) 마스터라 동일 ActivityType에 여러 유효 구간 레코드가 존재합니다. ValidityEndDate >= $session.system_date and ValidityStartDate <= $session.system_date 조건을 함께 걸어야 정확합니다.
Q3. 권한 오류가 뜨는데 SU53에서는 활동 유형 관련 오브젝트가 안 잡힙니다.
A. CO 권한은 원가 센터 오브젝트(K_CSKS) 및 컨트롤링 영역(K_TKA)에 의존하는 경우가 많습니다. DCL에서 K_CSKS/K_TKA를 매핑했는지 먼저 확인하고, 다음으로 ST01 권한 트레이스를 켜서 실제 체크 오브젝트를 잡아냅니다.
그 외 자주 마주치는 이슈로는, 컨트롤링 영역 통화와 원가 센터 통화가 달라 요율 조회 결과가 오해되는 경우가 있습니다. @Semantics.amount.currencyCode 어노테이션과 함께 통화 필드를 반드시 노출해 UI에서 혼동을 방지하는 것이 좋습니다.
이어서 살펴보면 좋은 주제들
I_CostCenter,I_CostCenterText와의 조인을 통한 원가 센터 그룹별 요율 대시보드- Analytical CDS View(
@Analytics.dataCategory: #CUBE)로 전환해 SAC(SAP Analytics Cloud) 라이브 연결로 노출 - RAP Behavior Definition을 통해 요율을 커스텀 액션으로 시뮬레이션
- Embedded Steampunk / SAP BTP ABAP Environment에서
I_ActivityType릴리즈 상태 확인
댓글 0
아직 댓글이 없습니다.