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

[SAP ABAP] 배치(Batch) 생성·변경 BAPI 풀 패턴 — BAPI_BATCH_CREATE + BAPI_OBJCL_CHANGE 로 특성값까지 (Class Type 023)

by Song.sh 2026. 5. 20.

SAP MM 환경에서 배치(Batch) 관리 자재를 다루다 보면 배치 마스터를 코드로 자동 생성/변경해야 하는 시나리오가 자주 생깁니다. MES 가 자체 채번한 배치 번호를 SAP 에 등록할 때, 외부 시스템에서 받은 배치 정보(생산일·유효기한·등급 등) 를 자동 반영할 때, 입고 처리 직전에 배치 분류 특성값을 미리 채워둘 때 — 모두 BAPI 호출로 처리합니다.

 

배치 관련 BAPI 작업은 보통 두 단계로 묶입니다. 첫째, 배치 마스터 자체를 생성/변경(BAPI_BATCH_CREATE · BAPI_BATCH_CHANGE) 하고, 둘째, 그 배치의 분류 특성값(Classification System) 을 BAPI_OBJCL_CHANGE 로 등록합니다. 두 단계가 한 세트로 동작해야 입고 시점에 배치의 등급·유효기한·로트 정보가 정확하게 따라옵니다.

 

이 글은 배치 생성·변경·분류 특성값 등록의 전체 흐름을 한 화면에 모은 메모입니다. 노트의 핵심 코드 3개(BAPI_BATCH_CREATEBAPI_OBJCL_CONCATENATEKEYBAPI_OBJCL_CHANGE) 패턴을 따라가면서 분류 시스템 사전 셋업 / 자주 빠뜨리는 함정 / 전체 코드 통합본까지 정리합니다.


핵심 — BAPI 4개 한눈 비교

배치 관련 BAPI 는 역할별로 4개로 나뉩니다. 둘은 배치 마스터용, 둘은 분류 시스템용.

BAPI 역할 대상
BAPI_BATCH_CREATE 배치 마스터 신규 생성 MCH1 · MCHA · MCHB
BAPI_BATCH_CHANGE 기존 배치의 속성 변경 (유효기한·상태·잔액 등) MCH1 · MCHA · MCHB
BAPI_OBJCL_CONCATENATEKEY 분류 조회/변경용 objectkey 조립 자재(MATNR) + 배치(CHARG)
BAPI_OBJCL_CHANGE 배치의 분류 특성값 등록/변경 AUSP · CABN · KLAH · KSML

핵심 한 줄: 배치 마스터 생성 → 분류 키 조립 → 특성값 등록 → COMMIT. 한 세트로 묶이는 4단계를 빠뜨리면 화면(MSC2N) 에서 배치는 보이는데 특성값이 비어 있는 사고가 발생합니다.


1단계 — 사전 셋업: 분류 시스템 매핑 확인

본격적인 BAPI 호출 전에 사전 셋업을 확인합니다. 배치 분류는 SAP 의 분류 시스템(Classification) 을 사용하므로, 자재마스터에 배치 클래스가 매핑되어 있어야 BAPI 가 동작합니다.

확인 항목 방법
배치 클래스 존재 CL02 → Class Type 023 (Batch) → 사내 사용 배치 클래스 조회
자재마스터 ↔ 배치 클래스 매핑 MM02 → Classification 뷰 → Class Type 023 + 사내 클래스 등록 확인
특성 마스터(CABN) CT04 → 특성 코드 확인 (예: ZBATCH_GRADE · ZBATCH_THICK)
배치 화면 확인 MSC2N → 자재+플랜트+배치 조회 → 분류 탭에 특성값 보이는지

운영팀(PP·QM·기준정보 담당) 이 이미 셋업해 둔 경우가 대부분이지만, 신규 자재 유형이거나 기존 자재 셋업이 잘못된 경우 BAPI 가 silent 하게 실패합니다(에러는 없는데 특성값이 안 들어감). BAPI 첫 호출 전에 한 번 확인.


2단계 — BAPI_BATCH_CREATE: 배치 마스터 생성

가장 단순한 케이스. 자재·배치·플랜트·저장위치만 지정하면 배치 마스터가 생성됩니다.

