본문 바로가기
BAPI · BADI · RFC · Interface

[SAP ABAP] BAPI_INCOMINGINVOICE_CREATE — 송장 생성 BAPI 호출 방법 (MIRO 자동화 · INVOICE_IND · DE_CRE_IND)

by Song.sh 2026. 5. 21.

SAP MM 모듈의 송장 검증(MIRO) 화면을 자동화하거나 외부 시스템(그룹웨어·전자결재·거래처 EDI)에서 들어온 송장 데이터를 SAP 에 등록할 때는 BAPI_INCOMINGINVOICE_CREATE 를 호출합니다. 이 BAPI 하나로 일반 송장·대변메모(Credit Memo)·후속 차변(Subsequent Debit)·후속 대변(Subsequent Credit) 네 가지 문서 유형을 모두 처리할 수 있습니다.

 

송장 취소 BAPI(BAPI_INCOMINGINVOICE_CANCEL) 가 단순한 시그니처를 갖는 것과 달리, 생성 BAPI 는 헤더·아이템·세금·계정분개·자재·자료배분까지 10개가 넘는 테이블 파라미터 를 다룹니다. 그래서 핵심 키 필드(INVOICE_IND·DE_CRE_IND) 의 의미를 이해하지 못하면 의도와 다른 문서 유형이 생성됩니다.

 

이 글에서는 BAPI 시그니처 정리·문서 유형 분기 키·헤더·아이템·세금 파라미터 채우기·시뮬레이션 모드 활용·COMMIT 처리·자주 발생하는 오류 패턴까지 단계별로 정리합니다.

핵심 — 문서 유형은 INVOICE_IND × DE_CRE_IND 조합으로 결정

BAPI 가 생성할 문서 유형은 헤더의 INVOICE_IND + 아이템의 DE_CRE_IND 두 플래그 조합으로 결정됩니다. 이 조합을 잘못 채우면 송장으로 등록해야 할 건이 대변메모로 들어가는 사고가 발생합니다.

INVOICE_IND DE_CRE_IND 문서 유형 의미
X (공백) 송장(Invoice) 표준 매입 송장. 가장 일반적
(공백) (공백) 대변메모(Credit Memo) 송장 금액 환수 — 부호 반대
X 1 후속 차변(Subsequent Debit) 기존 송장 추가 청구 — 차차
(공백) 2 후속 대변(Subsequent Credit) 기존 송장 일부 환수 — 차대

실무에서 가장 헷갈리는 케이스가 "송장 일부 환수" 입니다. 송장 전체를 취소하지 않고 일부 금액만 돌려받을 때는 대변메모가 아니라 후속 대변(차대) 으로 처리해야 합니다. 대변메모는 새로운 독립 전표지만, 후속 대변은 원본 송장을 참조해서 일부 환수만 기록하는 구조이기 때문입니다.


시그니처 — IMPORTING / EXPORTING / TABLES

📋 구분 파라미터 타입 설명
IMPORTING HEADERDATA BAPI_INCINV_CREATE_HEADER 송장 헤더 (필수)
IMPORTING ADDRESSDATA (Opt) BAPI_INCINV_CREATE_ADDRESSDATA 일회성 거래처 주소
EXPORTING INVOICEDOCNUMBER BAPI_INCINV_FLD-INV_DOC_NO 생성된 송장 전표번호
EXPORTING FISCALYEAR BAPI_INCINV_FLD-FISC_YEAR 생성된 송장 회계연도
TABLES ITEMDATA BAPI_INCINV_CREATE_ITEM PO 참조 아이템 (필수)
TABLES ACCOUNTINGDATA (Opt) BAPI_INCINV_CREATE_ACCOUNT 계정분개 (CO 분개 필요 시)
TABLES GLACCOUNTDATA (Opt) BAPI_INCINV_CREATE_GL_ACCOUNT G/L 계정 직접 분개
TABLES MATERIALDATA (Opt) BAPI_INCINV_CREATE_MATERIAL 자재 직접 분개
TABLES TAXDATA (Opt) BAPI_INCINV_CREATE_TAX 세금 (수동 입력 시)
TABLES WITHTAXDATA (Opt) BAPI_INCINV_CREATE_WITHTAX 원천세
TABLES RETURN BAPIRET2 메시지 (Type E 검증)
TABLES EXTENSIONIN (Opt) BAPIPAREX CI Include 확장 필드

호출 시 반드시 채워야 하는 것은 HEADERDATA + ITEMDATA 두 개. 나머지는 시나리오에 따라 선택. PO 참조 표준 송장이라면 PO 헤더·아이템에서 정보 끌어와 BAPI 가 자동 분개해주므로 ACCOUNTING/GL 은 비워둬도 됩니다.


1단계 — HEADERDATA 채우기

