ABAP

COEP vs CDS 뷰 — 코스트센터 실비 조회 차이 #shorts #SAP #ABAP

▶ YouTube에서 보기

COEP의 시대가 끝났다 — S/4HANA 비용 아키텍처 전환

ECC 시절 원가회계 담당자에게 COEP는 성전(聖典)이었다. 실적 라인 아이템은 여기 있었고, 배부·정산·재분배 결과도 모두 여기로 흘러들었다. 그러나 S/4HANA로 넘어오면서 회계 데이터 모델은 Universal Journal(ACDOCA)이라는 단일 원장으로 재편되었다. FI/CO 이원 구조가 사라진 자리에 ACDOCA가 들어섰고, COEP는 호환성(compatibility) 뷰로만 남아있다. 즉 여전히 이름은 있지만, 실제 저장소는 아니라는 뜻이다.

이 글에서 다루려는 것은 “그럼 코스트센터 실비를 어떻게 조회할 것인가”라는 실무 질문이다. 정답은 명확하다. ACDOCA 또는 그 위에 얹힌 릴리스된 CDS 뷰인 I_CostCenterCostItem을 쓰는 것이다. 이 글에서 얻어갈 결과는 다음과 같다.

  • 왜 COEP SELECT가 S/4HANA에서 안티패턴인지 이해한다
  • I_CostCenterCostItem의 필드 구성과 동작 원리를 파악한다
  • 회계연도·기간별 비용요소 집계 리포트를 CDS와 ABAP RAP 관점에서 구현한다
  • ACDOCA 직접 접근과의 트레이드오프를 판단할 수 있다
  • 성능 최적화 포인트(필드 선택, WHERE 절, 파티셔닝)를 체득한다

이 글을 읽기 전에 알고 있으면 좋은 것

S/4HANA 재무 데이터 모델(ACDOCA), CDS View 기본 문법, ABAP OpenSQL, CO 모듈의 코스트센터/비용요소 개념, VDM(Virtual Data Model) 계층(Basic/Composite/Consumption) 정도의 배경 지식이 있으면 무리 없이 따라올 수 있다. RAP는 뒷부분에 잠깐 등장하지만 필수는 아니다.

실습 환경과 버전 전제

이 글의 예시는 아래 환경 기준으로 작성했다. 릴리스에 따라 CDS 뷰의 필드 노출 범위가 다를 수 있으니 실제 시스템에서 ADT → Data Preview로 필드 존재 여부를 먼저 확인하는 것을 권장한다.

  • SAP S/4HANA On-Premise 2022 이상 또는 S/4HANA Cloud Public Edition (2023 릴리스 이상)
  • ABAP Development Tools (Eclipse) 최신 버전
  • 테이블: ACDOCA (Universal Journal Entry Line Items)
  • Basic 뷰: I_CostCenterCostItem (ACDOCA를 코스트센터 관점에서 투영한 릴리스 CDS 뷰)
  • Composite 뷰: C_CostCenterCostLnItm (Fiori Apps 소비용)
  • 권한 오브젝트: K_CSKS_SET(코스트센터), F_BKPF_BUK(회사코드)

Cloud 환경에서는 릴리스된 CDS만 접근 가능하므로 ACDOCA 직접 SELECT가 원천 차단된다. 반면 On-Prem은 여전히 가능하지만, 이 글에서 다룰 이유로 CDS 경유가 일반적으로 더 안전한 선택이다.

핵심 개념 — Universal Journal과 Compatibility Layer

ACDOCA를 도서관에 비유하면 이해가 쉽다. 과거에는 소설(FI: BSEG), 잡지(CO: COEP), 전문서적(자산: ANEP)이 각각 다른 서고에 흩어져 있었다. Universal Journal은 이 모든 자료를 하나의 통합 서고에 물리적으로 모아둔 구조다. 원본은 하나만 존재하고, 사용자는 원하는 관점(FI 관점, CO 관점, PA 관점)으로 열람 카드만 다르게 받는다.

이 열람 카드가 바로 Compatibility View다. COEP, BSEG, GLPCA 같은 이름을 그대로 유지하면서 실제 데이터는 ACDOCA에서 온다. 문제는 이 카드가 “원본 서고에 있는 모든 것을 정확히 보여주지 못한다”는 데 있다. 카드에 인쇄된 컬럼이 원본보다 좁기 때문이다. 예를 들어 COEP에는 세그먼트(SEGMENT), 이익센터 파트너(PPRCTR), 기능영역(FKBER) 같은 신필드가 제대로 매핑되지 않거나 특정 시나리오에서 값이 비는 경우가 있다.