DATA: ls_attr    TYPE bapibatchatt,        " ★ R 없음 (BAPIBATCHATT)
      lt_return  TYPE TABLE OF bapiret2,
      ls_return  TYPE bapiret2.

" 배치 속성 (선택 — 기본값으로 두려면 비워두기)
" BAPIBATCHATT 는 SAP 표준 필드명이 아닌 BAPI 영어 명명 규칙 사용
ls_attr-expirydate = '20271231'.    " 유효기한 (MCHA-VFDAT 으로 매핑)
ls_attr-prod_date  = '20260101'.    " 제조일 (MCHA-HSDAT)
ls_attr-statuskey  = '1'.           " 배치 상태 키 (MCHA-ZUSCH)

CALL FUNCTION 'BAPI_BATCH_CREATE'
  EXPORTING
    material              = 'TEST-MAT-001'      " 자재 코드
    batch                 = 'BATCH-0001'        " 배치 번호
    plant                 = '0001'              " 플랜트
    batchstoragelocation  = '0001'              " 저장위치
    batchattributes       = ls_attr             " 속성 (유효기한 등)
  TABLES
    return                = lt_return.

" 결과 확인
READ TABLE lt_return INTO ls_return
  WITH KEY type = 'E'.
IF sy-subrc = 0.
  CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
  MESSAGE |배치 생성 실패: { ls_return-message }| TYPE 'E'.
ELSE.
  CALL FUNCTION 'BAPI_TRANSACTION_COMMIT' EXPORTING wait = 'X'.
  MESSAGE |배치 { 'BATCH-0001' } 생성 완료| TYPE 'S'.
ENDIF.

 

주요 파라미터:

  • batchstoragelocation — 저장위치는 선택사항. 안 넣으면 MCHB(저장위치별 재고) 레코드는 입고 시점에 생성됨
  • batchattributes(BAPIBATCHATT — R 없음) — 유효기한·제조일·상태 등 표준 배치 속성
  • BAPI_TRANSACTION_COMMIT 별도 호출 필수

이 단계까지만 끝나면 배치 헤더는 만들어지지만 분류 특성값(등급·두께·로트 정보 등) 은 비어 있습니다. 이어서 3-4단계에서 특성값을 채웁니다.


3단계 — BAPI_OBJCL_CONCATENATEKEY: 분류 조회용 키 조립

배치의 분류 특성을 변경하려면 분류 시스템이 알아볼 수 있는 형태의 objectkey(자재 + 배치 조합 키) 를 먼저 만들어야 합니다. 이 키 조립을 표준 BAPI 가 해 줍니다.

" ★ BAPI 시그니처: OBJECTKEYTABLE LIKE BAPI1003_OBJECT_KEYS / OBJECTKEY_CONC LIKE BAPI1003_KEY-OBJECT
DATA: lt_keytab TYPE TABLE OF bapi1003_object_keys,
      ls_keytab TYPE bapi1003_object_keys,
      lv_object TYPE bapi1003_key-object,
      lt_return TYPE TABLE OF bapiret2.

" 자재 키
ls_keytab-key_field = 'MATNR'.
ls_keytab-value_int = 'TEST-MAT-001'.
APPEND ls_keytab TO lt_keytab.

" 배치 키
CLEAR ls_keytab.
ls_keytab-key_field = 'CHARG'.
ls_keytab-value_int = 'BATCH-0001'.
APPEND ls_keytab TO lt_keytab.

" 키 조립 호출
CALL FUNCTION 'BAPI_OBJCL_CONCATENATEKEY'
  EXPORTING
    objecttable    = 'MCH1'              " 배치 마스터 테이블
  IMPORTING
    objectkey_conc = lv_object           " 조립된 키 (출력)
  TABLES
    objectkeytable = lt_keytab
    return         = lt_return.

 

objecttable = 'MCH1' 은 분류 시스템 입장에서 "이 키가 어느 테이블의 키인지" 를 알려주는 메타정보. 배치 분류는 표준으로 MCH1(자재+배치) 을 사용합니다. 일부 환경에서는 MCHA(자재+플랜트+배치 — cross-plant) 를 쓰기도 하므로 사내 환경 확인 필요.


4단계 — BAPI_OBJCL_CHANGE: 분류 특성값 등록