헤더는 송장 1건당 하나의 행. 회사 코드·송장일자·금액·통화·거래처 등 청구서 1장의 상단 정보가 들어갑니다.

DATA ls_header TYPE bapi_incinv_create_header.

ls_header-invoice_ind   = 'X'.           " 송장(X) / 대변메모(공백)
ls_header-doc_date      = '20260520'.    " 송장일자
ls_header-pstng_date    = sy-datum.      " 전기일자
ls_header-comp_code     = '1000'.        " 회사코드
ls_header-diff_inv      = '0000100001'.  " 거래처 (LIFNR)
ls_header-currency      = 'KRW'.         " 통화
ls_header-gross_amount  = '1100000'.     " 총금액 (세금 포함)
ls_header-calc_tax_ind  = 'X'.           " 세금 자동 계산
ls_header-pmnttrms      = '0001'.        " 지급 조건
ls_header-ref_doc_no    = 'INV-2026-001'." 거래처 송장번호

핵심 포인트 — GROSS_AMOUNT 는 세금 포함 총금액. 화면 MIRO 에서 사용자가 입력하는 "총금액" 필드와 같은 값입니다. 세금을 자동 계산하게 하려면 CALC_TAX_IND = 'X' 를 설정하고, 직접 계산해서 채울 거면 TAXDATA 테이블을 별도로 넘깁니다.


2단계 — ITEMDATA 채우기 (PO 참조)

아이템은 PO 라인별로 한 줄씩 추가합니다. 가장 흔한 패턴이 PO 1개의 여러 아이템을 한 송장에 묶어 청구하는 경우입니다.

DATA: lt_item TYPE TABLE OF bapi_incinv_create_item,
      ls_item TYPE bapi_incinv_create_item.

" 첫 번째 아이템 (PO 4500000001 - 라인 10)
ls_item-invoice_doc_item = '000001'.
ls_item-po_number        = '4500000001'.
ls_item-po_item          = '00010'.
ls_item-tax_code         = 'V0'.            " 면세
ls_item-item_amount      = '500000'.        " 세전 금액
ls_item-quantity         = '10'.
ls_item-po_unit          = 'EA'.
ls_item-de_cre_ind       = space.           " 표준 송장
APPEND ls_item TO lt_item.

" 두 번째 아이템 (PO 4500000001 - 라인 20)
ls_item-invoice_doc_item = '000002'.
ls_item-po_number        = '4500000001'.
ls_item-po_item          = '00020'.
ls_item-tax_code         = 'V0'.
ls_item-item_amount      = '500000'.
ls_item-quantity         = '5'.
ls_item-po_unit          = 'EA'.
ls_item-de_cre_ind       = space.
APPEND ls_item TO lt_item.

ITEM_AMOUNT 합계 + 세금 = GROSS_AMOUNT 가 일치해야 합니다. 위 예시에서 500,000 + 500,000 + 세금 100,000 = 1,100,000 이 헤더의 GROSS_AMOUNT 와 맞아야 BAPI 가 통과합니다. 1원이라도 차이 나면 M8 060 ("Balance not zero") 에러가 발생합니다.


3단계 — 세금 처리 (자동 계산 vs 수동 입력)

세금 처리는 두 가지 패턴 중 하나를 선택합니다.

자동 계산HEADERDATA-CALC_TAX_IND = 'X'. SAP 가 아이템의 TAX_CODE 와 회사코드 세금 테이블을 보고 세금을 자동 계산합니다. TAXDATA 테이블은 비웁니다.

수동 입력CALC_TAX_IND = ' ' + TAXDATA 테이블에 세금 금액을 직접 채웁니다. 외부 시스템에서 받은 세금 금액을 그대로 반영해야 할 때 사용합니다.

" 수동 입력 패턴
DATA: lt_tax TYPE TABLE OF bapi_incinv_create_tax,
      ls_tax TYPE bapi_incinv_create_tax.

ls_tax-tax_code   = 'V1'.        " 10% 매입부가세
ls_tax-tax_amount = '100000'.    " 세금 100,000
ls_tax-taxjurcode = ''.          " 미국 외에는 비움
APPEND ls_tax TO lt_tax.

권장은 자동 계산입니다. 표준 SAP 의 세금 계산 로직을 그대로 사용하면 부가세·면세 분류 오류가 줄어듭니다. 외부 시스템 세금이 SAP 자동 계산과 다르면 그때만 수동 입력으로 전환하시기 바랍니다.


4단계 — 시뮬레이션 모드 활용 (실제 등록 전 검증)

HEADERDATA-SIMULATION = 'X' 로 호출하면 실제 전표를 만들지 않고 검증만 수행합니다. 인터페이스 개발 단계나 운영 중 대량 등록 직전 사전 점검에 유용합니다.

ls_header-simulation = 'X'.   " 시뮬레이션 모드