I_CostCenterCostItem은 이 문제를 해결하기 위해 SAP가 릴리스한 Basic Interface View다. ACDOCA를 코스트센터 라인아이템 관점으로 노출하되, 필드명은 CO 도메인 관습(RKOSTL, KSTAR, WRTTP 등)을 유지한다. 즉 “COEP를 읽던 습관 그대로, 소스는 ACDOCA로 갈아탄 것”이라 보면 된다.

핵심: COEP SELECT는 컴파일은 되지만 컴패터빌리티 레이어를 거치므로 예측하기 힘든 성능/정합성 이슈를 만든다. 새 코드는 반드시 릴리스된 CDS를 경유해야 한다.

주요 필드 지도 — 무엇을 읽고 무엇을 버릴 것인가

I_CostCenterCostItem은 100개가 넘는 필드를 노출한다. 실무에서 자주 쓰는 필드만 정리하면 다음과 같다.

CDS 필드ACDOCA 원본의미
CompanyCodeRBUKRS회사코드
FiscalYearGJAHR회계연도
FiscalPeriodPOPER회계기간
CostCenterRCNTR수신 코스트센터
CostElementRACCT비용요소(=원가요소, 계정)
ControllingAreaRKALSMNR/RRCTY 관련관리회계영역
AmountInCompanyCodeCurrencyHSL회사코드통화 금액
AmountInControllingAreaCurrencyKSL관리회계통화 금액
QuantityMSL수량
DebitCreditCodeDRCRK차/대변 구분
ValueTypeWRTTP가치유형(04=실적)

실무에서 가장 자주 실수하는 곳은 ValueType 필터다. WRTTP=04(실적)만 뽑아야 계획·약정·재분배가 섞이지 않는다. 또한 DebitCreditCode를 무시하고 단순 SUM(HSL)을 하면 부호가 어긋난다. ACDOCA는 원장 성격상 차변은 +, 대변은 −로 저장되지 않고 별도 컬럼으로 부호를 표현하는 라인도 있으므로 반드시 확인이 필요하다.

1단계 — 기본 CDS 뷰로 코스트센터 실비 조회

첫 예제는 특정 회사코드·회계연도의 코스트센터 실비를 단순히 나열하는 소비용 뷰다. Basic 뷰 위에 얇은 Consumption 레이어를 올려 필요한 필드만 노출한다.

@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Cost Center Actuals - Simple List'
@Metadata.allowExtensions: true
define view entity ZC_CCTR_ACTUAL_LIST
  as select from I_CostCenterCostItem
{
  key CompanyCode                        as CoCode,
  key FiscalYear                         as FiscalYear,
  key FiscalPeriod                       as Period,
  key CostCenter                         as CostCenter,
  key CostElement                        as CostElement,
      ControllingArea                    as CoArea,
      AccountingDocument                 as JournalEntryId,
      AccountingDocumentItem             as JournalEntryItem,
      DebitCreditCode                    as DrCrInd,
      case DebitCreditCode
        when 'S' then AmountInCompanyCodeCurrency
        else       AmountInCompanyCodeCurrency * -1
      end                                as SignedAmount,
      CompanyCodeCurrency                as Currency,
      ValueType                          as ValueType
}
where
      ValueType   = '04'   // 실적만
  and LedgerFiscalYear is not initial;

여기서 DebitCreditCode에 따라 부호를 뒤집는 표현식이 핵심이다. 회계연도·기간·코스트센터를 키로 두어 이후 집계 뷰에서 GROUP BY 대상으로 쓰기 좋게 만들었다.

2단계 — 회계연도·기간별 비용요소 집계 리포트

이제 실무에서 필요한 “코스트센터별×비용요소별×기간별 실적 합계”를 만들어보자. Composite 뷰로 집계 로직을 분리하고, 예외 상황을 로깅 가능한 ABAP 서비스에서 감싸는 구조가 일반적으로 안정적이다.

@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Cost Center Actuals - Aggregated by Period'
define view entity ZC_CCTR_ACTUAL_AGG
  as select from ZC_CCTR_ACTUAL_LIST
{
  key CoCode,
  key FiscalYear,
  key Period,
  key CostCenter,
  key CostElement,
      Currency,
      sum(SignedAmount) as ActualAmount,
      count(*)          as LineItemCount
}
group by
  CoCode, FiscalYear, Period, CostCenter, CostElement, Currency;

