ABAP

I_CostEstimate vs KEKO — 원가 CDS 뷰 #shorts #SAP #ABAP

▶ YouTube에서 보기

KEKO 테이블의 구조와 원가 견적 도메인 개요

SAP 제품 원가 계산(Product Cost Planning, CO-PC) 영역에서 KEKO는 수십 년간 원가 견적(Cost Estimate)의 헤더 정보를 담아온 핵심 테이블입니다. 자재별 표준 원가 견적을 생성(CK11N)하고 표시(CK13N)할 때마다 KEKO에 헤더 레코드가 쌓이고, 상세 항목은 CKIS, 원가 구성요소 분할은 KEPH에 저장되는 구조입니다.

KEKO의 키 구조는 다음과 같이 복합적입니다.

  • BZOBJ — 참조 오브젝트(0: 제품 원가 견적)
  • KALNR — 원가 견적 번호(내부 채번)
  • KALKA — 원가 산정 유형(01: 표준 원가 등)
  • KADKY — 원가 산정 일자(키의 일부)
  • TVERS — 원가 산정 버전

여기에 MATNR(자재), WERKS(플랜트), KLVAR(원가 산정 변형), LOSGR(로트 크기), FEH_STA(상태) 같은 속성 필드가 붙습니다. 문제는 이 5중 복합키와 내부 채번 구조 때문에, KEKO를 직접 SELECT하는 코드는 늘 길고 오류에 취약했다는 점입니다. S/4HANA(2022/2023 및 SAP BTP ABAP Environment 기준)에서는 이를 대체하는 릴리스된 CDS 인터페이스 뷰 I_CostEstimate가 제공되며, 이 글에서는 KEKO 직접 접근을 CDS 기반으로 전환하는 전 과정을 다룹니다.

KEKO vs I_CostEstimate: 물리 테이블과 CDS 인터페이스 뷰의 차이

KEKO를 직접 읽는 것과 I_CostEstimate를 읽는 것은 단순히 이름만 다른 게 아닙니다. 개념적으로 KEKO가 "창고의 원자재"라면, I_CostEstimate는 "라벨이 붙고 품질 검사를 마친 출고용 제품"에 비유할 수 있습니다.

구분KEKO (물리 테이블)I_CostEstimate (CDS 뷰)
필드명독일어 약어 (KALNR, KADKY)의미 기반 영문 (CostEstimate, CostingDate)
릴리스 계약없음 — 구조 변경 시 코드 파손 위험C1 릴리스 계약, 클라우드 개발에서 사용 가능
연관 데이터수동 JOIN 필요Association으로 선언적 탐색
권한/필터애플리케이션 코드에서 직접 처리뷰 레이어에서 일관 처리 가능
클라우드 호환ABAP Cloud에서 직접 접근 불가Released API로 사용 가능

특히 SAP BTP ABAP Environment나 S/4HANA Cloud Public Edition의 ABAP Cloud 개발 모델에서는 KEKO 같은 미릴리스 테이블에 직접 SELECT하면 구문 검사 단계에서 차단됩니다. 온프레미스라도 Clean Core 전략을 따른다면 I_CostEstimate로의 전환은 사실상 필수 과제로 보는 것이 일반적입니다.

I_CostEstimate 핵심 필드 분석 — 원가 산정에 필요한 데이터

I_CostEstimate는 KEKO의 기술적 필드를 의미 중심으로 재구성합니다. 실무에서 자주 쓰는 매핑은 다음과 같습니다.

  • CostEstimate ← KALNR: 원가 견적 번호
  • CostEstimateReferenceObject ← BZOBJ: 참조 오브젝트
  • CostingType ← KALKA: 원가 산정 유형
  • CostingVariant ← KLVAR: 원가 산정 변형(예: PPC1)
  • CostingDate ← KADKY: 산정 기준일
  • CostingVersion ← TVERS: 버전
  • Material / Plant ← MATNR / WERKS
  • CostingLotSize ← LOSGR: 산정 로트 크기
  • CostEstimateValidityStartDate / ...EndDate: 유효 기간

이름만 보고도 데이터 의미를 파악할 수 있어, KALNR·KADKY 약어를 모르는 주니어 개발자도 코드 리뷰가 가능해집니다. 필드 구성은 S/4HANA 릴리스에 따라 다를 수 있으므로, 실제 프로젝트에서는 ADT의 Data Definition 소스나 시스템의 뷰 정의를 직접 확인하는 것이 권장됩니다.

ABAP 코드: KEKO SELECT → I_CostEstimate 전환 실전 예제

