SAP

MARD vs LQUA 재고 불일치 3가지 원인 #shorts #SAP #WM

▶ YouTube에서 보기

이 글이 답하는 질문

MMBE에서 본 재고와 LS26에서 본 재고가 다르다는 문의는 SAP 물류 운영에서 가장 자주 올라오는 이슈 중 하나입니다. 원인은 대부분 하나로 수렴합니다. IM(Inventory Management)과 WM(Warehouse Management)이 같은 재고를 서로 다른 단위로 이원 관리하기 때문입니다. 이 글은 가상의 자동차 부품 제조사 "두레정공" 사례로 두 재고의 구조 차이를 뜯어보고, 어긋나는 대표 상황을 ABAP 검증 리포트로 직접 잡아내는 실전 예제입니다.

  • IM은 저장위치(Storage Location) 수준, WM은 빈(Bin) 수준 — 이 차이가 정확히 무엇인지 설명할 수 있다
  • MARD 계열과 LQUA 계열 테이블에서 각각 재고를 조회할 수 있다
  • MIGO 입고 후 TR(전송요청) → TO(전송오더) 흐름에서 재고가 어디에 "떠 있는지" 추적할 수 있다
  • 두 재고가 어긋나는 원인 3가지 이상과 각 확인 트랜잭션을 안다
  • IM/WM 재고를 대사하는 ABAP 리포트를 작성·확장할 수 있다

미리 깔고 가는 배경

MIGO로 입고 전기를 해 보고 자재문서가 무엇인지 아는 수준이면 충분합니다. ABAP 쪽은 SELECT 문과 내부 테이블 루프를 읽을 수 있어야 하고, SE38에서 리포트를 실행해 본 경험이 있으면 좋습니다. WM 트랜잭션(LT04, LT12 등)을 처음 본다면 이 글에서 흐름과 함께 익히면 됩니다.

테스트 환경

이 글의 화면·테이블 구조는 SAP ECC 6.0 EHP8(LE-WM)SAP S/4HANA 2023 온프레미스의 Stock Room Management(기능이 축소된 WM)에서 확인했습니다. 예제 조직 데이터는 전부 가상으로 만들었습니다.

  • 회사: 두레정공(가상의 자동차 부품 제조사)
  • 플랜트 4300 / 저장위치 43W1(완제품 창고동)
  • 창고번호 D40 — T320 테이블에서 4300/43W1에 배정
  • 예제 자재: DR-BRKT-1002(브레이크 브래킷), 배치 B2608A
  • 필요 권한: SE38 실행, MMBE·MB52·LS26·LX23 조회 권한

핵심 개념 — 총량 장부와 위치 장부

도서관에 비유하면 이해가 빠릅니다. IM은 "이 도서관에 이 책이 몇 권 있는가"를 기록하는 장서 목록이고, WM은 "그 책이 몇 층 어느 서가 몇 번째 칸에 꽂혀 있는가"를 기록하는 배가표입니다. 장서 목록에 3권이라 적혀 있으면 서가 어딘가에 합쳐서 3권이 있어야 정상입니다. 두 장부 합계가 다르면 책을 잃어버렸거나, 반납 처리가 중간에 끊긴 것입니다.

구분IM(재고관리)WM(창고관리)
관리 단위플랜트 + 저장위치창고번호 + 저장유형 + 저장빈(퀀트)
핵심 질문얼마나 있는가(수량·평가)정확히 어디에 있는가(위치·이동)
재고 테이블MARD(저장위치), MCHB(배치)LQUA(퀀트), LAGP(빈 마스터)
문서 테이블MKPF/MSEG(S/4는 MATDOC)LTBK/LTBP(TR), LTAK/LTAP(TO)
대표 조회MMBE, MB52LS26, LX02, LX03