이 뷰를 호출하는 ABAP 클래스 예시. 파라미터 검증, 권한 체크, 예외 로깅을 최소한으로 갖춘 형태다.

CLASS zcl_ccenter_actual_reader DEFINITION PUBLIC FINAL CREATE PUBLIC.
  PUBLIC SECTION.
    TYPES: BEGIN OF ty_result,
             co_code       TYPE bukrs,
             fiscal_year   TYPE gjahr,
             period        TYPE poper,
             cost_center   TYPE kostl,
             cost_element  TYPE racct,
             currency      TYPE waers,
             actual_amount TYPE hsl12,
           END OF ty_result,
           tt_result TYPE STANDARD TABLE OF ty_result WITH EMPTY KEY.

    METHODS read_actuals
      IMPORTING iv_co_code     TYPE bukrs
                iv_fiscal_year TYPE gjahr
                iv_period_from TYPE poper
                iv_period_to   TYPE poper
      RETURNING VALUE(rt_data) TYPE tt_result
      RAISING   cx_sy_open_sql_db.
ENDCLASS.

CLASS zcl_ccenter_actual_reader IMPLEMENTATION.
  METHOD read_actuals.
    IF iv_co_code IS INITIAL OR iv_fiscal_year IS INITIAL.
      RAISE EXCEPTION TYPE cx_sy_open_sql_db
        EXPORTING textid = cx_sy_open_sql_db=>cx_sy_open_sql_db.
    ENDIF.

    SELECT co_code, fiscal_year, period,
           cost_center, cost_element, currency,
           actual_amount
      FROM zc_cctr_actual_agg
      WHERE co_code     = @iv_co_code
        AND fiscal_year = @iv_fiscal_year
        AND period      BETWEEN @iv_period_from AND @iv_period_to
      INTO TABLE @rt_data.
  ENDMETHOD.
ENDCLASS.

3단계 — 프로덕션 관점: 성능·권한·테스트

실서비스에 태우려면 다음 세 가지를 반드시 챙긴다.

첫째, 필드 프루닝이다. SELECT *는 절대 금지. ACDOCA는 300개 이상의 컬럼을 가지므로 컬럼 스토어의 이점을 살리려면 필요한 필드만 선택해야 한다. 둘째, WHERE 절 순서가 아니라 선택도가 중요하다. 회사코드·회계연도·원장(RLDNR='0L')을 반드시 조건에 포함시켜야 파티션 프루닝이 동작한다. 셋째, DCL(Data Control Language)로 권한을 얹는다.

@EndUserText.label: 'DCL for Cost Center Actuals'
@MappingRole: true
define role ZR_CCTR_ACTUAL_AGG {
  grant select on ZC_CCTR_ACTUAL_AGG
    where CoCode      = aspect pfcg_auth( F_BKPF_BUK, BUKRS, ACTVT = '03' )
      and CostCenter  = aspect pfcg_auth( K_CSKS_SET, KOSTL, ACTVT = '03' );
}

단위 테스트는 ABAP Unit + CDS Test Double Framework를 활용한다. 실제 ACDOCA에 의존하지 않고 cl_cds_test_environmentI_CostCenterCostItem을 모킹하면 CI 파이프라인에서도 안정적으로 돈다.

CLASS ltc_reader DEFINITION FINAL FOR TESTING
  DURATION SHORT RISK LEVEL HARMLESS.
  PRIVATE SECTION.
    CLASS-DATA environment TYPE REF TO if_cds_test_environment.
    CLASS-METHODS class_setup.
    METHODS aggregation_works FOR TESTING.
ENDCLASS.

CLASS ltc_reader IMPLEMENTATION.
  METHOD class_setup.
    environment = cl_cds_test_environment=>create( i_for_entity = 'ZC_CCTR_ACTUAL_AGG' ).
  ENDMETHOD.
  METHOD aggregation_works.
    " insert test doubles into I_CostCenterCostItem here...
  ENDMETHOD.
ENDCLASS.

ACDOCA 직접 접근 vs I_CostCenterCostItem — 트레이드오프