조립된 objectkey 와 함께 BAPI_OBJCL_CHANGE 를 호출하면 분류 특성값이 등록/변경됩니다. 특성 타입(문자형·수치형·통화형) 별로 별도 테이블에 채워 넣습니다.

DATA: lt_charnew  TYPE TABLE OF bapi1003_alloc_values_char,
      lt_numnew   TYPE TABLE OF bapi1003_alloc_values_num,
      lt_currnew  TYPE TABLE OF bapi1003_alloc_values_curr,
      ls_charnew  TYPE bapi1003_alloc_values_char,
      ls_numnew   TYPE bapi1003_alloc_values_num,
      lv_status   TYPE bapi1003_key-status.   " ★ BAPI EXPORTING CLASSIF_STATUS 의 실제 타입

" 1) 문자형 특성 — 등급 (예: A+)
ls_charnew-charact     = 'ZBATCH_GRADE'.
ls_charnew-value_char  = 'A+'.
APPEND ls_charnew TO lt_charnew.

" 2) 수치형 특성 — 두께 (예: 1.20 mm)
ls_numnew-charact      = 'ZBATCH_THICK'.
ls_numnew-value_from   = '1.20'.
APPEND ls_numnew TO lt_numnew.

" 3) BAPI 호출
CALL FUNCTION 'BAPI_OBJCL_CHANGE'
  EXPORTING
    objectkey          = lv_object       " 2단계에서 조립한 키
    objecttable        = 'MCH1'
    classnum           = 'ZCL_BATCH'     " 사내 배치 클래스 (CL02 에서 확인)
    classtype          = '023'           " Batch class type
  IMPORTING
    classif_status     = lv_status
  TABLES
    allocvaluesnumnew  = lt_numnew       " 수치형 특성값
    allocvaluescharnew = lt_charnew      " 문자형 특성값
    allocvaluescurrnew = lt_currnew      " 통화형 특성값 (비어도 전달)
    return             = lt_return.

" 4) COMMIT
READ TABLE lt_return INTO ls_return WITH KEY type = 'E'.
IF sy-subrc = 0.
  CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
  MESSAGE |분류 특성 등록 실패: { ls_return-message }| TYPE 'E'.
ELSE.
  CALL FUNCTION 'BAPI_TRANSACTION_COMMIT' EXPORTING wait = 'X'.
ENDIF.

 

주요 포인트:

  • classtype = '023' — 배치 분류의 SAP 표준 타입 코드(자재 분류는 '001')
  • allocvalues*new 3개 테이블 모두 NOT OPTIONAL — 빈 값이어도 반드시 전달
  • classif_status' ' 또는 '1' 이면 정상 — 다른 값이면 에러 추적

5단계 — BAPI_BATCH_CHANGE: 기존 배치 속성 변경

이미 존재하는 배치의 유효기한·상태·잔액 같은 표준 속성을 변경할 때는 BAPI_BATCH_CHANGE 사용. 시그니처는 CREATE 와 비슷하지만 변경 의도 매핑 구조체(BATCHATTRIBUTESX)가 필수 라는 차이가 있습니다.

DATA: ls_attr  TYPE bapibatchatt,         " ★ R 없음 (BAPIBATCHATT)
      ls_attrx TYPE bapibatchattx.        " ★ 변경 의도 매핑 (BAPIBATCHATTX)

" 변경할 값 채우기 (BAPI 영어 필드명)
ls_attr-expirydate = '20281231'.   " 유효기한 연장
ls_attr-statuskey  = '2'.          " 상태를 Restricted 로 변경

" 변경 의도 매핑 — 변경할 필드만 'X' (BAPIBATCHATTX 도 동일한 영어 필드명 사용)
ls_attrx-expirydate = 'X'.
ls_attrx-statuskey  = 'X'.

CALL FUNCTION 'BAPI_BATCH_CHANGE'
  EXPORTING
    material         = 'TEST-MAT-001'
    batch            = 'BATCH-0001'
    plant            = '0001'
    batchattributes  = ls_attr            " 변경 후 값
    batchattributesx = ls_attrx           " ★ 어떤 필드를 변경할지 매핑
  TABLES
    return           = lt_return.

" 분류 특성도 같이 변경하려면 3-4단계 패턴 그대로 다시 호출
" → CONCATENATEKEY → OBJCL_CHANGE (값만 갱신)

