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

[SAP ABAP] BAPI_GOODSMVT_CANCEL — 입고·자재문서 취소 BAPI 호출 방법 (MBST 자동화 · MKPF-SMBLN 사전체크)

by Song.sh 2026. 5. 21.

SAP MM 모듈에서 자재문서를 취소하려면 화면에서는 MBST·MIGO_GR_REV 를 사용하지만, 인터페이스나 자동 정정 배치에서는 BAPI_GOODSMVT_CANCEL 을 호출합니다. 입고·출고·자재이동 어떤 종류든 한 BAPI 로 일괄 취소 가능합니다.

 

이 BAPI 는 송장 취소(BAPI_INCOMINGINVOICE_CANCEL) 처럼 자재문서 자체를 삭제하는 것이 아니라 반대 부호의 자재문서를 새로 생성 합니다. 원본 자재문서(예: BWART 101)와 취소 자재문서(BWART 102)가 짝으로 남아 재고 / 분개를 자동 청산하므로 추적 가능성이 끝까지 유지됩니다.

 

이 글에서는 BAPI 시그니처·전체 vs 부분 취소·전기일자 옵션·취소 가능 여부 사전 체크·COMMIT 처리·자주 발생하는 함정까지 정리합니다.

핵심 — BAPI_GOODSMVT_CANCEL 시그니처

📋 구분 파라미터 타입 설명
IMPORTING MATERIALDOCUMENT BAPI2017_GM_HEAD_02-MAT_DOC 취소할 자재문서 번호 (MKPF-MBLNR)
IMPORTING MATDOCUMENTYEAR BAPI2017_GM_HEAD_02-DOC_YEAR 회계연도 (MKPF-MJAHR)
IMPORTING GOODSMVT_PSTNG_DATE (Opt) BAPI2017_GM_HEAD_02-PSTNG_DATE 취소 전표 전기일자 (생략 시 시스템 일자)
IMPORTING GOODSMVT_PR_UNAME (Opt) PR_UNAME 인쇄 사용자명
EXPORTING GOODSMVT_HEADRET BAPI2017_GM_HEAD_RET 취소 자재문서 헤더 (취소 전표 번호 포함)
TABLES RETURN BAPIRET2 처리 메시지
TABLES GOODSMVT_MATDOCITEM (Opt) BAPI2017_GM_ITEM_04 특정 아이템만 취소 시 사용

입고 생성 BAPI(BAPI_GOODSMVT_CREATE) 가 HEADER + CODE + ITEM 3종 세트로 복잡한 것과 달리, 취소 BAPI 는 자재문서 번호 + 회계연도만 채우면 끝. 이동유형도, 자재·플랜트·수량도 SAP 가 원본 자재문서에서 그대로 읽어와 반대 부호로 자동 처리합니다.


1단계 — 전체 취소 (가장 단순한 패턴)

자재문서 전체를 한 번에 취소하는 표준 패턴입니다. GOODSMVT_MATDOCITEM 테이블은 비워두면 됩니다.

DATA: lt_return  TYPE TABLE OF bapiret2,
      ls_return  TYPE bapiret2,
      ls_headret TYPE bapi2017_gm_head_ret.

CALL FUNCTION 'BAPI_GOODSMVT_CANCEL'
  EXPORTING
    materialdocument    = '5000000001'   " 취소할 자재문서
    matdocumentyear     = '2026'
*   goodsmvt_pstng_date = sy-datum       " 생략 시 시스템 일자
  IMPORTING
    goodsmvt_headret    = ls_headret
  TABLES
    return              = lt_return.

READ TABLE lt_return INTO ls_return WITH KEY type = 'E'.
IF sy-subrc = 0.
  CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
ELSE.
  CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
    EXPORTING wait = 'X'.

  WRITE: / '취소 자재문서:', ls_headret-mat_doc, '/', ls_headret-doc_year.
ENDIF.

핵심은 GOODSMVT_HEADRET 에서 취소 자재문서 번호를 받는 것입니다. 원본 문서(5000000001)와 별개로 SAP 가 새 자재문서(예: 5000000002) 를 생성해 청산합니다. 인터페이스에서 외부 시스템에 취소 결과를 전달할 때 이 번호가 키 값이 됩니다.


2단계 — 부분(아이템) 취소

자재문서의 특정 아이템만 취소할 때 GOODSMVT_MATDOCITEM 테이블에 라인을 지정합니다.

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

ls_item-mat_doc      = '5000000001'.
ls_item-doc_year     = '2026'.
ls_item-matdoc_itm   = '0001'.            " 자재문서 라인번호 (MSEG-ZEILE)
ls_item-entry_qnt    = '50'.              " 일부 수량만 취소 가능
ls_item-entry_uom    = 'EA'.
APPEND ls_item TO lt_item.

CALL FUNCTION 'BAPI_GOODSMVT_CANCEL'
  EXPORTING
    materialdocument    = '5000000001'
    matdocumentyear     = '2026'
  IMPORTING
    goodsmvt_headret    = ls_headret
  TABLES
    return              = lt_return
    goodsmvt_matdocitem = lt_item.

