ABAP

아직도 T007S로 세금 코드 조회? — I_TaxCode 3단계 #shorts #SAP #ABAP

▶ YouTube에서 보기

개요 및 학습 도달점

SAP S/4HANA로 전환한 개발 조직이 가장 먼저 마주하는 질문 중 하나는 "T007S를 계속 직접 조회해도 되는가?"입니다. 이 글에서는 세금 코드 마스터를 조회하는 새로운 표준 접근인 I_TaxCode CDS View의 구조, 동작 원리, 그리고 실무에서의 적용 방법을 초급자 관점에서 단계적으로 정리합니다. Virtual Data Model(VDM)의 개념부터 실제 벤더 인보이스 검증 로직까지, 실전에서 바로 사용할 수 있는 코드를 함께 다룹니다.

  • I_TaxCode CDS View의 위치와 역할 파악
  • T007S 직접 조회 대비 장점 이해
  • ABAP SELECT 문에서 CDS View 사용 방법 습득
  • 다국어 텍스트 조인 및 유효성 검증 패턴 구현
  • 프로덕션 환경에서의 성능/보안 고려 사항 점검

알고 있어야 할 배경

이 글은 ABAP 기본 문법(SELECT, WHERE, INTO), 내부 테이블 처리, 그리고 세금 코드가 재무 회계(FI) 프로세스에서 어떤 역할을 하는지에 대한 최소한의 감각을 전제로 합니다. CDS View를 처음 접하는 독자도 따라올 수 있도록 개념 요약을 포함했지만, ADT(ABAP Development Tools) 사용 경험이 있으면 Data Preview 기능으로 결과를 즉시 확인할 수 있어 학습 효율이 높아집니다.

실행 환경과 준비물

이 글의 예제는 다음 환경을 기준으로 작성되었습니다.

  • SAP S/4HANA 2022 이상 (On-Premise) 또는 SAP S/4HANA Cloud, private edition
  • ABAP Platform 7.57 이상 (ABAP CDS 완전 지원)
  • Eclipse + ABAP Development Tools (ADT) 3.30 이상
  • Financial Accounting(FI) 모듈이 활성화된 클라이언트
  • 테스트 회사 코드(BUKRS)와 최소 1개의 세금 국가(LAND1)가 커스터마이징되어 있어야 함

권한 측면에서는 S_DEVELOP(개발), S_RS_COMP(리포트), 그리고 CDS View 조회에 필요한 S_RFC 권한이 있어야 데이터 미리 보기와 실행이 원활합니다. Cloud 환경에서는 Released API 여부를 반드시 확인하고 사용하는 것이 일반적입니다.

핵심 개념 정리

SAP는 S/4HANA에서 데이터베이스 테이블을 직접 사용하는 대신 Virtual Data Model(VDM)이라는 계층을 도입했습니다. VDM은 세 종류의 CDS View로 구성됩니다.

  • Basic View (I_*): 원천 테이블을 재구성한 기본 뷰. I_TaxCode가 여기에 속합니다.
  • Composite View (C_*): 여러 Basic View를 결합해 비즈니스 로직을 담은 뷰.
  • Consumption View: OData/Fiori에서 소비되는 최종 뷰.

비유하자면 T007S는 원자재 창고에 있는 부품이고, I_TaxCode는 그 부품을 조립해 라벨을 붙이고 다국어 매뉴얼까지 첨부한 완제품 상자와 같습니다. 개발자는 창고에 직접 들어가는 대신 완제품 상자를 받아 사용하면 됩니다.

T007S를 직접 조회할 때 발생하는 대표적인 문제는 다음과 같습니다.

  • 하드 의존성: 테이블 구조가 릴리스마다 변경될 수 있으며, 필드 추가·삭제 시 코드 수정 부담이 큽니다.
  • 텍스트 조인 번거로움: 세금 코드 설명은 T007S가 아닌 별도 텍스트 테이블에 있어, 다국어 처리를 위해 SY-LANGU 조건을 매번 명시해야 합니다.
  • 유효성 검증 로직 중복: 삭제 플래그(XSKIP) 같은 필드를 매번 필터링해야 합니다.
  • Cloud 호환성: Steampunk나 S/4HANA Cloud, public edition에서는 T007S 직접 접근이 제한됩니다.

I_TaxCode는 이 모든 문제를 뷰 계층에서 해결합니다. 세금 국가, 세금 코드, 그리고 관련 텍스트가 이미 조인된 형태로 노출되며, Association을 통해 계정 결정, 세율 상세 정보 등으로 자연스럽게 확장할 수 있습니다.

실전 코드: 3단계 접근

1단계 — 가장 단순한 조회