CALL FUNCTION 'BAPI_TRANSACTION_COMMIT' EXPORTING wait = 'X'.

BATCHATTRIBUTES + BATCHATTRIBUTESX 의 의미: BAPI_PO_CHANGE 의 POITEM + POITEMX 한 쌍과 같은 패턴입니다. 한쪽(BATCHATTRIBUTES) 에는 변경할 새 값을 채우고, 다른 한쪽(BATCHATTRIBUTESX) 에는 그 필드의 변경 의도를 'X' 로 마크. BATCHATTRIBUTESX 에 마크되지 않은 필드는 새 값을 채워도 BAPI 가 무시합니다.

배치 자체의 속성(MCHA-VFDAT · MCHA-ZUSCH 등) 은 BATCH_CHANGE 로(BAPI 영어 필드명 EXPIRYDATE · STATUSKEY), 분류 특성값(AUSP) 은 OBJCL_CHANGE 로 — 두 영역이 명확히 분리 되어 있습니다. 변경 시나리오에 맞춰 둘 중 하나 또는 둘 다 호출.


6단계 — 실무 패턴: "있으면 변경 / 없으면 생성"

가장 자주 만나는 시나리오. 외부 시스템에서 받은 배치가 SAP 에 있으면 변경, 없으면 새로 만들기.

DATA: lv_exists TYPE flag.

" 1) 배치 존재 여부 확인
SELECT SINGLE @abap_true FROM mch1
  INTO @lv_exists
  WHERE matnr = @iv_matnr
    AND charg = @iv_batch.

IF lv_exists = abap_true.
  " 있음 → 변경 (BATCHATTRIBUTESX 변경 의도 매핑 필수)
  CALL FUNCTION 'BAPI_BATCH_CHANGE'
    EXPORTING material         = iv_matnr
              batch            = iv_batch
              plant            = iv_werks
              batchattributes  = ls_attr
              batchattributesx = ls_attrx       " ★ 변경할 필드만 'X'
    TABLES    return           = lt_return.
ELSE.
  " 없음 → 생성
  CALL FUNCTION 'BAPI_BATCH_CREATE'
    EXPORTING material              = iv_matnr
              batch                 = iv_batch
              plant                 = iv_werks
              batchstoragelocation  = iv_lgort
              batchattributes       = ls_attr
    TABLES    return                = lt_return.
ENDIF.

" 2) 결과 체크
READ TABLE lt_return INTO ls_return WITH KEY type = 'E'.
IF sy-subrc = 0.
  CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
  RETURN.
ENDIF.

" 3) 분류 키 조립
CALL FUNCTION 'BAPI_OBJCL_CONCATENATEKEY'
  EXPORTING objecttable    = 'MCH1'
  IMPORTING objectkey_conc = lv_object
  TABLES    objectkeytable = lt_keytab.

" 4) 분류 특성값 등록/변경
CALL FUNCTION 'BAPI_OBJCL_CHANGE'
  EXPORTING objectkey   = lv_object
            objecttable = 'MCH1'
            classnum    = 'ZCL_BATCH'
            classtype   = '023'
  TABLES    allocvaluesnumnew  = lt_numnew
            allocvaluescharnew = lt_charnew
            allocvaluescurrnew = lt_currnew
            return             = lt_return.

" 5) 최종 COMMIT
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'.
ENDIF.

이 패턴이 가장 안전합니다. SELECT 로 존재 여부를 한 번에 확인하고 CREATE 또는 CHANGE 분기, 그 다음 분류 특성값을 통합 처리.


흔히 빠뜨리는 함정

BAPI_TRANSACTION_COMMIT 누락

CALL FUNCTION 'BAPI_BATCH_CREATE' ...
" ❌ COMMIT 없음 — DB 반영 안 됨

BAPI 는 자동 COMMIT 안 함. 호출 후 BAPI_TRANSACTION_COMMIT 명시 호출 필수. wait = 'X' 로 동기 커밋 권장.

BAPI_BATCH_CHANGE 에서 BATCHATTRIBUTESX 누락

CALL FUNCTION 'BAPI_BATCH_CHANGE'
  EXPORTING material        = p_matnr
            batch           = p_charg
            batchattributes = ls_attr.   " ❌ BATCHATTRIBUTESX 없음
" → 새 값을 채워도 BAPI 가 변경 안 함

