docs: [입고×수입검사] 검사완료→재고 자동 생성 설계 반영 (2026-03-20 구현 완료)
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# 입고등록 × 수입검사 연동 계획
|
||||
|
||||
> **작성일**: 2026-03-17
|
||||
> **상태**: 설계 중
|
||||
> **상태**: 구현 완료 (Phase 1 데이터 매핑 제외)
|
||||
> **담당**: R&D실 (API) + 프론트엔드 개발자 (React)
|
||||
|
||||
---
|
||||
@@ -19,12 +19,13 @@
|
||||
| `DocumentService::resolve()` | ✅ | 품목 ID → 수입검사 템플릿 자동 매칭 |
|
||||
| `ReceivingService::getItemsWithInspectionTemplate()` | ✅ | 입고 목록에서 `has_inspection_template` 플래그 반환 |
|
||||
| React `checkInspectionTemplate()` | ✅ | 입고 상세 로드 시 API 호출 → `hasInspectionTemplate` 상태 설정 |
|
||||
| React 수입검사 버튼 렌더링 | ✅ | `hasInspectionTemplate === true` → "수입검사하기" + "수입검사성적서 보기" 버튼 표시 |
|
||||
| React 수입검사 버튼 렌더링 | ✅ | 템플릿 존재 또는 검사결과 있으면 버튼 표시 |
|
||||
| `ImportInspectionInputModal` | ✅ | 수입검사 입력 모달 (검사항목 동적 로드) |
|
||||
| `InspectionModal` | ✅ | 수입검사 성적서 보기 모달 |
|
||||
| MNG 중복 검증 | ✅ | 동일 category 내 같은 품목 중복 연결 방지 |
|
||||
| 검사완료 → `inspection_completed` 상태 전이 | ✅ | 검사완료 시 자동 상태 변경 |
|
||||
| 검사완료 → 재고 자동 생성 | ✅ | `inspection_completed` 상태에서 Stock/StockLot 자동 생성 |
|
||||
| **품목 ↔ 템플릿 매핑 데이터** | ❌ | `linked_item_ids`에 품목 미연결 (27종 전부) |
|
||||
| 검사결과 → 입고 반영 API | ⚠️ | options에 저장은 되나 상태 전이 보강 필요 |
|
||||
|
||||
### 1.3 핵심 포인트
|
||||
|
||||
@@ -49,25 +50,61 @@ API DocumentService::resolve()
|
||||
└─ 출력: { template: {...}, is_new: true/false }
|
||||
```
|
||||
|
||||
### 2.2 입고 → 수입검사 흐름 (구현됨)
|
||||
### 2.2 입고 → 수입검사 → 재고 흐름 (구현 완료)
|
||||
|
||||
```
|
||||
입고 상세 로드 (ReceivingDetail.tsx)
|
||||
↓ loadData() → getReceivingById(id)
|
||||
↓ result.data.itemId 확인
|
||||
↓ checkInspectionTemplate(itemId) 호출
|
||||
↓ API: GET /api/v1/documents/resolve?category=incoming_inspection&item_id={itemId}
|
||||
입고 등록 (receiving_pending)
|
||||
↓
|
||||
├─ hasTemplate: true
|
||||
│ → hasInspectionTemplate = true
|
||||
│ → customHeaderActions 렌더링:
|
||||
│ [수입검사하기] → ImportInspectionInputModal 오픈
|
||||
│ [수입검사성적서 보기] → InspectionModal 오픈
|
||||
입고 상세 로드 (ReceivingDetail.tsx)
|
||||
↓ checkInspectionTemplate(itemId)
|
||||
↓
|
||||
├─ 템플릿 존재 또는 검사결과 있음
|
||||
│ → [수입검사하기] + [수입검사성적서 보기] 버튼 표시
|
||||
│
|
||||
└─ hasTemplate: false
|
||||
→ 버튼 미표시 (수입검사 불필요)
|
||||
└─ 템플릿 없고 검사결과 없음
|
||||
→ 버튼 미표시
|
||||
↓
|
||||
[수입검사하기] → 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 모드에서는 아직 품목이 저장되지 않았으므로 미표시.
|
||||
|
||||
---
|
||||
@@ -134,55 +171,52 @@ MNG 문서양식관리에서 27종 수입검사 템플릿의 `linked_item_ids`
|
||||
| MNG에서 linked_item_ids 설정 | R&D실 | 각 템플릿 수정 |
|
||||
| 매핑 검증 (누락/중복 체크) | R&D실 | API로 검증 |
|
||||
|
||||
### Phase 2: API 보강 (백엔드, 필요 시)
|
||||
|
||||
> Phase 1 완료 후 실제 검사 플로우를 테스트하며 부족한 부분을 보강한다.
|
||||
### Phase 2: API 보강 (백엔드) — ✅ 완료
|
||||
|
||||
| 작업 | 상태 | 설명 |
|
||||
|------|:----:|------|
|
||||
| `DocumentService::resolve()` | ✅ 완료 | 품목 → 템플릿 매칭 |
|
||||
| `DocumentService::formatTemplateForReact()` | ✅ 완료 | 클로저 스코프 수정 (`$methodCodes`) |
|
||||
| `ReceivingService::getItemsWithInspectionTemplate()` | ✅ 완료 | 입고 목록 `has_inspection_template` 플래그 |
|
||||
| `checkInspectionTemplate()` React 호출 | ✅ 완료 | 입고 상세에서 버튼 표시 제어 |
|
||||
| 수입검사 결과 → Receiving options 반영 | ⚠️ 보강 필요 | 검사완료 시 inspectionDate/Result 자동 설정 |
|
||||
| 입고 상태 전이 (inspection_pending) | ⚠️ 보강 필요 | 검사 시작 → 검사대기, 검사완료 → 입고대기 |
|
||||
| `Receiving::STATUSES` | ✅ 완료 | `inspection_completed` 상태 추가 |
|
||||
| `ReceivingService::update()` | ✅ 완료 | `inspection_completed` 상태에서 재고 자동 생성 |
|
||||
| `StoreReceivingRequest` | ✅ 완료 | `order_qty` required 검증, `inspection_completed` 허용 |
|
||||
| 수입검사 결과 → Receiving options 반영 | ✅ 완료 | `saveInspectionData()`에서 자동 설정 |
|
||||
|
||||
### Phase 3: React UI 보강 (프론트엔드, 필요 시)
|
||||
|
||||
> 버튼 표시 및 모달 연동은 이미 구현됨. 검사 결과 저장 후 입고 데이터 자동 반영 부분만 보강.
|
||||
### Phase 3: React UI 보강 (프론트엔드) — ✅ 완료
|
||||
|
||||
| 작업 | 상태 | 설명 |
|
||||
|------|:----:|------|
|
||||
| 수입검사하기 버튼 | ✅ 완료 | `hasInspectionTemplate` 기반 조건부 렌더링 |
|
||||
| 수입검사하기 버튼 | ✅ 완료 | 템플릿 존재 또는 검사결과 있으면 표시 |
|
||||
| ImportInspectionInputModal | ✅ 완료 | 검사항목 동적 로드 + 입력 |
|
||||
| InspectionModal (성적서 보기) | ✅ 완료 | 저장된 검사 성적서 조회 |
|
||||
| 검사 결과 저장 후 입고 자동 갱신 | ⚠️ 보강 필요 | `handleImportInspectionSave()` → `loadData()` 이미 호출, API 보강 후 자동 반영 |
|
||||
| 검사완료 → `inspection_completed` 상태 전이 | ✅ 완료 | `saveInspectionData()` → status 자동 변경 |
|
||||
| 입고 목록 삭제 기능 | ✅ 완료 | 체크박스 선택 → 삭제 버튼 표시 |
|
||||
| 단위(unit) → API 전달 | ✅ 완료 | `transformFrontendToApi()`에서 `unit` 매핑 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 관련 API 엔드포인트
|
||||
|
||||
### 5.1 기존 (구현 완료)
|
||||
### 5.1 구현 완료
|
||||
|
||||
```
|
||||
GET /api/v1/documents/resolve
|
||||
params: { category: 'incoming_inspection', item_id: 101 }
|
||||
→ 해당 품목의 수입검사 템플릿 + 기존 문서 반환
|
||||
|
||||
POST /api/v1/documents
|
||||
→ 검사 결과 문서 저장
|
||||
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 포함
|
||||
```
|
||||
|
||||
### 5.2 보강 필요
|
||||
|
||||
```
|
||||
PATCH /api/v1/receivings/{id}/inspection-result (신규)
|
||||
body: { inspection_date, inspection_result, document_id? }
|
||||
→ Receiving.options의 검사일/검사결과 업데이트
|
||||
→ 상태 전이 (inspection_pending → receiving_pending)
|
||||
```
|
||||
> 별도 `PATCH /inspection-result` 엔드포인트는 불필요. `saveInspectionData()`가 `documents/upsert` + `receivings/{id}` PUT 2단계로 처리한다.
|
||||
|
||||
---
|
||||
|
||||
@@ -205,11 +239,15 @@ PATCH /api/v1/receivings/{id}/inspection-result (신규)
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 버튼 렌더링 조건 (ReceivingDetail.tsx:882)
|
||||
### 버튼 렌더링 조건 (ReceivingDetail.tsx)
|
||||
|
||||
```typescript
|
||||
const showInspectionActions = hasInspectionTemplate
|
||||
|| !!detail?.inspectionResult
|
||||
|| !!detail?.inspectionDate;
|
||||
|
||||
const customHeaderActions =
|
||||
(isViewMode || isEditMode) && detail && hasInspectionTemplate ? (
|
||||
(isViewMode || isEditMode) && detail && showInspectionActions ? (
|
||||
<div className="flex gap-2">
|
||||
<Button onClick={handleInspection}>수입검사하기</Button>
|
||||
<Button onClick={handleViewInspectionReport}>수입검사성적서 보기</Button>
|
||||
@@ -220,10 +258,11 @@ const customHeaderActions =
|
||||
| 조건 | 결과 |
|
||||
|------|------|
|
||||
| new 모드 | 버튼 미표시 (품목 미저장) |
|
||||
| view/edit + `hasInspectionTemplate=false` | 버튼 미표시 |
|
||||
| view/edit + 템플릿 없고 검사결과 없음 | 버튼 미표시 |
|
||||
| view/edit + `hasInspectionTemplate=true` | **두 버튼 모두 표시** |
|
||||
| view/edit + 검사결과 또는 검사일 있음 | **두 버튼 모두 표시** (합격 후에도 유지) |
|
||||
|
||||
> **핵심**: MNG에서 해당 품목의 수입검사 템플릿에 `linked_item_ids`를 설정하면 버튼이 자동 표시된다.
|
||||
> **핵심**: 템플릿이 있거나, 이미 검사가 수행된 경우 버튼이 표시된다.
|
||||
|
||||
---
|
||||
|
||||
@@ -236,4 +275,4 @@ const customHeaderActions =
|
||||
|
||||
---
|
||||
|
||||
**최종 업데이트**: 2026-03-17
|
||||
**최종 업데이트**: 2026-03-20
|
||||
|
||||
Reference in New Issue
Block a user