먼저 I_TaxCode가 어떤 데이터를 반환하는지 확인하는 최소 예제입니다. 벤더 인보이스 처리 화면에서 특정 국가의 세금 코드 목록을 드롭다운으로 보여준다고 가정합니다.

REPORT z_demo_taxcode_lookup.

DATA: lt_tax_codes TYPE TABLE OF i_taxcode,
      lv_country   TYPE land1 VALUE 'DE'.

SELECT country,
       taxcode,
       taxcodetype,
       taxpercentagerate
  FROM i_taxcode
  WHERE country = @lv_country
  INTO TABLE @lt_tax_codes.

LOOP AT lt_tax_codes ASSIGNING FIELD-SYMBOL(<fs_tax>).
  WRITE: / <fs_tax>-country,
           <fs_tax>-taxcode,
           <fs_tax>-taxcodetype,
           <fs_tax>-taxpercentagerate.
ENDLOOP.

여기서 주목할 점은 T007S를 몰라도 된다는 것입니다. 세금 국가(MWSKZ가 아닌 Country)와 세금 코드(TaxCode)가 의미 있는 필드명으로 노출되어 있어 가독성이 좋습니다.

2단계 — 실무 시나리오: 벤더 인보이스 유효성 검증

이제 실제 프로세스에 가까운 예제로 넘어갑니다. 사용자가 벤더 인보이스를 등록할 때 입력한 세금 코드가 (1) 존재하는지, (2) 삭제되지 않았는지, (3) 사용자의 로그인 언어로 된 설명이 무엇인지 반환하는 검증 클래스입니다.

CLASS zcl_vendor_invoice_validator DEFINITION
  PUBLIC FINAL CREATE PUBLIC.

  PUBLIC SECTION.
    TYPES: BEGIN OF ty_validation_result,
             is_valid        TYPE abap_bool,
             tax_code        TYPE i_taxcode-taxcode,
             tax_description TYPE i_taxcodetext-taxcodename,
             message         TYPE string,
           END OF ty_validation_result.

    METHODS validate_tax_code
      IMPORTING iv_country  TYPE land1
                iv_tax_code TYPE mwskz
      RETURNING VALUE(rs_result) TYPE ty_validation_result.
ENDCLASS.

CLASS zcl_vendor_invoice_validator IMPLEMENTATION.
  METHOD validate_tax_code.
    DATA ls_tax TYPE i_taxcode.

    SELECT SINGLE tax~country,
                  tax~taxcode,
                  tax~taxcodetype,
                  text~taxcodename
      FROM i_taxcode AS tax
      LEFT OUTER JOIN i_taxcodetext AS text
        ON  text~country  = tax~country
        AND text~taxcode  = tax~taxcode
        AND text~language = @sy-langu
      WHERE tax~country  = @iv_country
        AND tax~taxcode  = @iv_tax_code
      INTO @DATA(ls_result).

    IF sy-subrc <> 0.
      rs_result-is_valid = abap_false.
      rs_result-message  = |세금 코드 { iv_tax_code }가 국가 { iv_country }에 존재하지 않습니다.|.
      MESSAGE i001(zfi_log) WITH iv_country iv_tax_code.
      RETURN.
    ENDIF.

    rs_result-is_valid        = abap_true.
    rs_result-tax_code        = ls_result-taxcode.
    rs_result-tax_description = ls_result-taxcodename.
    rs_result-message         = |유효한 세금 코드: { ls_result-taxcodename }|.
  ENDMETHOD.
ENDCLASS.

이 코드에서 I_TaxCodeTextLEFT OUTER JOIN으로 결합한 이유는 특정 언어에 번역이 없을 때도 마스터 데이터 검증 자체는 성공해야 하기 때문입니다. T007S로 직접 구현했다면 세금 코드 존재 여부 확인, 삭제 플래그 필터링, 텍스트 테이블 조인을 각각 세 번의 SELECT로 수행해야 했을 것입니다.

3단계 — 프로덕션 등급: 성능, 보안, 테스트

대량 처리와 유닛 테스트를 고려한 개선 버전입니다. 배치 잡에서 수천 건의 인보이스를 처리할 때는 개별 SELECT 대신 FOR ALL ENTRIES나 CDS View 파라미터를 활용하고, Test Double 프레임워크로 데이터베이스 접근을 격리합니다.

CLASS zcl_vendor_invoice_batch DEFINITION
  PUBLIC FINAL CREATE PUBLIC.

  PUBLIC SECTION.
    TYPES: BEGIN OF ty_input,
             invoice_id TYPE guid_32,
             country    TYPE land1,
             tax_code   TYPE mwskz,
           END OF ty_input,
           tt_input TYPE STANDARD TABLE OF ty_input WITH EMPTY KEY.

    METHODS validate_batch
      IMPORTING it_input TYPE tt_input
      RETURNING VALUE(rt_invalid) TYPE tt_input
      RAISING   cx_sy_open_sql_db.