BAPI_BATCH_CHANGE 는 BAPI_PO_CHANGE 와 같은 X-구조체 패턴. 변경할 필드를 BATCHATTRIBUTES 에 채우고 BATCHATTRIBUTESX 의 같은 필드에 'X' 마크 — 한 쌍이 필수입니다. BATCHATTRIBUTESX 가 없거나 해당 필드에 마크가 빠지면 BAPI 가 "변경 의도 없음" 으로 해석해 새 값을 무시합니다.

BAPIBATCHATT 타입명 오타

DATA ls_attr TYPE bapibatchattr.   " ❌ R 한 개 더 — 잘못된 타입
DATA ls_attr TYPE bapibatchatt.    " ✅ R 없음

자주 헷갈리는 부분. BAPIBATCHATT(R 없음) 가 SAP 표준 구조 이름. CHANGE 용 X-구조체는 BAPIBATCHATTX(끝에 X).

ALLOC 테이블 3개 다 안 전달

CALL FUNCTION 'BAPI_OBJCL_CHANGE'
  TABLES allocvaluescharnew = lt_charnew.   " ❌ num / curr 누락

allocvaluesnumnew · allocvaluescharnew · allocvaluescurrnew 세 테이블은 NOT OPTIONAL. 비어 있어도 반드시 전달. 안 그러면 시그니처 충돌.

Class Type 잘못 입력

classtype = '001'.   " ❌ 자재 분류 / 배치는 '023'

classtype = '023'(Batch 분류) 가 표준. 자재 분류('001') 와 헷갈리면 BAPI 가 silent 하게 통과하지만 실제 배치 특성값은 등록되지 않음.

자재마스터에 배치 클래스 매핑 누락

MM02 → Classification 뷰 → 클래스 등록 없음
  → BAPI_OBJCL_CHANGE 호출 시 status = ERROR
  → "Class XX is not assigned to material" 메시지

자재마스터(MM02) 의 Classification 뷰에 배치 클래스가 등록되어 있어야 분류 BAPI 가 동작합니다. 운영팀과 협의해 IMG 셋업 또는 자재 마스터 수정.

특성 코드 대소문자 / 존재 안 함

ls_charnew-charact = 'zbatch_grade'.   " ❌ 소문자
ls_charnew-charact = 'ZBATCH_GRADEX'.  " ❌ CT04 에 없는 코드

특성 코드(CHARACT) 는 대문자 + CT04 에 등록된 정확한 이름. 다르면 그 줄만 무시되고 다른 특성값은 정상 등록 — 부분 성공이라 발견이 어려움. CT04 확인 필수.

MCH1 vs MCHA 혼동

objecttable = 'MCHA'.   " 일부 환경에선 동작 / 다른 환경에선 안 됨

배치 분류의 표준 objecttable 은 MCH1. 일부 cross-plant 배치 관리 환경에서는 MCHA 가 정답일 수 있음. 사내 시스템에서 MSC3N 으로 한 건 조회해 "어느 테이블의 키로 분류가 잡혀 있는지" 확인 후 결정.

LOOP 안에서 COMMIT 한 번만

LOOP AT lt_batches INTO ls_batch.
  CALL FUNCTION 'BAPI_BATCH_CREATE' ...
  CALL FUNCTION 'BAPI_OBJCL_CHANGE' ...
ENDLOOP.
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT' EXPORTING wait = 'X'.
" ❌ LOOP 끝에 한 번만 — 에러난 건도 같이 묶여 처리될 위험

대량 처리 시 매 건마다 결과 체크 후 COMMIT 또는 ROLLBACK 분리 처리. 에러 건만 재처리 가능하게 설계.

BAPI 결과의 type = 'W' 무시

배치 분류 BAPI 는 warning(TYPE = 'W') 메시지가 자주 들어옵니다. 일부 warning 은 무시해도 되지만(예: 일부 특성값이 비어 있음), 일부는 실제 데이터 반영 안 됨을 의미. 메시지 ID·번호로 분류해 처리.


전체 코드 — 복사용 통합본

배치 생성 + 분류 특성값 등록 한 사이클을 미니 리포트로 정리.

REPORT zr_bapi_batch_create_demo.

