ABAP

SKA1 vs I_GLAccount — GL 계정 조회 차이 #shorts #SAP #ABAP

▶ YouTube에서 보기

개요 및 이 글에서 다룰 내용

S/4HANA 재무 모듈에서 총계정원장(General Ledger) 계정 마스터를 다룰 때 가장 먼저 마주치는 CDS 뷰가 바로 I_GLAccount입니다. 전통 ABAP에서는 SKA1(Chart of Accounts 레벨 계정 마스터) 테이블을 직접 조회했지만, S/4HANA에서는 가상 데이터 모델(VDM) 계층의 I_GLAccount를 통해 표준화된 컬럼명과 어노테이션, 텍스트 연결 구조를 함께 활용하는 것이 권장됩니다. 이 글에서는 SKA1과 I_GLAccount의 관계, 텍스트 뷰 연결, 그리고 실전 ABAP/CDS 코드를 단계별로 다룹니다.

  • I_GLAccount의 정의와 SKA1·SKAT 매핑 구조 파악
  • Chart of Accounts(COA) 키 항목의 의미와 사용 방식 이해
  • OPEN SQL / OPEN CURSOR를 통한 GL 계정 조회 패턴 습득
  • I_GLAccountText 등 텍스트 뷰 조인 방식 익히기
  • S/4HANA에서 SKA1 직접 접근과 VDM 뷰 사용의 차이 분석

먼저 알고 있으면 좋은 배경

이 글은 ABAP Open SQL 기본 문법(SELECT, JOIN, INTO TABLE)과 CDS View의 기본 구조(define view, association)를 알고 있다는 전제로 작성되었습니다. 또한 SAP FI 모듈의 기본 용어인 Company Code, Chart of Accounts, GL Account 정도는 익숙해야 합니다. ADT(Eclipse-based ABAP Development Tools) 사용 경험이 있으면 CDS 뷰 정의를 직접 열어보면서 따라가기 좋습니다.

실습 환경 및 버전 정보

이 글의 코드는 다음 환경 기준으로 검증된 일반적인 패턴이며, 시스템 릴리즈에 따라 필드명이 약간 다를 수 있습니다.

  • SAP S/4HANA 2022 / 2023 (on-premise) 또는 S/4HANA Cloud Public Edition
  • ABAP Platform 2022 이상 (NetWeaver 7.57+)
  • ABAP Development Tools(ADT) for Eclipse 2023-06 이상
  • HANA DB 2.0 SPS06+
  • 권한: S_TABU_DIS(SKA1 조회), S_DEVELOP(CDS 뷰 활성화), F_SKA1_BUK(GL 마스터 권한 그룹)

예제에 등장하는 객체는 I_GLAccount(기본 뷰), I_GLAccountText(텍스트 뷰), I_GLAccountInChartOfAccounts(소비 뷰 변형) 등입니다. 시스템에 따라 일부 뷰는 별도 BC 세트 활성화가 필요할 수 있습니다.

핵심 개념 정리

전통적인 SAP ECC에서 GL 계정 마스터는 두 레벨로 관리됩니다. SKA1은 Chart of Accounts(차변원장계획표) 레벨의 마스터로 계정번호, 계정유형(P&L/Balance Sheet), Group Account 등을 보관합니다. SKB1은 Company Code 레벨로 통화, 세금 카테고리, 조정 계정 여부 등을 가집니다. 그리고 SKAT는 언어별 텍스트(짧은 설명, 긴 설명)를 분리해서 저장합니다.

비유하자면 SKA1은 "전국 표준 도서분류표"이고 SKB1은 "각 도서관(회사 코드)이 그 분류를 어떻게 운용하는지에 대한 규칙"이며, SKAT는 "각 언어로 번역된 도서명"에 해당합니다.