부분 취소가 가능한 경우는 제한적입니다. 일반적으로 자재문서 라인이 후속 소비·이동 없이 그대로 남아 있어야 부분 취소가 허용됩니다. 후속 처리가 이미 발생한 경우 표준은 전체 취소 후 정정 흐름을 권장합니다.


3단계 — 호출 전 사전 체크 (취소 가능 여부)

BAPI 가 RETURN 에 에러를 담아 돌려주기는 하지만, 사전에 MKPF·MSEG 에서 취소 가능 여부를 확인 해두면 실패 호출을 줄일 수 있습니다.

DATA: lv_smbln TYPE mkpf-smbln,
      lv_xauto TYPE mseg-xauto.

" 1) 이미 취소된 문서인지 확인 (MKPF-SMBLN 가 채워져 있으면 이미 취소됨)
SELECT SINGLE mkpf~smbln
  INTO  lv_smbln
  FROM  mkpf
  WHERE mblnr = lv_mblnr
    AND mjahr = lv_mjahr.

IF lv_smbln IS NOT INITIAL.
  MESSAGE 'Already cancelled' TYPE 'E'.
ENDIF.

" 2) 후속 처리 여부 확인 (XAUTO = 'X' 자동 생성 라인은 별도 검증 필요)
SELECT SINGLE xauto
  INTO  lv_xauto
  FROM  mseg
  WHERE mblnr = lv_mblnr
    AND mjahr = lv_mjahr.

MKPF-SMBLN 이 채워져 있으면 이미 취소된 문서입니다. 한 자재문서를 두 번 취소하면 "Document already reversed" 에러가 발생하므로 사전 차단이 필요합니다.


4단계 — 전기일자 처리 (이전 기간 취소)

원본 자재문서의 전기일자가 마감된 기간에 속해 있고 현재 기간에 취소해야 한다면 GOODSMVT_PSTNG_DATE 에 현재 열려 있는 기간의 일자를 명시합니다.

CALL FUNCTION 'BAPI_GOODSMVT_CANCEL'
  EXPORTING
    materialdocument    = '5000000001'
    matdocumentyear     = '2025'           " 작년 문서
    goodsmvt_pstng_date = sy-datum         " 올해 일자로 취소
  IMPORTING
    goodsmvt_headret    = ls_headret
  TABLES
    return              = lt_return.

MMRV 에서 현재 회사 / 플랜트의 열린 기간을 확인 후 일자를 결정하시기 바랍니다. 회계 기간(OB52) 도 함께 열려 있어야 정상 처리됩니다.


5단계 — 다건 일괄 취소

여러 자재문서를 한 배치에서 취소할 때는 건별로 RETURN 검증 + COMMIT/ROLLBACK 패턴을 권장합니다. 한 건 실패가 다른 건에 영향 없게 분리하기 위함입니다.

LOOP AT lt_cancel_target INTO ls_target.

  REFRESH lt_return.
  CLEAR ls_headret.

  CALL FUNCTION 'BAPI_GOODSMVT_CANCEL'
    EXPORTING
      materialdocument    = ls_target-mblnr
      matdocumentyear     = ls_target-mjahr
      goodsmvt_pstng_date = ls_target-pstng_date
    IMPORTING
      goodsmvt_headret    = ls_headret
    TABLES
      return              = lt_return.

  READ TABLE lt_return WITH KEY type = 'E' TRANSPORTING NO FIELDS.
  IF sy-subrc = 0.
    CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
    APPEND VALUE #( mblnr  = ls_target-mblnr
                    status = 'FAIL'
                    msg    = ls_return-message ) TO lt_log.
  ELSE.
    CALL FUNCTION 'BAPI_TRANSACTION_COMMIT' EXPORTING wait = 'X'.
    APPEND VALUE #( mblnr      = ls_target-mblnr
                    cancel_doc = ls_headret-mat_doc
                    status     = 'OK' ) TO lt_log.
  ENDIF.

ENDLOOP.

흔히 빠뜨리는 함정

이미 송장 처리된 자재문서

PO 입고 자재문서가 이미 송장 처리(MIRO) 된 경우, 입고만 취소하면 GR/IR 잔액이 깨집니다. 올바른 순서는 송장 취소(MR8M 또는 BAPI_INCOMINGINVOICE_CANCEL) → 입고 취소 입니다. 송장이 살아 있는데 입고만 취소하면 BAPI 가 거부합니다.

후속 출고가 발생한 경우

입고 후 이미 그 자재가 출고·이동되어 재고에서 빠진 경우 단순 취소가 불가능합니다. 재고 부족 에러("Deficit of stock") 가 발생합니다. 이 경우 후속 이동을 먼저 취소한 다음 원본 입고를 취소해야 합니다.

이미 취소된 문서 재취소

MKPF-SMBLN 에 취소 문서가 이미 채워진 경우 재취소는 불가능합니다. 화면에서는 막혀 있지만 BAPI 직접 호출 시 RETURN 메시지로만 알려주므로 사전 SELECT 가 안전합니다.

회계 기간 마감