두 장부를 잇는 고리가 T320(플랜트/저장위치 → 창고번호 배정)입니다. 입고 흐름을 순서대로 따라가면 이원 구조가 보입니다.

  1. MIGO에서 101 이동유형으로 입고 전기 → 자재문서가 생성되고 MARD의 재고가 즉시 증가
  2. 동시에 WM 쪽에는 입고 인터림 저장유형(일반적으로 902)에 퀀트가 생기고, 전송요청 TR(LTBK/LTBP)이 만들어짐
  3. LT04(또는 자재문서 기준 LT06)로 TR을 TO(LTAK/LTAP)로 변환 — "902에서 최종 빈으로 옮겨라"라는 작업 지시
  4. 작업자가 실물을 옮긴 뒤 LT12로 TO 확인 → 902 퀀트가 사라지고 최종 빈에 퀀트 생성
  5. 출고는 반대로: 납품문서 기준 LT03으로 피킹 TO 생성 → 출하 인터림 916 → 출고 전기 시 IM/WM 동시 감소

여기서 중요한 포인트: 2~4단계 사이에도 IM 총량과 WM 총량은 같습니다. 재고가 인터림 저장유형에 "떠 있을" 뿐입니다. MMBE와 LS26의 특정 빈 수량이 달라 보여도 총량이 맞으면 프로세스 지연이지 데이터 불일치가 아닙니다.

핵심 한 줄: IM은 총량 장부, WM은 위치 장부다. 총량은 항상 일치해야 하고, 다르면 수량 문제가 아니라 끊어진 프로세스를 찾아야 한다.

직접 해보기 — IM/WM 대사 리포트 3단계

1단계: 기본 대사 리포트. 저장위치 하나를 골라 MARD 합계와 LQUA 퀀트 합계를 자재별로 비교합니다. T320으로 창고번호를 먼저 결정하는 것이 핵심입니다.

REPORT zdr_imwm_basic.

PARAMETERS: p_werks TYPE werks_d DEFAULT '4300',
            p_lgort TYPE lgort_d DEFAULT '43W1'.

" 저장위치에 배정된 창고번호 결정
SELECT SINGLE lgnum FROM t320
  WHERE werks = @p_werks AND lgort = @p_lgort
  INTO @DATA(lv_lgnum).
IF sy-subrc <> 0.
  MESSAGE 'WM 관리 대상 저장위치가 아닙니다' TYPE 'S' DISPLAY LIKE 'E'.
  RETURN.
ENDIF.

" IM 재고: 가용 + 품질검사 + 보류
SELECT matnr, labst, insme, speme FROM mard
  WHERE werks = @p_werks AND lgort = @p_lgort
  INTO TABLE @DATA(lt_im).

" WM 재고: 인터림 포함 전체 퀀트 합계
SELECT matnr, SUM( gesme ) AS gesme FROM lqua
  WHERE lgnum = @lv_lgnum AND werks = @p_werks AND lgort = @p_lgort
  GROUP BY matnr
  INTO TABLE @DATA(lt_wm).

LOOP AT lt_im INTO DATA(ls_im).
  DATA(lv_im) = ls_im-labst + ls_im-insme + ls_im-speme.
  READ TABLE lt_wm INTO DATA(ls_wm) WITH KEY matnr = ls_im-matnr.
  DATA(lv_wm) = COND labst( WHEN sy-subrc = 0 THEN ls_wm-gesme ELSE 0 ).
  IF lv_im <> lv_wm.
    WRITE: / |{ ls_im-matnr }  IM:{ lv_im }  WM:{ lv_wm }  차이:{ lv_im - lv_wm }|.
  ENDIF.
ENDLOOP.

LQUA의 GESME는 인터림(902, 916, 999 등) 퀀트까지 포함한 총재고라서, 정상 상태라면 MARD 합계와 일치합니다. 반품(RETME)·이전중(UMLME) 재고는 단순화를 위해 뺐으니 실제 운영에서는 범위를 맞춰 주세요.

2단계: 실무 시나리오 — 배치·재고범주까지 내려가고, 미처리 문서를 함께 집계. 총량이 맞아도 재고범주(BESTQ)가 어긋나면 전기변경문서 미처리를 의심해야 하므로, 배치 단위 비교와 미결 TR/TO 건수를 같이 보여줍니다.

REPORT zdr_imwm_recon.

PARAMETERS p_lgnum TYPE lgnum DEFAULT 'D40'.

TYPES: BEGIN OF ty_diff,
         matnr  TYPE matnr,  werks TYPE werks_d,
         lgort  TYPE lgort_d, charg TYPE charg_d,
         im_qty TYPE labst,  wm_qty TYPE labst, diff TYPE labst,
       END OF ty_diff.