CALL FUNCTION 'BAPI_INCOMINGINVOICE_CREATE'
  EXPORTING
    headerdata        = ls_header
  IMPORTING
    invoicedocnumber  = lv_doc
    fiscalyear        = lv_year
  TABLES
    itemdata          = lt_item
    return            = lt_return.

" 시뮬레이션 결과 검증
READ TABLE lt_return WITH KEY type = 'E' TRANSPORTING NO FIELDS.
IF sy-subrc = 0.
  " 실제 등록 시에도 동일 에러 발생할 것
ENDIF.

시뮬레이션 모드에서도 RETURN 메시지는 정상으로 돌아옵니다. 에러가 없으면 실제 호출(SIMULATION 비우고 재호출) 시 성공할 가능성이 높습니다. 단, 시뮬레이션은 DB 상태를 보지 못하는 일부 검증을 건너뛰므로 100% 보장은 아닙니다.


5단계 — BAPI 호출 + COMMIT

전체 호출 흐름입니다. 헤더·아이템 채우고 호출, RETURN 검증 후 COMMIT 처리.

DATA: lt_return TYPE TABLE OF bapiret2,
      ls_return TYPE bapiret2,
      lv_doc    TYPE bapi_incinv_fld-inv_doc_no,
      lv_year   TYPE bapi_incinv_fld-fisc_year.

CALL FUNCTION 'BAPI_INCOMINGINVOICE_CREATE'
  EXPORTING
    headerdata        = ls_header
  IMPORTING
    invoicedocnumber  = lv_doc
    fiscalyear        = lv_year
  TABLES
    itemdata          = lt_item
    taxdata           = lt_tax
    return            = lt_return.

READ TABLE lt_return INTO ls_return
     WITH KEY type = 'E'.
IF sy-subrc = 0.
  CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
  WRITE: / '실패:', ls_return-message.
ELSE.
  CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
    EXPORTING wait = 'X'.
  WRITE: / '송장 등록 성공:', lv_doc, '/', lv_year.
ENDIF.

흔히 빠뜨리는 함정

GROSS_AMOUNT 와 ITEM_AMOUNT 합계 불일치

가장 흔한 에러입니다. 헤더 총금액 = 아이템 합계 + 세금. 통화 환산이나 소수점 처리 차이로 1원이라도 어긋나면 BAPI 가 거부합니다. 외부 데이터를 받아서 등록할 때는 두 값을 ABAP 측에서 다시 계산해서 비교한 후 호출하시기 바랍니다.

PO 번호 / PO 아이템 매칭 오류

PO_NUMBER + PO_ITEM 조합이 실제 EKKO/EKPO 에 존재하지 않거나, 이미 송장 처리가 끝난(EREKZ = 'X') PO 라인을 참조하면 "No more items can be invoiced for purchase order" 에러가 발생합니다. 호출 전 EKPO 의 송장 완료 플래그 확인이 안전합니다.

통화 자릿수

JPY 같은 0자리 통화, KWD 같은 3자리 통화에서 금액 단위가 BAPI 와 다르면 100배·1000배 어긋난 송장이 생성될 수 있습니다. TCURX 테이블에서 통화별 소수점 자릿수를 확인 후 호출 측에서 미리 정합화하시기 바랍니다.

CALC_TAX_IND 와 TAXDATA 동시 사용

자동 계산을 켜두고 TAXDATA 까지 채우면 BAPI 가 두 값을 비교해서 다르면 에러를 냅니다. 한 쪽만 사용하시기 바랍니다.

COMMIT 누락

BAPI 자체는 호출 성공이라도 BAPI_TRANSACTION_COMMIT 을 호출하지 않으면 DB 에 반영되지 않습니다. 비동기 인터페이스에서 COMMIT 직후 다른 BAPI 를 또 호출하려면 wait = 'X' 옵션이 필수입니다.

거래처 일회성 처리

거래처 마스터에 없는 일회성 거래처로 송장을 등록하려면 ADDRESSDATA 파라미터에 주소·세금ID 를 넣어야 합니다. 일반 거래처면 DIFF_INV 만 채우고 ADDRESSDATA 는 비웁니다.


전체 코드 — 복사용 통합본

*&---------------------------------------------------------------------*
*& Report  Z_XX_INVOICE_CREATE
*&---------------------------------------------------------------------*
*& 송장 생성 BAPI 호출 샘플 (PO 참조 표준 송장)
*&---------------------------------------------------------------------*
REPORT z_xx_invoice_create.

DATA: ls_header TYPE bapi_incinv_create_header,
      lt_item   TYPE TABLE OF bapi_incinv_create_item,
      ls_item   TYPE bapi_incinv_create_item,
      lt_return TYPE TABLE OF bapiret2,
      ls_return TYPE bapiret2,
      lv_doc    TYPE bapi_incinv_fld-inv_doc_no,
      lv_year   TYPE bapi_incinv_fld-fisc_year.