ENDCLASS.

CLASS zcl_vendor_invoice_batch IMPLEMENTATION.
  METHOD validate_batch.
    IF it_input IS INITIAL.
      RETURN.
    ENDIF.

    SELECT country, taxcode
      FROM i_taxcode
      FOR ALL ENTRIES IN @it_input
      WHERE country = @it_input-country
        AND taxcode = @it_input-tax_code
      INTO TABLE @DATA(lt_valid).

    LOOP AT it_input INTO DATA(ls_input).
      READ TABLE lt_valid TRANSPORTING NO FIELDS
        WITH KEY country = ls_input-country
                 taxcode = ls_input-tax_code.
      IF sy-subrc <> 0.
        APPEND ls_input TO rt_invalid.
      ENDIF.
    ENDLOOP.

    IF rt_invalid IS NOT INITIAL.
      cl_ba_log=>get_instance( )->add_message(
        iv_type = 'W'
        iv_text = |무효 세금 코드 { lines( rt_invalid ) }건 감지| ).
    ENDIF.
  ENDMETHOD.
ENDCLASS.

성능 관점에서 이 구조는 N+1 쿼리 문제를 회피합니다. 1만 건의 인보이스가 있더라도 데이터베이스 호출은 단 한 번으로 끝납니다. 보안 관점에서는 CDS View가 DCL(Data Control Language)을 통해 권한을 자동 적용하므로, 특정 회사 코드에 대한 접근 권한이 없는 사용자에게는 해당 데이터가 아예 반환되지 않습니다. 이는 T007S 직접 조회에서는 별도 구현이 필요했던 부분입니다.

자주 겪는 실수와 해결법

Q1. I_TaxCode를 조회했더니 삭제 예정인 세금 코드가 나오지 않습니다. T007S에는 있는데요?

이는 버그가 아니라 의도된 동작입니다. I_TaxCode는 삭제 플래그(XSKIP)가 설정된 코드를 기본적으로 제외합니다. 감사 목적으로 모든 이력을 봐야 한다면 기술 뷰인 I_TaxCode_F 계열 또는 원천 테이블 접근을 위해 별도의 Custom CDS View를 생성하는 접근을 검토합니다.

Q2. Cloud 환경에서 I_TaxCode 사용 시 "Not Released for Cloud Development" 경고가 뜹니다.

SAP는 CDS View마다 Release Contract를 부여합니다. 사용하려는 뷰가 자신의 환경(Key User Extensibility, Cloud Development, On-Premise)에서 Released 상태인지 SAP API Business Hub 또는 ADT의 Release Info 탭에서 확인해야 합니다. Released가 아니라면 C_TaxCode 같은 대체 Consumption View가 있는지 찾아보는 것이 일반적인 대응입니다.

Q3. 세금 코드 설명(텍스트)이 영문으로만 나옵니다.

I_TaxCodeText를 조인할 때 language = @sy-langu 조건이 누락되었을 가능성이 높습니다. 텍스트 뷰는 여러 언어 행을 한꺼번에 반환하므로 반드시 로그인 언어 필터를 명시해야 합니다. 또한 특정 언어 번역이 등록되지 않았다면 LEFT OUTER JOINCOALESCE로 폴백(fallback) 언어를 지정하는 패턴을 권장합니다.

확장 학습 방향

이 글의 내용을 바탕으로 다음 주제로 확장해 볼 수 있습니다. 첫째, I_TaxCode와 Association을 이루는 I_TaxCodeText, I_CompanyCode, I_ChartOfAccounts를 연결해 세금 계정 결정 로직을 CDS View 하나로 구성하는 방법을 익히면 좋습니다. 둘째, CDS View Entity(RAP 스타일)로 마이그레이션하는 방법을 익히면 최신 ABAP RESTful Application Programming Model과 연동이 쉬워집니다. 셋째, ABAP Unit + CDS Test Double Framework로 세금 코드 검증 로직을 데이터베이스 없이 테스트하는 패턴을 학습하면 CI/CD 파이프라인에 자연스럽게 통합할 수 있습니다.

더 읽어볼 자료

  • SAP Help Portal — Virtual Data Model (VDM) 개요
  • SAP Help Portal — ABAP CDS View Entities 개발 가이드
  • SAP Help Portal — Released Objects for Cloud Development
  • SAP API Business Hub — CDS View 카탈로그 및 Release Info
  • SAP Community — ABAP CDS 태그 (실전 Q&A)
  • SAP Blogs — S/4HANA VDM 마이그레이션 사례 모음

댓글 0

아직 댓글이 없습니다.