1단계로 가장 단순한 조회부터 비교합니다. 아래는 특정 플랜트 자재의 표준 원가 견적을 읽는 레거시 코드입니다.

" [Before] KEKO 직접 접근 — 레거시 스타일
SELECT kalnr, kadky, klvar, losgr
  FROM keko
  INTO TABLE @DATA(lt_keko_hdr)
  WHERE bzobj = '0'
    AND matnr = @lv_matnr
    AND werks = @lv_plant
    AND kalka = '01'
    AND tvers = '01'.
" [After] I_CostEstimate 기반 — Clean Core 스타일
SELECT CostEstimate,
       CostingDate,
       CostingVariant,
       CostingLotSize,
       CostEstimateValidityStartDate
  FROM I_CostEstimate
  INTO TABLE @DATA(lt_estimates)
  WHERE CostEstimateReferenceObject = '0'
    AND Material    = @lv_material
    AND Plant       = @lv_plant
    AND CostingType = '01'
    AND CostingVersion = '01'.

2단계로 실무에서는 조회 실패에 대한 방어 코드와 로깅이 필요합니다. 최신 유효 견적 한 건만 안전하게 가져오는 패턴입니다.

TRY.
    SELECT SINGLE CostEstimate, CostingDate, CostingLotSize
      FROM I_CostEstimate
      WHERE Material      = @iv_material
        AND Plant         = @iv_plant
        AND CostingType   = '01'
        AND CostEstimateValidityStartDate <= @sy-datum
        AND CostEstimateValidityEndDate   >= @sy-datum
      INTO @DATA(ls_current_estimate).

    IF sy-subrc <> 0.
      RAISE EXCEPTION NEW zcx_costing_error(
        textid = zcx_costing_error=>no_valid_estimate ).
    ENDIF.
  CATCH cx_sy_open_sql_db INTO DATA(lx_db).
    " Application Log(BAL 또는 XCO Log)로 기록 후 재전파
    zcl_cost_log=>get( )->add_exception( lx_db ).
    RAISE EXCEPTION NEW zcx_costing_error( previous = lx_db ).
ENDTRY.

연관 CDS 뷰 활용: I_CostEstimateItem / I_CostEstimateVersion

헤더만으로는 원가 분석이 끝나지 않습니다. 항목 수준(CKIS 대응)의 데이터는 항목 뷰를 통해 접근하며, 헤더 뷰의 Association 경로를 타면 JOIN 문 없이 한 번에 읽을 수 있습니다.

" 헤더 + 항목을 Path Expression으로 조회
SELECT hdr~CostEstimate,
       hdr~Material,
       itm~CostEstimateItem,
       itm~CostElement,
       itm~TotalCostAmount
  FROM I_CostEstimate AS hdr
    INNER JOIN I_CostEstimateItem AS itm
      ON itm~CostEstimate = hdr~CostEstimate
  WHERE hdr~Plant       = @lv_plant
    AND hdr~CostingType = '01'
  INTO TABLE @DATA(lt_cost_detail).

버전 관리가 활성화된 환경이라면 버전 차원의 뷰(예: I_CostEstimateVersion 계열)로 시뮬레이션 버전과 릴리스 버전을 구분해 비교 리포트를 만들 수 있습니다. 이때 KEKO 시절처럼 TVERS를 하드코딩하지 않고, 버전 뷰의 상태 필드를 기준으로 필터링하는 방식이 일반적으로 권장됩니다. 사용 가능한 뷰 목록과 릴리스 상태는 SAP Business Accelerator Hub 또는 ADT의 Released Objects 트리에서 확인할 수 있습니다.

원가 계층 탐색: Association 경로로 Material·Plant 연결

인터페이스 뷰의 진짜 힘은 Association 네트워크입니다. I_CostEstimate에서 _Material, _Plant 같은 연관을 따라가면 자재 마스터·플랜트 속성을 별도 JOIN 선언 없이 얻습니다.

SELECT ce~CostEstimate,
       ce~CostingDate,
       ce~\_Material-MaterialType     AS MaterialType,
       ce~\_Material-MaterialBaseUnit AS BaseUnit,
       ce~\_Plant-PlantName           AS PlantName
  FROM I_CostEstimate AS ce
  WHERE ce~Plant = @lv_plant
  INTO TABLE @DATA(lt_enriched).

Path Expression은 실행 시점에 LEFT OUTER JOIN으로 변환되므로, 연관 대상이 없어도 헤더 행이 유실되지 않습니다. KEKO + MARA + T001W를 수동으로 엮던 코드에서 흔했던 "JOIN 조건 누락으로 행이 증식하는" 사고를 구조적으로 줄여 줍니다.