원본 문서가 속한 기간이 마감되어 있으면 GOODSMVT_PSTNG_DATE 를 현재 열린 기간으로 명시해야 합니다. 단, 회사 정책상 "전기 기간 자재문서는 현 기간으로 취소" 가 막혀 있는 경우도 있으니 운영팀과 확인이 필요합니다.

배치 / 시리얼 후속 처리

배치 관리 자재의 경우 입고 시 생성된 배치에 이미 후속 변경(BAPI_BATCH_CHANGE) 이 발생하면 일부 필드 검증에 막힐 수 있습니다. 시리얼 관리 자재도 시리얼 상태가 "활성" 이어야만 취소가 진행됩니다.

COMMIT 누락 / 비동기 SELECT

BAPI 자체 호출 성공이라도 BAPI_TRANSACTION_COMMIT 누락 시 DB 미반영. 동기 인터페이스에서 COMMIT 직후 MKPF SELECT 하려면 wait = 'X' 필수입니다.

MR11 GR/IR 청산과의 관계

GR/IR 미청산 라인이 있는 자재문서는 MR11 청산 후 다시 입고 취소를 시도해야 합니다. 회사 정책에 따라 BAPI 호출 시점 검증을 우회하는 경우도 있으므로 운영기 흐름을 사전 확인하시기 바랍니다.


전체 코드 — 복사용 통합본

*&---------------------------------------------------------------------*
*& Report  Z_XX_GOODS_RECEIPT_CANCEL
*&---------------------------------------------------------------------*
*& 입고 / 자재이동 취소 BAPI 호출 샘플
*&---------------------------------------------------------------------*
REPORT z_xx_goods_receipt_cancel.

DATA: ls_headret TYPE bapi2017_gm_head_ret,
      lt_return  TYPE TABLE OF bapiret2,
      ls_return  TYPE bapiret2.

DATA: lv_mblnr   TYPE bapi2017_gm_head_02-mat_doc  VALUE '5000000001',
      lv_mjahr   TYPE bapi2017_gm_head_02-doc_year VALUE '2026',
      lv_pstdat  TYPE bapi2017_gm_head_02-pstng_date.

DATA: lv_smbln   TYPE mkpf-smbln.

* ★ 사전 체크: 이미 취소된 문서인지 확인
SELECT SINGLE smbln
  INTO  lv_smbln
  FROM  mkpf
  WHERE mblnr = lv_mblnr
    AND mjahr = lv_mjahr.

IF sy-subrc <> 0.
  WRITE: / '대상 자재문서 없음:', lv_mblnr, lv_mjahr.
  EXIT.
ENDIF.

IF lv_smbln IS NOT INITIAL.
  WRITE: / '이미 취소된 문서 — 재취소 불가. 취소문서:', lv_smbln.
  EXIT.
ENDIF.

* ★ 핵심: BAPI 호출 (전체 취소)
CALL FUNCTION 'BAPI_GOODSMVT_CANCEL'
  EXPORTING
    materialdocument    = lv_mblnr
    matdocumentyear     = lv_mjahr
*   goodsmvt_pstng_date = lv_pstdat   " 필요 시 활성화 (이전 기간 취소)
  IMPORTING
    goodsmvt_headret    = ls_headret
  TABLES
    return              = lt_return.

* ★ 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_mblnr, '/', lv_mjahr,
         / '취소 자재문서:', ls_headret-mat_doc, '/', ls_headret-doc_year.
ENDIF.

같이 보면 좋은 글은 "BAPI_GOODSMVT_CREATE — 입고·출고·자재이동 BAPI 호출 방법" 입니다. 자재문서 생성 → 취소 흐름을 한 세트로 익혀두면 인터페이스의 양방향 자동화에 그대로 적용 가능합니다.


요약

단계 처리 내용 핵심 포인트
1 사전 체크 MKPF-SMBLN · 송장·후속 출고 확인
2 전체 vs 부분 결정 전체는 ITEM 비움 · 부분은 ITEM 명시
3 전기일자 결정 현 기간 자재문서 일자 또는 현재 일자
4 BAPI 호출 MBLNR + MJAHR 두 개로 트리거
5 RETURN 검증 Type 'E' 있으면 ROLLBACK
6 COMMIT wait = 'X' 동기 처리

입고 취소 BAPI 는 시그니처가 단순한 만큼 사전 체크와 처리 순서가 품질을 좌우 합니다. 송장 → 입고 순으로 취소, 후속 출고가 있다면 그것부터 취소, 이미 취소된 문서 재시도 차단. 이 세 가지를 인터페이스 워크플로우에 패턴으로 박아두면 운영 중 사고가 거의 발생하지 않습니다.


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

BAPI 시그니처·MKPF·MSEG 필드 구조는 SAP MM 표준(패키지 MB · ECC 6.0 / S/4HANA on-premise) 기준이며, 사내 추가 BAdI · GR/IR 정책 · 결재 흐름에 따라 일부 동작이 다를 수 있으니 운영 시스템 적용 전 개발·QA 환경에서 검증하시기 바랍니다.