“그냥 ACDOCA를 직접 SELECT하면 안 되나?” 자주 나오는 질문이다. 결론부터 말하면 가능하지만 권장되지 않는다.

  • ACDOCA 직접 접근의 장점: 최고 성능(뷰 오버헤드 없음), 모든 컬럼 접근 가능, FI·CO·PA 관점을 한 번의 조인 없이 다룰 수 있다.
  • 단점: 릴리스 안정성 없음(Cloud에서는 접근 불가), 부호/값유형/원장 필터를 개발자가 매번 챙겨야 함, 향후 데이터 모델 변경 시 대응 필요.
  • I_CostCenterCostItem 장점: 릴리스 계약(C1) 준수, 필드명 표준화, Cloud/OnPrem 공통 대응, 상위 소비 뷰(C_CostCenterCostLnItm)와 자연스러운 연결.
  • 단점: Basic 뷰라 어노테이션 최소, 특정 파생 컬럼(예: 세그먼트 파트너)이 제한적일 수 있음.

실무 기준선은 “새 개발은 CDS, 초대량 배치·데이터 마이그레이션 등 예외 상황만 ACDOCA 직접 접근” 정도가 일반적으로 합리적이다.

흔한 실수와 트러블슈팅

Q1. COEP에서 뽑은 합계와 I_CostCenterCostItem 합계가 다릅니다.
십중팔구 값유형(WRTTP) 필터가 누락되어 있다. COEP 호환뷰는 실적/계획/약정을 섞어 보여줄 수 있다. ValueType = '04'를 걸었는지 먼저 확인하자. 또한 원장 필드(Ledger = '0L')를 빠뜨리면 확장 원장이 있는 시스템에서 이중 집계된다.

Q2. 금액 부호가 반대로 나옵니다.
AmountInCompanyCodeCurrency는 절대값처럼 보이지만 실제로는 라인 성격에 따라 다르게 저장된다. DebitCreditCode('S'=차변, 'H'=대변)를 곱해 부호화하거나, 이미 부호화된 필드(AmountInCompanyCodeCurrencySigned 계열이 있는 릴리스라면 그쪽)를 쓰자.

Q3. 성능이 왜 이렇게 느립니까?
가장 흔한 원인은 (1) WHERE에 회사코드/회계연도가 빠져 파티션 프루닝 실패, (2) SELECT *로 컬럼 스토어 이점 상실, (3) Basic 뷰 위에 사용자 정의 조인을 과도하게 쌓아 옵티마이저가 밀어내리기 실패. ST05 SQL Trace와 HANA PlanViz로 실행 계획을 확인하는 습관이 필요하다.

Q4. 통계적 CO 전기가 안 잡힙니다.
S/4HANA에서는 CO 전기가 FI와 동시에 ACDOCA에 기록되므로 “통계 전기만 따로” 라는 개념이 흐려졌다. I_CostCenterCostItem은 실제 코스트센터가 수신자로 잡힌 라인만 반환하므로, 통계 코스트센터 로직은 별도 필드(PartnerCostCenter)를 함께 조회해야 한다.

이 다음에 파볼 만한 주제

여기까지 왔다면 다음 갈래로 확장할 수 있다. 하나는 소비 계층인 C_CostCenterCostLnItm과 Analytical Query C_CostCenterCostQry를 이용해 Fiori Analytical Report를 만드는 길. 또 하나는 RAP(RESTful ABAP Programming Model)로 Managed BO를 얹어 실적 조회 API를 노출하는 길. 셋째는 Group ReportingUniversal Allocation 관점에서 배부·정산 결과가 I_CostCenterCostItem에 어떻게 흘러들어오는지 추적하는 길이다.

더 읽어볼 자료

  • SAP Help Portal — SAP S/4HANA Cloud, Universal Journal 개요
  • SAP Help Portal — SAP S/4HANA, ACDOCA Field Description
  • SAP Help Portal — ABAP CDS Development in ABAP Platform
  • SAP Community Blog — Compatibility Views vs Released CDS Views (검색 키워드: “CO Compatibility Views S/4HANA”)
  • SAP Note 2185026 — S/4HANA Simplification List for FIN(회사 시스템 릴리스에 맞는 버전 확인)
  • SAP API Business Hub — CDS 뷰 I_CostCenterCostItemC_CostCenterCostLnItm 스펙
  • openSAP 코스는 “S/4HANA Financials” 시리즈에서 Universal Journal 챕터가 특히 참고할 만하다

댓글 0

아직 댓글이 없습니다.