DATA lt_diff TYPE STANDARD TABLE OF ty_diff.

SELECT werks, lgort FROM t320
  WHERE lgnum = @p_lgnum INTO TABLE @DATA(lt_map).
IF lt_map IS INITIAL.
  MESSAGE |창고 { p_lgnum }에 배정된 저장위치가 없습니다| TYPE 'E'.
ENDIF.

" IM: 배치 재고(MCHB) 기준
SELECT matnr, werks, lgort, charg,
       clabs AS labst, cinsm AS insme, cspem AS speme
  FROM mchb FOR ALL ENTRIES IN @lt_map
  WHERE werks = @lt_map-werks AND lgort = @lt_map-lgort
  INTO TABLE @DATA(lt_im).

" WM: 배치별 퀀트 집계 (재고범주 무관 총량)
SELECT matnr, werks, lgort, charg, SUM( gesme ) AS gesme
  FROM lqua WHERE lgnum = @p_lgnum
  GROUP BY matnr, werks, lgort, charg
  INTO TABLE @DATA(lt_wm).

" 미결 문서: 원인 추적용 부가 정보
SELECT COUNT(*) FROM ltap
  WHERE lgnum = @p_lgnum AND pquit = @space INTO @DATA(lv_open_to).
SELECT COUNT(*) FROM ltbk
  WHERE lgnum = @p_lgnum AND statu <> 'E' INTO @DATA(lv_open_tr).
" 상태값 체계는 시스템 설정에 따라 다를 수 있어 도메인 확인 권장

LOOP AT lt_im INTO DATA(ls_im).
  DATA(lv_im) = ls_im-labst + ls_im-insme + ls_im-speme.
  READ TABLE lt_wm INTO DATA(ls_wm)
       WITH KEY matnr = ls_im-matnr werks = ls_im-werks
                lgort = ls_im-lgort charg = ls_im-charg.
  DATA(lv_wm) = COND labst( WHEN sy-subrc = 0 THEN ls_wm-gesme ELSE 0 ).
  IF lv_im <> lv_wm.
    APPEND VALUE #( matnr = ls_im-matnr werks = ls_im-werks
                    lgort = ls_im-lgort charg = ls_im-charg
                    im_qty = lv_im wm_qty = lv_wm
                    diff = lv_im - lv_wm ) TO lt_diff.
  ENDIF.
ENDLOOP.

WRITE: / |미결 TO 항목: { lv_open_to }건 / 미결 TR: { lv_open_tr }건|.
TRY.
    cl_salv_table=>factory( IMPORTING r_salv_table = DATA(lo_alv)
                            CHANGING  t_table      = lt_diff ).
    lo_alv->display( ).
  CATCH cx_salv_msg INTO DATA(lx_msg).
    WRITE: / |ALV 오류: { lx_msg->get_text( ) }|.  " 로그로 대체
ENDTRY.

차이 행이 나오면 미결 TO/TR 건수부터 봅니다. 미결이 많으면 프로세스 지연, 미결이 0인데 차이가 있으면 진짜 불일치입니다. WM에만 있고 IM에 없는 퀀트(반대 방향)도 잡으려면 lt_wm 기준 루프를 한 번 더 돌리면 됩니다.

3단계: 프로덕션 반영 — 권한·성능·테스트. 야간 배치(SM36)로 돌려 업무 시작 전에 차이를 알림으로 받는 구성이 일반적입니다. 세 가지를 챙깁니다. 첫째, 창고 권한 점검. 둘째, 집계는 위 코드처럼 GROUP BY로 DB에 내려서 처리(HANA 환경에서 특히 유리). 셋째, 비교 로직을 DB 접근 없는 메서드로 분리해 ABAP Unit으로 테스트할 수 있게 만듭니다.

AUTHORITY-CHECK OBJECT 'L_LGNUM' ID 'LGNUM' FIELD p_lgnum.
IF sy-subrc <> 0.
  MESSAGE |창고 { p_lgnum } 조회 권한이 없습니다| TYPE 'E'.
ENDIF.