PARAMETERS: p_matnr TYPE matnr OBLIGATORY DEFAULT 'TEST-MAT-001',
            p_charg TYPE charg_d OBLIGATORY DEFAULT 'BATCH-0001',
            p_werks TYPE werks_d OBLIGATORY DEFAULT '0001',
            p_lgort TYPE lgort_d              DEFAULT '0001',
            p_grade TYPE char10               DEFAULT 'A+',
            p_thick TYPE p DECIMALS 2         DEFAULT '1.20'.

DATA: ls_attr     TYPE bapibatchatt,                          " ★ BAPIBATCHATT (R 없음)
      ls_attrx    TYPE bapibatchattx,                         " ★ CHANGE 용 X-구조체
      lt_return   TYPE TABLE OF bapiret2,
      ls_return   TYPE bapiret2,
      lt_keytab   TYPE TABLE OF bapi1003_object_keys,         " ★ OBJECTKEYTABLE 타입
      ls_keytab   TYPE bapi1003_object_keys,
      lv_object   TYPE bapi1003_key-object,                   " OBJECTKEY_CONC 타입
      lt_charnew  TYPE TABLE OF bapi1003_alloc_values_char,
      ls_charnew  TYPE bapi1003_alloc_values_char,
      lt_numnew   TYPE TABLE OF bapi1003_alloc_values_num,
      ls_numnew   TYPE bapi1003_alloc_values_num,
      lt_currnew  TYPE TABLE OF bapi1003_alloc_values_curr,
      lv_status   TYPE bapi1003_key-status,                   " ★ CLASSIF_STATUS 타입
      lv_exists   TYPE flag.

* === 1) 배치 존재 여부 ===
SELECT SINGLE @abap_true FROM mch1
  INTO @lv_exists
  WHERE matnr = @p_matnr AND charg = @p_charg.

* === 2) 배치 속성 준비 (BAPI 영어 필드명 사용) ===
ls_attr-expirydate = '20271231'.    " MCHA-VFDAT 으로 매핑
ls_attr-prod_date  = sy-datum.      " MCHA-HSDAT
ls_attr-statuskey  = '1'.           " MCHA-ZUSCH (Available)

" CHANGE 용 변경 의도 매핑 (변경할 필드만 'X')
ls_attrx-expirydate = 'X'.
ls_attrx-prod_date  = 'X'.
ls_attrx-statuskey  = 'X'.

* === 3) 배치 생성 또는 변경 ===
IF lv_exists = abap_true.
  CALL FUNCTION 'BAPI_BATCH_CHANGE'
    EXPORTING material         = p_matnr
              batch            = p_charg
              plant            = p_werks
              batchattributes  = ls_attr
              batchattributesx = ls_attrx     " ★ 변경 의도 매핑
    TABLES    return           = lt_return.
  WRITE: / |기존 배치 변경: { p_charg }|.
ELSE.
  CALL FUNCTION 'BAPI_BATCH_CREATE'
    EXPORTING material              = p_matnr
              batch                 = p_charg
              plant                 = p_werks
              batchstoragelocation  = p_lgort
              batchattributes       = ls_attr
    TABLES    return                = lt_return.
  WRITE: / |신규 배치 생성: { p_charg }|.
ENDIF.

READ TABLE lt_return INTO ls_return WITH KEY type = 'E'.
IF sy-subrc = 0.
  CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
  WRITE: / |❌ 배치 처리 실패: { ls_return-message }|.
  RETURN.
ENDIF.

* === 4) 분류 키 조립 ===
ls_keytab-key_field = 'MATNR'.
ls_keytab-value_int = p_matnr.
APPEND ls_keytab TO lt_keytab.

CLEAR ls_keytab.
ls_keytab-key_field = 'CHARG'.
ls_keytab-value_int = p_charg.
APPEND ls_keytab TO lt_keytab.

CALL FUNCTION 'BAPI_OBJCL_CONCATENATEKEY'
  EXPORTING objecttable    = 'MCH1'
  IMPORTING objectkey_conc = lv_object
  TABLES    objectkeytable = lt_keytab
            return         = lt_return.

* === 5) 분류 특성값 ===
" 등급 (문자형)
ls_charnew-charact    = 'ZBATCH_GRADE'.
ls_charnew-value_char = p_grade.
APPEND ls_charnew TO lt_charnew.

