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

279 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 입고등록 × 수입검사 연동 계획
> **작성일**: 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_completed`와 `completed` 두 상태 모두 재고 생성을 트리거한다.
### 2.4 재고 연동 조건 (`ReceivingService::update()`)
```php
$stockStatuses = ['completed', 'inspection_completed'];
$wasCompleted = in_array($oldStatus, $stockStatuses);
$isCompletingReceiving = in_array($newStatus, $stockStatuses) && !$wasCompleted;
```
| 상태 변경 | 재고 동작 |
|----------|----------|
| `receiving_pending``inspection_completed` | Stock/StockLot **생성** |
| `receiving_pending``completed` | Stock/StockLot **생성** |
| `inspection_completed``receiving_pending` | 재고 **차감** (전량) |
| `inspection_completed``inspection_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)
```typescript
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 + 검사결과 또는 검사일 있음 | **두 버튼 모두 표시** (합격 후에도 유지) |
> **핵심**: 템플릿이 있거나, 이미 검사가 수행된 경우 버튼이 표시된다.
---
## 관련 문서
- [수입검사 성적서 연동 계획](incoming-inspection-document-integration-plan.md) — 기존 상세 설계
- [수입검사 템플릿 계획](incoming-inspection-templates-plan.md) — 템플릿 생성 계획
- [채번규칙](../../rules/numbering-rules.md) — 원자재 로트번호 채번
- [입고관리 분석](receiving-management-analysis-plan.md) — 입고 시스템 현황
---
**최종 업데이트**: 2026-03-20