CLASS lcl_recon DEFINITION.
  PUBLIC SECTION.
    " DB 접근이 없는 순수 비교 로직 → ABAP Unit 테스트 대상
    CLASS-METHODS compare
      IMPORTING it_im          TYPE ANY TABLE
                it_wm          TYPE ANY TABLE
                iv_tolerance   TYPE labst DEFAULT 0
      RETURNING VALUE(rt_diff) TYPE ztt_imwm_diff.
ENDCLASS.

iv_tolerance는 소수 단위 환산 오차를 걸러내는 허용치입니다. 결과가 0건이 아니면 표준 대사 트랜잭션 LX23을 같은 범위로 실행해 교차 검증하는 것을 권장합니다. LX23은 조정 전기 기능까지 있으므로 조회 전용 권한과 분리해 운영하는 편이 안전합니다.

삽질 노트 — 재고가 어긋나는 대표 상황

원인 1: 전기변경문서(Posting Change Notice) 미처리. 품질검사 합격으로 MIGO 321 이동(검사중→가용)을 IM에서 전기하면 WM에는 전기변경문서가 생깁니다. 이를 LU04/LT05로 처리하지 않으면 LQUA의 재고범주(BESTQ)는 여전히 Q로 남아, 총량은 같은데 범주별 수량이 어긋납니다. 확인: LU04 미결 목록, LX23 범주별 비교.

원인 2: 인터페이스 오류. 분산 WM이나 외부 WMS/MES 연동 환경에서 IDoc 실패로 한쪽만 전기되는 경우입니다. IM에는 자재문서가 있는데 WM 퀀트가 안 움직였다면 전형적인 패턴입니다. 확인: WE02/WE05로 실패 IDoc 조회, BD87 재처리, 이후 LX23 재대사.

원인 3: 실사 이원 처리. IM 실사 차이(MI07)와 WM 실사 차이 정리(LI20)는 별개 절차입니다. LI20으로 차이를 999 인터림에 넣고 LI21로 IM 전기까지 마쳐야 닫히는데, LI21을 빠뜨리면 999에 잔량이 쌓입니다. 확인: LX02에서 저장유형 999 잔량, LI21 미결 차이.

원인 4: 반쪽 취소. 입고 자재문서만 MIGO에서 취소하고 이미 확인된 TO를 되돌리지 않으면(또는 LT15로 미결 TO를 취소하지 않으면) 902 인터림에 음수/양수 잔량이 남습니다. 확인: LX02의 902 잔량, LT22·LB10 미결 문서.

Q1. MMBE와 LS26 수량이 다르면 무조건 사고인가요? 아닙니다. 최종 빈 수량만 보면 인터림에 떠 있는 재고 때문에 달라 보일 수 있습니다. 판단 기준은 LX23의 총량 비교입니다.

Q2. LX23에서 차이가 보이면 바로 조정 전기해도 되나요? 권장하지 않습니다. 조정은 차이를 "숨기는" 결과가 되기 쉬우므로, 미결 TO/TR·IDoc·실사 이력으로 원인을 좁힌 뒤 절차에 따라 조정하는 것이 일반적입니다.

Q3. 902에 재고가 계속 쌓여 있어요. TR은 있는데 TO를 만들지 않았거나, TO를 만들고 확인(LT12)을 안 한 상태입니다. LB10과 LT22로 미결 문서를 찾아 처리 주체를 확인하세요.

더 파볼 주제

이 구조가 손에 익으면 핸들링 유닛(HU) 관리, RF 트랜잭션(LM 계열) 기반 모바일 피킹, 저장 유닛(SU) 관리로 확장해 볼 만합니다. S/4HANA에서는 자재문서가 MATDOC 단일 테이블로 바뀌었으니 IM 쪽 조회 로직 차이도 비교해 보세요. 마이그레이션 관점에서는, 기존 LE-WM의 호환 사용 기한이 지나면서 S/4HANA에서는 Stock Room Management로 축소 운영하거나 EWM(내장/분산)으로 전환하는 흐름이 이어지고 있습니다. EWM에서도 "IM 수준 재고와 창고 내 위치 재고의 대사"라는 문제 자체는 그대로 유효합니다.

참고 링크 모음

댓글 0

아직 댓글이 없습니다.