Files
sam-docs/dev/dev_plans/receiving-inspection-integration-plan.md

12 KiB
Raw Blame History

입고등록 × 수입검사 연동 계획

작성일: 2026-03-17 상태: 구현 완료 (Phase 1 데이터 매핑 제외) 담당: R&D실 (API) + 프론트엔드 개발자 (React)


1. 개요

1.1 목적

입고등록 시 선택한 품목에 맞는 수입검사 성적서(27종)를 자동 매칭하여 검사를 수행하고, 검사 결과를 입고 데이터에 반영한다.

1.2 현재 구현 상태

항목 상태 설명
DocumentService::resolve() 품목 ID → 수입검사 템플릿 자동 매칭
ReceivingService::getItemsWithInspectionTemplate() 입고 목록에서 has_inspection_template 플래그 반환
React checkInspectionTemplate() 입고 상세 로드 시 API 호출 → hasInspectionTemplate 상태 설정
React 수입검사 버튼 렌더링 템플릿 존재 또는 검사결과 있으면 버튼 표시
ImportInspectionInputModal 수입검사 입력 모달 (검사항목 동적 로드)
InspectionModal 수입검사 성적서 보기 모달
MNG 중복 검증 동일 category 내 같은 품목 중복 연결 방지
검사완료 → inspection_completed 상태 전이 검사완료 시 자동 상태 변경
검사완료 → 재고 자동 생성 inspection_completed 상태에서 Stock/StockLot 자동 생성
품목 ↔ 템플릿 매핑 데이터 linked_item_ids에 품목 미연결 (27종 전부)

1.3 핵심 포인트

MNG에서 수입검사 템플릿의 linked_item_ids에 품목을 연결하면, 입고 상세 화면에 수입검사 버튼이 자동으로 표시된다. 추가 코드 변경 없이 데이터 매핑만으로 동작하는 구조.


2. 시스템 구조 (기존 인프라)

2.1 템플릿 ↔ 품목 매핑

MNG 문서양식관리
├─ document_templates (27종 수입검사 양식)
│   ├─ category: '수입검사'
│   ├─ linked_item_ids: [101, 102, 103]  ← 이 품목들이 이 검사서 사용
│   └─ sections → section_items (검사항목 N개, 동적)
│
API DocumentService::resolve()
├─ 입력: { category: 'incoming_inspection', item_id: 101 }
├─ 로직: linked_item_ids에 해당 item_id가 포함된 템플릿 검색
└─ 출력: { template: {...}, is_new: true/false }

2.2 입고 → 수입검사 → 재고 흐름 (구현 완료)

입고 등록 (receiving_pending)
  ↓
입고 상세 로드 (ReceivingDetail.tsx)
  ↓ checkInspectionTemplate(itemId)
  ↓
  ├─ 템플릿 존재 또는 검사결과 있음
  │   → [수입검사하기] + [수입검사성적서 보기] 버튼 표시
  │
  └─ 템플릿 없고 검사결과 없음
      → 버튼 미표시
  ↓
[수입검사하기] → ImportInspectionInputModal
  ↓ 검사항목 입력 → 검사완료 버튼
  ↓
saveInspectionData()
  ↓ Step 1: POST /v1/documents/upsert (검사 데이터 저장)
  ↓ Step 2: PUT /v1/receivings/{id} (status → inspection_completed)
  ↓
ReceivingService::update()
  ↓ inspection_completed 감지 → 재고 반영 대상
  ↓ StockService::increaseFromReceiving()
  ↓
Stock + StockLot 자동 생성 → 재고현황에 표시

2.3 상태 흐름 (확정)

receiving_pending ──수입검사완료──→ inspection_completed ──(재고 자동 생성)
(입고대기)                         (검사완료)

receiving_pending ──입고처리──→ completed ──(재고 자동 생성)
(입고대기)                      (입고완료)

핵심: inspection_completedcompleted 두 상태 모두 재고 생성을 트리거한다.

2.4 재고 연동 조건 (ReceivingService::update())

$stockStatuses = ['completed', 'inspection_completed'];
$wasCompleted = in_array($oldStatus, $stockStatuses);
$isCompletingReceiving = in_array($newStatus, $stockStatuses) && !$wasCompleted;
상태 변경 재고 동작
receiving_pendinginspection_completed Stock/StockLot 생성
receiving_pendingcompleted Stock/StockLot 생성
inspection_completedreceiving_pending 재고 차감 (전량)
inspection_completedinspection_completed (수량 변경) 재고 조정 (차이분)

view/edit 모드에서만 버튼 표시. new 모드에서는 아직 품목이 저장되지 않았으므로 미표시.


3. 27종 검사서 ↔ 원자재 매핑 전략

3.1 매핑 방식: 1:N (한 템플릿 → 여러 품목)

수입검사 템플릿 A (SUS 판재)
  └─ linked_item_ids: [SUS304 3T, SUS304 2T, SUS316 3T, ...]

수입검사 템플릿 B (GI 도금강판)
  └─ linked_item_ids: [GI 0.5T, GI 0.8T, GI 1.0T, ...]

수입검사 템플릿 C (알루미늄)
  └─ linked_item_ids: [AL 40x40, AL 30x30, ...]

수입검사 템플릿 D (DC 모터)
  └─ linked_item_ids: [DC모터 24V, DC모터 12V, ...]

3.2 매핑 기준