I_GLAccount는 SKA1을 기반으로 한 VDM(Virtual Data Model) Basic Interface View입니다. SAP 표준 어노테이션(@ObjectModel, @Semantics, @EndUserText.label)이 부여되어 있고, 필드명이 SAKNR 같은 약어 대신 GLAccount, ChartOfAccounts 등 의미가 분명한 명칭으로 노출됩니다. 또한 _Text association을 통해 SKAT를 손쉽게 연결할 수 있고, _GLAccountGroup, _AccountClassification 같은 관련 마스터로의 path expression도 제공합니다.

구조를 도식화하면 다음과 같습니다.

SKA1 (DB Table)
  └── I_GLAccount (Basic View, @VDM.viewType: #BASIC)
        ├── _Text → I_GLAccountText → SKAT
        ├── _GLAccountGroup → I_GLAccountGroup
        └── _ChartOfAccounts → I_ChartOfAccounts → T004
                                    
       소비 계층:
       C_GLAccountMasterData (Consumption View)
       I_GLAccountStdVH (Value Help)

이러한 계층 분리 덕분에 보고서나 Fiori 앱은 I_GLAccount만 참조해도 텍스트, 그룹, 분류 정보를 일관된 방식으로 가져올 수 있고, 필드명 표준화로 인해 다국적 시스템 간 인터페이스도 단순해집니다.

1단계 — 기본 조회 예제

먼저 특정 Chart of Accounts에 속한 모든 GL 계정의 번호와 짧은 텍스트를 가져오는 가장 단순한 패턴부터 살펴봅니다. 전통적인 SKA1 + SKAT 조인 방식과 I_GLAccount association 활용 방식을 비교해보겠습니다.

REPORT zr_ledger_account_list.

DATA: lt_account_list TYPE STANDARD TABLE OF i_glaccount,
      lv_coa          TYPE i_glaccount-chartofaccounts VALUE 'INT'.

" Path expression으로 텍스트 association 직접 호출
SELECT gl~chartofaccounts,
       gl~glaccount,
       gl~glaccounttype,
       gl~glaccountgroup,
       \_Text-glaccountname AS account_name_kr
  FROM i_glaccount AS gl
  WHERE gl~chartofaccounts = @lv_coa
    AND \_Text-language     = @sy-langu
  ORDER BY gl~glaccount
  INTO TABLE @DATA(lt_master).

LOOP AT lt_master ASSIGNING FIELD-SYMBOL(<ls_master>).
  WRITE: / <ls_master>-glaccount,
           <ls_master>-glaccounttype,
           <ls_master>-account_name_kr.
ENDLOOP.

위 코드에서 주목할 점은 \_Text-glaccountname 형태의 path expression입니다. 별도 JOIN을 작성하지 않아도 association 정의에 따라 자동으로 LEFT OUTER JOIN이 생성되며, language 키만 명시하면 됩니다. 만약 동일한 결과를 전통 방식으로 작성한다면 다음처럼 길어집니다.

SELECT a~ktopl, a~saknr, a~xbilk, a~ktoks, t~txt20
  FROM ska1 AS a
  LEFT OUTER JOIN skat AS t
    ON  t~ktopl = a~ktopl
    AND t~saknr = a~saknr
    AND t~spras = @sy-langu
  WHERE a~ktopl = @lv_coa
  INTO TABLE @DATA(lt_legacy).

두 코드 모두 동일한 결과를 반환하지만, I_GLAccount 버전이 필드명 가독성과 다국어 텍스트 처리 측면에서 훨씬 명확합니다.

2단계 — 실무 시나리오: 손익계정 추출과 예외 처리

실무에서는 단순 조회보다 "특정 계정 유형(예: P&L 계정)만 필터링하고, 누락되거나 차단(Blocked)된 계정을 식별해 로그를 남기는" 패턴이 흔합니다. 결산 시 손익 계정만 분석하거나 인터페이스 인입 데이터를 검증할 때 사용합니다.

CLASS zcl_pnl_account_loader DEFINITION PUBLIC FINAL CREATE PUBLIC.
  PUBLIC SECTION.
    TYPES: BEGIN OF ty_account_info,
             gl_account    TYPE i_glaccount-glaccount,
             account_type  TYPE i_glaccount-glaccounttype,
             account_group TYPE i_glaccount-glaccountgroup,
             account_name  TYPE i_glaccounttext-glaccountname,
             is_blocked    TYPE abap_bool,
           END OF ty_account_info,
           tt_account_info TYPE STANDARD TABLE OF ty_account_info
                           WITH NON-UNIQUE KEY gl_account.

    METHODS load_pnl_accounts
      IMPORTING iv_chart_of_accounts TYPE i_glaccount-chartofaccounts
      RETURNING VALUE(rt_accounts)   TYPE tt_account_info
      RAISING   cx_sy_open_sql_db.
ENDCLASS.

CLASS zcl_pnl_account_loader IMPLEMENTATION.
  METHOD load_pnl_accounts.

    DATA(lo_log) = cl_bali_log_db_writer=>create_instance( ).

    TRY.
        SELECT gl~glaccount,
               gl~glaccounttype,
               gl~glaccountgroup,
               \_Text-glaccountname AS account_name,
               CASE gl~corporategroupaccount
                 WHEN '' THEN @abap_false
                 ELSE @abap_true
               END AS is_blocked
          FROM i_glaccount AS gl
          WHERE gl~chartofaccounts = @iv_chart_of_accounts
            AND gl~glaccounttype    = 'N'
            AND \_Text-language      = @sy-langu
          INTO TABLE @rt_accounts.

        IF rt_accounts IS INITIAL.
          MESSAGE i001(zfi_msg) WITH iv_chart_of_accounts
                  INTO DATA(lv_dummy).
          lo_log->add_message( CONV #( sy-msgv1 ) ).
        ENDIF.

      CATCH cx_sy_open_sql_db INTO DATA(lx_db).
        lo_log->add_exception( lx_db ).
        RAISE EXCEPTION lx_db.
    ENDTRY.

  ENDMETHOD.
ENDCLASS.

여기서 GLAccountType 코드는 시스템마다 차이가 있지만 일반적으로 N(Non-Operating), X(P&L), S(Secondary Cost), A(Asset/Balance) 등으로 분류됩니다. 결과가 비었을 때 메시지를 BAL 로그로 남기는 부분은 야간 배치에서 운영 이슈를 추적할 때 매우 유용합니다.

3단계 — 프로덕션 패키지 로딩과 OPEN CURSOR 활용

전사 결산 보고서처럼 수십만 건의 계정 라인을 처리할 때는 한 번에 INTO TABLE로 받지 말고 패키지 단위로 처리하는 것이 메모리 안정성에 유리합니다. 또한 인증/마스킹이 필요한 환경에서는 권한 체크와 응답 시간 모니터링도 함께 구현합니다.

CLASS zcl_vendor_recon_processor DEFINITION PUBLIC.
  PUBLIC SECTION.
    METHODS run_batch
      IMPORTING iv_chart_of_accounts TYPE i_glaccount-chartofaccounts
                iv_package_size      TYPE i DEFAULT 5000.
ENDCLASS.

CLASS zcl_vendor_recon_processor IMPLEMENTATION.
  METHOD run_batch.

    DATA: lt_package      TYPE STANDARD TABLE OF i_glaccount,
          lv_cursor       TYPE cursor,
          lv_processed    TYPE i,
          lv_start_ts     TYPE timestampl,
          lv_end_ts       TYPE timestampl.

    GET TIME STAMP FIELD lv_start_ts.

    AUTHORITY-CHECK OBJECT 'F_SKA1_BUK'
      ID 'KTOPL' FIELD iv_chart_of_accounts
      ID 'ACTVT' FIELD '03'.
    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE cx_sy_authorization_error.
    ENDIF.

    OPEN CURSOR WITH HOLD @lv_cursor FOR
      SELECT gl~chartofaccounts,
             gl~glaccount,
             gl~glaccounttype,
             gl~balancesheetaccount,
             gl~placcount,
             \_Text-glaccountname AS account_name
        FROM i_glaccount AS gl
       WHERE gl~chartofaccounts = @iv_chart_of_accounts
         AND \_Text-language     = @sy-langu
       ORDER BY gl~glaccount.

    DO.
      FETCH NEXT CURSOR @lv_cursor
        INTO TABLE @lt_package PACKAGE SIZE @iv_package_size.

      IF sy-subrc <> 0.
        EXIT.
      ENDIF.

      LOOP AT lt_package ASSIGNING FIELD-SYMBOL(<ls_gl>).
        zcl_recon_calc=>accumulate( iv_account = <ls_gl>-glaccount ).
      ENDLOOP.

      lv_processed = lv_processed + lines( lt_package ).
    ENDDO.

    CLOSE CURSOR @lv_cursor.

    GET TIME STAMP FIELD lv_end_ts.
    cl_demo_output=>display( |Processed { lv_processed } accounts in { 
      cl_abap_tstmp=>subtract( tstmp1 = lv_end_ts tstmp2 = lv_start_ts ) } sec| ).

  ENDMETHOD.
ENDCLASS.

여기서 OPEN CURSOR WITH HOLD는 COMMIT 이후에도 커서를 유지하므로 다른 RFC 호출이 끼어들어도 안전합니다. PACKAGE SIZE는 일반적으로 1,000 ~ 10,000 사이가 무난하며, HANA에서는 너무 작게 잡으면 round-trip 비용이 커지므로 5,000 정도가 권장 시작점입니다.

자주 만나는 함정과 해결 방법

Q1. SKA1을 직접 SELECT해도 되지 않나요? 기술적으로는 가능하지만, S/4HANA Cloud에서는 SKA1 직접 접근이 제한되며 on-premise에서도 권장되지 않습니다. 필드명이 표준화되지 않아 인터페이스 변경에 취약하고, 향후 Release Upgrade 시 SAP가 SKA1 구조를 확장하면 영향을 받습니다. I_GLAccount는 SAP가 안정성을 유지하는 Released 객체이므로 우선 사용을 권장합니다.

Q2. \_Text-glaccountname이 빈 값으로 나옵니다. 대부분 language 조건이 누락된 경우입니다. SKAT에는 모든 언어 레코드가 들어 있으므로 association 조건에 반드시 \_Text-language = @sy-langu를 추가해야 합니다. 또한 한국어 텍스트가 등록되지 않은 계정도 있으니, 폴백으로 영어('E')를 한 번 더 조회하는 로직이 일반적입니다.

Q3. GLAccountType 값이 시스템마다 다른데 어떻게 처리하나요? 도메인 GLACCOUNT_TYPE의 고정값을 사용하되, 하드코딩 대신 상수 인터페이스(if_fi_gl_constants)나 커스텀 상수 클래스를 도입하세요. 또한 Secondary Cost Element(S) 같은 신규 타입은 S/4HANA에서 도입된 것이므로 ECC 호환 코드를 S/4HANA로 마이그레이션할 때 분기 처리가 필요합니다.

Q4. Company Code 단위 속성(통화, 조정 계정)도 같이 가져오려면? I_GLAccount는 COA 레벨 뷰이므로 Company Code 속성은 포함되지 않습니다. I_GLAccountInCompanyCode(SKB1 기반) 또는 I_GLAccountInChartOfAccounts와 조인하거나 association을 따라가야 합니다.

이어서 살펴보면 좋은 주제

I_GLAccount를 이해했다면 다음으로 I_GLAccountInCompanyCode(Company Code 레벨 마스터), I_JournalEntry·I_JournalEntryItem(전표 데이터), I_GLAccountLineItemRawData(라인 아이템 분석)로 영역을 넓혀가는 것이 자연스러운 흐름입니다. 또한 OData 노출을 원한다면 C_GLAccountMasterData 같은 Consumption 뷰를 RAP(ABAP RESTful Application Programming) 모델로 감싸 Fiori Elements 앱으로 발행할 수 있습니다. 마지막으로 SAP Analytics Cloud나 Datasphere로 데이터를 흘려보낼 때는 I_GLAccountStdVH(Value Help) 뷰의 활용도 함께 살펴보세요.

댓글 0

아직 댓글이 없습니다.