실무 시나리오: 제품 원가 견적 리포트 프로그램

3단계 프로덕션 수준 예제로, 플랜트별 유효 표준 원가 리스트를 제공하는 조회 클래스를 구성합니다. 테스트 용이성을 위해 CDS 접근을 인터페이스 뒤로 숨기고, ABAP Unit에서 CL_CDS_TEST_ENVIRONMENT로 뷰를 목킹합니다.

CLASS zcl_std_cost_reader DEFINITION PUBLIC FINAL CREATE PUBLIC.
  PUBLIC SECTION.
    TYPES tt_result TYPE STANDARD TABLE OF zif_std_cost=>ty_result
                    WITH EMPTY KEY.
    METHODS get_valid_estimates
      IMPORTING iv_plant         TYPE werks_d
                iv_max_rows      TYPE i DEFAULT 500
      RETURNING VALUE(rt_result) TYPE tt_result.
ENDCLASS.

CLASS zcl_std_cost_reader IMPLEMENTATION.
  METHOD get_valid_estimates.
    " 성능: 필요한 컬럼만, UP TO 절로 결과 상한 제한
    SELECT CostEstimate, Material, CostingDate,
           CostingLotSize, CostingVariant
      FROM I_CostEstimate
      WHERE Plant       = @iv_plant
        AND CostingType = '01'
        AND CostEstimateValidityEndDate >= @sy-datum
      ORDER BY Material, CostingDate DESCENDING
      INTO CORRESPONDING FIELDS OF TABLE @rt_result
      UP TO @iv_max_rows ROWS.
  ENDMETHOD.
ENDCLASS.
" ABAP Unit: CDS 목킹으로 DB 의존성 제거
CLASS ltc_reader DEFINITION FOR TESTING RISK LEVEL HARMLESS
  DURATION SHORT.
  PRIVATE SECTION.
    CLASS-DATA go_cds_env TYPE REF TO if_cds_test_environment.
    METHODS returns_only_valid FOR TESTING.
ENDCLASS.

보안 관점에서는 조회 클래스 진입부에 AUTHORITY-CHECK(예: K_KEKO 계열 권한 오브젝트)를 두거나, 접근 제어(DCL)가 걸린 상위 뷰를 소비하는 방식으로 플랜트 권한을 통제합니다. RAP 기반 Fiori 앱으로 확장한다면 이 클래스를 그대로 Unmanaged Query 구현에 재사용할 수 있습니다.

마이그레이션 주의사항 — 흔한 실수와 해결책

FAQ 1. I_CostEstimate로 바꿨더니 결과 건수가 KEKO보다 많거나 적습니다. KEKO 직접 조회 시 걸었던 BZOBJ·TVERS 필터를 CDS 전환 시 누락하는 경우가 가장 흔합니다. 뷰 자체에 기본 필터가 내장되어 있는지 뷰 정의(WHERE 절)를 먼저 확인하고, 부족한 조건은 소비 측에서 명시하세요.

FAQ 2. KADKY가 역순 저장(9999... 방식)이던 로직은 어떻게 되나요? 일부 원가 테이블은 날짜를 역변환해 저장했지만, 인터페이스 뷰는 일반 날짜 의미로 노출하는 것이 보통입니다. 레거시의 날짜 역변환 유틸을 그대로 옮기면 비교 조건이 뒤집히므로, 전환 시 해당 헬퍼 호출을 반드시 제거하고 검증 데이터를 대조하세요.

FAQ 3. 항목 뷰 조인 후 성능이 나빠졌습니다. 헤더 필터(플랜트·유형·유효일)를 항목 조인 이전에 적용하고, 필요한 컬럼만 선택하며, 집계는 SELECT 내 SUM( ... )으로 DB에 내려보내는 code-pushdown이 핵심입니다. 루프 내 SELECT SINGLE 패턴이 남아 있다면 FOR ALL ENTRIES가 아닌 조인·CTE로 재작성하는 편이 일반적으로 유리합니다.

추가로, 시스템 릴리스마다 뷰의 릴리스 상태와 필드 구성이 다를 수 있으니 전환 전 ADT에서 API State를 확인하고, 금액 필드 사용 시 통화 참조 필드를 함께 조회하는 습관을 들이세요.

더 나아가기 좋은 주제로는 RAP 기반 원가 조회 앱 개발, I_CostEstimateItem을 활용한 원가 구성요소 분석, CDS 접근 제어(DCL) 설계, Embedded Analytics(Analytical Query)로의 확장이 있습니다. 참고할 만한 자료는 다음과 같습니다.

댓글 0

아직 댓글이 없습니다.