기준 설명
재질 그룹 SUS, GI, AL, 플라스틱 등 동일 재질은 같은 검사항목
형태 그룹 판재, 코일, 프로파일, 봉강 등 형태별 검사 기준 차이
부품 유형 모터, 전자부품, 볼트/너트, 접착제 등

3.3 매핑 설정 방법

MNG 문서양식관리에서 각 수입검사 템플릿 수정 시 연결 품목을 설정한다.

MNG > 문서 > 문서양식관리 > [수입검사 템플릿 선택] > 수정
  → "연결 품목" 영역에서 해당 검사서를 사용할 품목 선택
  → linked_item_ids에 자동 저장

중복 방지: 동일 category(수입검사) 내에서 같은 품목을 두 템플릿에 중복 연결 불가 (MNG에서 자동 검증).

3.4 매핑 검증

매핑 완료 후 아래 체크:

✅ 모든 원자재(RM) 품목이 최소 1개 수입검사 템플릿에 연결됨
✅ 동일 품목이 2개 이상 수입검사 템플릿에 중복 연결되지 않음
✅ 템플릿 없는 품목은 입고 시 수입검사 건너뜀 (정상 동작)

4. 구현 계획

Phase 1: 데이터 매핑 (MNG 작업, 코드 변경 없음)

MNG 문서양식관리에서 27종 수입검사 템플릿의 linked_item_ids에 원자재 품목 연결.

작업 담당 비고
27종 검사서 ↔ 원자재 매핑표 작성 R&D실 재질/형태별 그룹핑
MNG에서 linked_item_ids 설정 R&D실 각 템플릿 수정
매핑 검증 (누락/중복 체크) R&D실 API로 검증

Phase 2: API 보강 (백엔드) — 완료

작업 상태 설명
DocumentService::resolve() 완료 품목 → 템플릿 매칭
DocumentService::formatTemplateForReact() 완료 클로저 스코프 수정 ($methodCodes)
ReceivingService::getItemsWithInspectionTemplate() 완료 입고 목록 has_inspection_template 플래그
Receiving::STATUSES 완료 inspection_completed 상태 추가
ReceivingService::update() 완료 inspection_completed 상태에서 재고 자동 생성
StoreReceivingRequest 완료 order_qty required 검증, inspection_completed 허용
수입검사 결과 → Receiving options 반영 완료 saveInspectionData()에서 자동 설정

Phase 3: React UI 보강 (프론트엔드) — 완료

작업 상태 설명
수입검사하기 버튼 완료 템플릿 존재 또는 검사결과 있으면 표시
ImportInspectionInputModal 완료 검사항목 동적 로드 + 입력
InspectionModal (성적서 보기) 완료 저장된 검사 성적서 조회
검사완료 → inspection_completed 상태 전이 완료 saveInspectionData() → status 자동 변경
입고 목록 삭제 기능 완료 체크박스 선택 → 삭제 버튼 표시
단위(unit) → API 전달 완료 transformFrontendToApi()에서 unit 매핑

5. 관련 API 엔드포인트

5.1 구현 완료

GET /api/v1/documents/resolve
  params: { category: 'incoming_inspection', item_id: 101 }
  → 해당 품목의 수입검사 템플릿 + 기존 문서 반환

POST /api/v1/documents/upsert
  → 검사 데이터 저장 (sections/items/field_values)

PUT /api/v1/receivings/{id}
  body: { status: 'inspection_completed', inspection_status, inspection_date, inspection_result }
  → 상태 변경 + 재고 자동 생성 (inspection_completed 시)

GET /api/v1/items/{id}
  → 응답에 has_inspection_template 포함

별도 PATCH /inspection-result 엔드포인트는 불필요. saveInspectionData()documents/upsert + receivings/{id} PUT 2단계로 처리한다.


6. 입고등록 화면 구조 (구현 완료)

수입검사 버튼 (헤더 영역)

┌──────────────────────────────────────────────────────────────────┐
│  입고 상세                         [수입검사하기] [성적서 보기]    │
│                                    ↑ hasInspectionTemplate=true   │
├──────────────────────────────────────────────────────────────────┤
│  기본 정보 (Card)                                                │
│  ...                                                             │
├──────────────────────────────────────────────────────────────────┤
│  수입검사 정보 (Card)                                             │
│  검사일: (readOnly, options에서 자동)                              │
│  검사결과: (readOnly, options에서 자동)                            │
│  업체 제공 성적서: [파일 업로드]                                    │
└──────────────────────────────────────────────────────────────────┘

버튼 렌더링 조건 (ReceivingDetail.tsx)

const showInspectionActions = hasInspectionTemplate
  || !!detail?.inspectionResult
  || !!detail?.inspectionDate;

const customHeaderActions =
  (isViewMode || isEditMode) && detail && showInspectionActions ? (
    <div className="flex gap-2">
      <Button onClick={handleInspection}>수입검사하기</Button>
      <Button onClick={handleViewInspectionReport}>수입검사성적서 보기</Button>
    </div>
  ) : undefined;
조건 결과
new 모드 버튼 미표시 (품목 미저장)
view/edit + 템플릿 없고 검사결과 없음 버튼 미표시
view/edit + hasInspectionTemplate=true 두 버튼 모두 표시
view/edit + 검사결과 또는 검사일 있음 두 버튼 모두 표시 (합격 후에도 유지)

핵심: 템플릿이 있거나, 이미 검사가 수행된 경우 버튼이 표시된다.


관련 문서


최종 업데이트: 2026-03-20