" 두께 (수치형)
ls_numnew-charact     = 'ZBATCH_THICK'.
ls_numnew-value_from  = p_thick.
APPEND ls_numnew TO lt_numnew.

* === 6) 분류 BAPI 호출 ===
CALL FUNCTION 'BAPI_OBJCL_CHANGE'
  EXPORTING
    objectkey          = lv_object
    objecttable        = 'MCH1'
    classnum           = 'ZCL_BATCH'
    classtype          = '023'
  IMPORTING
    classif_status     = lv_status
  TABLES
    allocvaluesnumnew  = lt_numnew
    allocvaluescharnew = lt_charnew
    allocvaluescurrnew = lt_currnew
    return             = lt_return.

* === 7) 최종 COMMIT ===
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: /,
         / |✅ 배치 { p_charg } 처리 완료|,
         / |   - 자재    : { p_matnr }|,
         / |   - 플랜트  : { p_werks }|,
         / |   - 등급    : { p_grade }|,
         / |   - 두께    : { p_thick }|.
ENDIF.

* === 8) 메시지 로그 ===
LOOP AT lt_return INTO ls_return WHERE type CA 'EWI'.
  WRITE: / |[{ ls_return-type }] { ls_return-message }|.
ENDLOOP.

이 미니 리포트를 그대로 SE38 에 넣고 실행하면 자재 + 배치 + 플랜트만 입력해도 배치 생성·변경 + 분류 특성값 등록이 한 번에 처리됩니다. 운영 환경에서는 자사 클래스명(ZCL_BATCH) · 특성 코드(ZBATCH_GRADE·ZBATCH_THICK) 만 사내 명명 규칙으로 교체.


요약

단계 BAPI 역할
1 사전 셋업 확인 CL02 · CT04 · MM02 Classification 뷰
2 BAPI_BATCH_CREATE 배치 마스터 생성 (자재 + 배치 + 플랜트)
3 BAPI_OBJCL_CONCATENATEKEY 분류 조회용 objectkey 조립 (MATNR + CHARG)
4 BAPI_OBJCL_CHANGE 분류 특성값 등록 (classtype = '023')
5 BAPI_BATCH_CHANGE 기존 배치 속성 변경 (유효기한·상태 등)
6 BAPI_TRANSACTION_COMMIT 최종 커밋 (wait = 'X')

배치 BAPI 작업의 핵심은 "마스터(BATCH_CREATE / CHANGE) 와 특성(OBJCL_CHANGE) 이 분리되어 있다" 는 사실을 이해하는 것입니다. 둘이 한 세트로 호출돼야 화면에서 봤을 때 자연스럽게 보이는 배치가 만들어집니다. 사전 셋업(CL02 · MM02 Classification 뷰) · COMMIT · ALLOC 3개 테이블 필수 전달 · classtype '023' 같은 함정 몇 가지만 피하면, 같은 패턴을 MES 연동 / 외부 시스템 수신 / 일괄 업로드 같은 다른 시나리오에도 그대로 재사용할 수 있습니다.


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

BAPI_BATCH_CREATE · BAPI_BATCH_CHANGE · BAPI_OBJCL_CONCATENATEKEY · BAPI_OBJCL_CHANGE · BAPI_TRANSACTION_COMMIT 은 SAP MM 표준 BAPI 로 ECC 6.0 / S/4HANA on-premise 환경에서 동일하게 동작합니다. 배치 분류는 SAP 표준 분류 시스템(Classification)의 Class Type 023 을 사용하며, 자재마스터(MM02) 의 Classification 뷰에 사내 배치 클래스가 등록되어 있어야 분류 BAPI 가 동작합니다.

objecttable 은 일반적으로 MCH1 (자재 + 배치) 가 표준이며, cross-plant 배치 관리(batch level = 9) 환경에서는 MCHA 가 정답이 될 수 있어 사내 환경 확인이 필요합니다. BAPI_OBJCL_CHANGEallocvalues*new 3개 테이블(수치·문자·통화) 은 NOT OPTIONAL 이며 빈 테이블이라도 반드시 전달해야 시그니처가 매칭됩니다.

 

본문의 자재 코드 · 배치 번호 · 플랜트 · 클래스명 · 특성 코드는 회사 식별 가능 정보를 일반화한 예시이며, 사내 명명 규칙에 맞춰 조정해 사용하시기 바랍니다.