
입고(GR) 데이터는 재고·회계·후속 문서 흐름에 직접 연결되는 핵심 기준 데이터이기 때문에,
저장 시점의 작은 오류나 처리 충돌도 운영·재무 전반에 연쇄적인 영향을 미칠 수 있다.
이에 따라 다음과 같은 구조적 리스크를 통제할 필요가 있었다.
➡ 입고 문서와 재고 테이블 간 불일치, 운영자 재확인·조정 업무 증가
➡ 데이터 충돌 발생 가능성과 운영 부서의 시스템 신뢰도 저하의 문제 발생
입고(GR) 수정 및 저장 시점을 Logical Unit of Work (LUW) 정의하고,
동시성 제어와 Commit/Rollback 규칙을 명확히 설정함으로써
항상 일관된 처리 결과가 보장되도록 설계하였다.
입고 품목은 입고문서 번호(GRNUM) + 품목 번호(GRPOS) 조합으로 식별된다.
이에 해당 키를 기준으로 ENQUEUE/DEQUEUE Lock을 적용하여
동일 데이터에 대한 동시 수정이 발생하지 않도록 통제하였다.
이를 통해 “First User Wins” 원칙을 적용하고,
데이터 충돌을 애플리케이션 레벨이 아닌 트랜잭션 레벨에서 구조적으로 차단하였다.
“동시성 문제를 해결하는 가장 확실한 방법은 ‘동시에 같은 데이터를 못 건드리게 하는 것’이라고 판단했다.
동일 데이터에 대한 동시 수정 충돌을 SAP Lock(Enqueue) 메커니즘을 통해 구조적으로 방지하였다.
입고 저장 과정에서 일부 품목 또는 일부 테이블만 반영되고 나머지가 실패하는 경우,
GR 문서·PO 상태·재고 테이블·FI 문서 간 데이터 불일치가 발생할 가능성이 있었다.
다음 네 영역을 단일 처리 단위로 묶어 관리하였다.
위 영역 중
어느 한 단계라도 오류가 발생하면 ROLLBACK WORK를 수행하고
모든 처리가 정상 완료된 경우에만 COMMIT WORK
를 실행하도록 설계하였다
즉,
“한 번의 저장은 GR·PO·재고·FI가 모두 성공했을 때만 유효하다”
라는 All-or-Nothing 트랜잭션 원칙을 적용하여,
문서·재고·회계 상태가 서로 어긋난 채로 남는 상황을 구조적으로 차단하였다.
입고 수정 저장이 시작될때,
변경 대상 품목을 기준으로 GRNUM(입고문서 번호) + GRPOS(품목 번호) 조합에 대해 Lock을 선점하도록 설계하였다.
ENQUEUE 호출foreign_lock) 시 → 즉시 저장을 중단하고 사용자에게 명확한 안내 메시지 제공“해당 품목은 현재 다른 사용자에 의해 수정 중입니다.”
이를 통해 동일 품목에 대한 동시 수정 자체를 사전에 차단하고,
사용자가 저장 실패 원인을 명확히 인지할 수 있도록 하였다.
*&---------------------------------------------------------------------*
*& Form ENQUEUE_LOCK
*&---------------------------------------------------------------------*
* Lock Enqueue
*----------------------------------------------------------------------*
FORM enqueue_lock_item .
DATA lv_numc LIKE ztspgri-grpos.
CLEAR gv_subrc.
PERFORM get_selected_rows USING go_alvb.
LOOP AT gt_selected INTO DATA(ls_selected).
CLEAR lv_numc.
lv_numc = ls_selected-row_id.
CALL FUNCTION 'ENQUEUE_EZ_ZTSPGRI'
EXPORTING
mode_ztspgri = 'E'
mandt = sy-mandt
grnum = gs_hmain-grnum
grpos = lv_numc
EXCEPTIONS
foreign_lock = 1
system_failure = 2
OTHERS = 3.
IF sy-subrc NE 0.
gv_subrc = sy-subrc.
MESSAGE i012. " 해당 품목은 현재 다른 사용자에 의해 수정 중입니다.
RETURN.
ENDIF.
ENDLOOP.
ENDFORM.
입고 저장 로직이 종료될 때,
처리 대상 품목에 대해 DEQUEUE를 호출하여 Lock을 명확히 해제하도록 설계하였다.
COMMIT WORK 이후 DEQUEUE 수행ROLLBACK WORK 수행 후 반드시 DEQUEUE 실행특히 예외 상황에서도 Lock이 해제되지 않고 남는 일이 없도록,
예외 처리 블록에서 Lock 해제를 강제하는 구조로 설계하였다.
이를 통해
하도록 하였다.
*&---------------------------------------------------------------------*
*& Form DEQUEUE_LOCK_ITEM
*&---------------------------------------------------------------------*
* Lock Dequeue
*----------------------------------------------------------------------*
FORM dequeue_lock_item.
DATA lv_numc LIKE ztspgri-grpos.
LOOP AT gt_selected INTO DATA(ls_selected).
CLEAR lv_numc.
lv_numc = ls_selected-row_id.
CALL FUNCTION 'DEQUEUE_EZ_ZTSPGRI'
EXPORTING
mode_ztspgri = 'E'
mandt = sy-mandt
grnum = gs_hmain-grnum
grpos = lv_numc.
ENDLOOP.
CLEAR gt_selected.
ENDFORM.
‘한 번의 저장 = 한 번의 Commit 또는 Rollback’ 원칙을 실제로 적용하기 위해, 사용자가 GR을 저장하는 행위 전체를 하나의 업무 트랜잭션으로 보고 GR·재고·PO·FI가 함께 움직이도록 설계했다.
→ “입고는 되었지만 PO는 예전 상태 그대로” 같은 문서 불일치가 발생하지 않도록 했다.
입고(GR)와 연계된 재고·PO·FI 전 구간에 대해,
모든 테이블에 생성자·생성일·생성시각 / 수정자·수정일·수정시각을 갖는공통 Audit 필드 구조를 표준 규칙으로 설계했다.
이를 통해,
생성/수정 이력은 단순히 “언제 바뀌었는지”를 남기는 용도를 넘어,
변경 주체(담당자)와 변경 타이밍을 기준으로 책임과 권한을 명확히 할 수 있는 근거 데이터로 활용된다.
이슈를 추적할 때, “어느 조직/사용자가 어떤 패턴으로 수정했는지”를 이력 기반으로 분석할 수 있어,
운영 정책 수립, 권한 조정, 교육 대상 선정 같은 후속 프로세스에도 직접적인 인사이트를 제공한다.