* ★ 1) 헤더 데이터 (송장 1건의 청구서 상단 정보)
ls_header-invoice_ind   = 'X'.           " 송장(X) / 대변메모(' ')
ls_header-doc_date      = sy-datum.      " 송장일자
ls_header-pstng_date    = sy-datum.      " 전기일자
ls_header-comp_code     = '1000'.        " 회사코드
ls_header-diff_inv      = '0000100001'.  " 거래처
ls_header-currency      = 'KRW'.
ls_header-gross_amount  = '1100000'.     " 총금액 (세금 포함)
ls_header-calc_tax_ind  = 'X'.           " 세금 자동 계산
ls_header-pmnttrms      = '0001'.
ls_header-ref_doc_no    = 'INV-2026-001'." 거래처 송장번호

* ★ 2) 아이템 데이터 (PO 라인별)
ls_item-invoice_doc_item = '000001'.
ls_item-po_number        = '4500000001'.
ls_item-po_item          = '00010'.
ls_item-tax_code         = 'V1'.         " 10% 매입부가세
ls_item-item_amount      = '500000'.
ls_item-quantity         = '10'.
ls_item-po_unit          = 'EA'.
ls_item-de_cre_ind       = space.        " 표준 송장
APPEND ls_item TO lt_item.

ls_item-invoice_doc_item = '000002'.
ls_item-po_number        = '4500000001'.
ls_item-po_item          = '00020'.
ls_item-tax_code         = 'V1'.
ls_item-item_amount      = '500000'.
ls_item-quantity         = '5'.
ls_item-po_unit          = 'EA'.
ls_item-de_cre_ind       = space.
APPEND ls_item TO lt_item.

* ★ 3) BAPI 호출
CALL FUNCTION 'BAPI_INCOMINGINVOICE_CREATE'
  EXPORTING
    headerdata        = ls_header
  IMPORTING
    invoicedocnumber  = lv_doc
    fiscalyear        = lv_year
  TABLES
    itemdata          = lt_item
    return            = lt_return.

* ★ 4) RETURN 검증
READ TABLE lt_return INTO ls_return
     WITH KEY type = 'E'.

IF sy-subrc = 0.
  CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
  WRITE: / '송장 등록 실패'.
  LOOP AT lt_return INTO ls_return.
    WRITE: / ls_return-type, ls_return-id,
             ls_return-number, ls_return-message.
  ENDLOOP.
ELSE.
  CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
    EXPORTING wait = 'X'.
  WRITE: / '송장 등록 성공',
         / '전표번호:', lv_doc,
         / '회계연도:', lv_year.
ENDIF.

같이 보면 좋은 글은 "BAPI_INCOMINGINVOICE_CANCEL — 송장 취소 BAPI 호출 방법" 입니다. 송장 생성 → 잘못 등록 발견 → 취소 → 정정 송장 재등록 순서의 인터페이스 시나리오에서 두 BAPI 를 짝으로 익혀두면 편리합니다.


요약

단계 처리 내용 핵심 포인트
1 문서 유형 결정 INVOICE_IND × DE_CRE_IND 조합
2 HEADERDATA 채우기 GROSS_AMOUNT 는 세금 포함 총액
3 ITEMDATA 채우기 PO 참조 + 아이템 합계 검증
4 세금 처리 자동 계산(CALC_TAX_IND) 권장
5 시뮬레이션 SIMULATION = 'X' 사전 검증
6 호출 + COMMIT RETURN 검증 후 wait='X' COMMIT

송장 생성 BAPI 는 시그니처 자체보다 "GROSS_AMOUNT = ITEM_AMOUNT 합계 + 세금" 의 금액 정합성과 INVOICE_IND × DE_CRE_IND 조합 의 문서 유형 매핑이 품질의 90% 를 좌우합니다. 외부 시스템 연동에서는 시뮬레이션 모드로 사전 검증한 후 실제 등록하는 패턴을 워크플로우에 박아두면 잘못된 송장이 운영 DB 에 들어가는 사고를 막을 수 있습니다.


Disclaimer — 이 포스트는 실무 정리 노트를 바탕으로 AI 보조로 정리되었습니다.

BAPI 시그니처·구조체 필드(BAPI_INCINV_CREATE_HEADER·BAPI_INCINV_CREATE_ITEM)·문서 유형 분기 로직은 SAP MM 표준(패키지 MRM · ECC 6.0 / S/4HANA on-premise) 기준이며, 사내 세금·결재·BAdI 커스터마이징에 따라 일부 동작이 다를 수 있으니 운영 시스템 적용 전 개발·QA 환경에서 검증하시기 바랍니다.