docs: [order] 재고생산관리 개발문서 + React 구현 요청서 추가

- dev/changes/20260316_stock_production_order.md: 변경이력
- plans/stock-production-react-request.md: 프론트 개발자 전달 문서
- INDEX.md 등록
This commit is contained in:
김보곤
2026-03-16 22:28:49 +09:00
parent cd3ee4e817
commit 029d4b6f02
3 changed files with 482 additions and 0 deletions

View File

@@ -234,6 +234,7 @@ DB 도메인별:
| [20260314_api_quality_improvement_deploy.md](dev/changes/20260314_api_quality_improvement_deploy.md) | API 품질 개선 배포 — 테스트 56개 + N+1 최적화 3건 (근거 문서 포함) |
| [20260315_eval_removal_safe_math_evaluator.md](dev/changes/20260315_eval_removal_safe_math_evaluator.md) | API 보안 개선 — eval() 3건 제거, SafeMathEvaluator 도입 |
| [20260316_sales_policy_changes.md](changes/20260316_sales_policy_changes.md) | 영업 정책 변경 — 수당 구조 개편 및 무료 체험 폐지 |
| [20260316_stock_production_order.md](dev/changes/20260316_stock_production_order.md) | 재고생산관리 기능 추가 (STOCK 타입, 절곡 공정 자동, 생산지시 연동) |
---
@@ -266,6 +267,7 @@ DB 도메인별:
| [vehicle-api.md](frontend/api-specs/vehicle-api.md) | 차량관리 API 명세 (20개 엔드포인트: 차량목록, 차량일지, 정비이력, 사진) |
| [stock-production-api.md](frontend/api-specs/stock-production-api.md) | 재고생산관리 API 명세 (기존 수주 API + STOCK 타입) |
| [vehicle-react-implementation.md](plans/vehicle-react-implementation.md) | 차량관리 React 구현 요청서 (3개 메뉴, 컴포넌트 구조, 타입 정의) |
| [stock-production-react-request.md](plans/stock-production-react-request.md) | 재고생산관리 React 구현 요청서 (수주 화면 단순화, API 스펙 포함) |
### frontend/integration/ — 프론트엔드 개발 가이드

View File

@@ -0,0 +1,139 @@
# 재고생산관리 기능 추가
**날짜:** 2026-03-16
**작업자:** Claude Code
---
## 변경 개요
수주 없이 재고 목적으로 생산하는 경우를 관리하는 **재고생산관리** 기능을 추가했다.
기존 `orders` 테이블을 공유하며, `order_type_code = 'STOCK'`으로 일반 수주와 구분한다.
### 설계 원칙
- **내부 오더(Internal Order)** 패턴 — 재고생산도 수주로 취급
- 기존 테이블/API 재사용 — 별도 테이블/엔드포인트 없음
- 하류 시스템(작업지시, 생산, 출하, 품질검사) 변경 없이 동작
---
## 수정된 파일
### 커밋 1: `feat: [order] 재고생산관리(STOCK) 타입 추가`
| 파일 | 변경 내용 |
|------|----------|
| `app/Models/Orders/Order.php` | `TYPE_STOCK = 'STOCK'` 상수 추가 |
| `app/Http/Requests/Order/StoreOrderRequest.php` | STOCK validation 허용, `production_reason`/`target_stock_qty` 옵션 추가 |
| `app/Http/Requests/Order/UpdateOrderRequest.php` | 동일 |
| `app/Services/OrderService.php` | STK 채번, stats `order_type` 필터, 매출 생성 스킵 |
| `app/Http/Controllers/Api/V1/OrderController.php` | stats에 `order_type` 파라미터 전달 |
### 커밋 2: `feat: [order] 재고생산 생산지시 자동 처리`
| 파일 | 변경 내용 |
|------|----------|
| `app/Services/OrderService.php` | `store()`: STOCK → `site_name='재고생산'` 자동 설정 |
| `app/Services/OrderService.php` | `createProductionOrder()`: STOCK 분기 추가 (절곡 자동, project_name, scheduled_date) |
| `lang/ko/error.php` | `bending_process_not_found` 에러 메시지 추가 |
| `lang/en/error.php` | 동일 (영문) |
---
## 상세 변경 사항
### 1. Order 모델 — 타입 상수
```php
public const TYPE_ORDER = 'ORDER'; // 수주
public const TYPE_PURCHASE = 'PURCHASE'; // 발주
public const TYPE_STOCK = 'STOCK'; // 재고생산 (신규)
```
### 2. 채번 규칙
| 타입 | 접두사 | 형식 | 예시 |
|------|--------|------|------|
| ORDER | `ORD` | `ORD{YYYYMMDD}{NNNN}` | `ORD202603160001` |
| STOCK | `STK` | `STK{YYYYMMDD}{NNNN}` | `STK202603160001` |
### 3. store() — STOCK 자동 처리
```php
if ($isStock) {
$data['site_name'] = '재고생산';
}
```
### 4. createProductionOrder() — STOCK 분기
| 항목 | ORDER (기존) | STOCK (신규) |
|------|-------------|-------------|
| 공정 매칭 | BOM item_id → process_items 매핑 | **절곡 공정 직접 할당** (BOM 스킵) |
| project_name | `order.site_name ?? client_name` | `'재고생산'` 고정 |
| scheduled_date | `order.delivery_date` | `now()` |
| 매출 생성 | `sales_recognition` 정책 적용 | **생성 안 함** |
절곡 공정 조회:
```php
$bendingProcess = Process::where('tenant_id', $tenantId)
->where('process_name', '절곡')
->where('is_active', true)
->first();
```
### 5. stats() — order_type 필터
```php
public function stats(?string $orderType = null): array
```
`GET /api/v1/orders/stats?order_type=STOCK` 으로 재고생산 전용 통계 조회 가능.
### 6. 매출 생성 스킵
```php
if ($status === Order::STATUS_CONFIRMED
&& $order->order_type_code !== Order::TYPE_STOCK // STOCK 제외
&& $order->shouldCreateSaleOnConfirm()) {
```
---
## 영향범위 분석
| 영역 | 영향 | 이유 |
|------|------|------|
| 기존 수주(ORDER) | ❌ 없음 | `$isStock` 조건 분기, else 블록에서 기존 코드 그대로 실행 |
| 기존 발주(PURCHASE) | ❌ 없음 | 동일 |
| 작업지시(WorkOrder) | ✅ 정상 동작 | `sales_order_id` FK로 연결, 절곡 공정 할당됨 |
| 생산/품질검사 | ❌ 없음 | WorkOrder 기반 하류 시스템, Order 타입 무관 |
| 출하(Shipment) | ❌ 없음 | WorkOrder 참조, Order.site_name 미사용 |
| 캘린더 | ✅ 표시됨 | `project_name='재고생산'`, `scheduled_date=now()` |
| 생산지시 목록 | ✅ 표시됨 | `site_name='재고생산'`으로 현장명 표시 |
---
## 테스트 체크리스트
- [x] STOCK 수주 생성 → `order_no` STK 접두사 확인
- [x] STOCK 수주 생성 → `site_name='재고생산'` 자동 설정 확인
- [ ] STOCK 수주 확정 → 매출 자동 생성 안 됨 확인
- [ ] STOCK 생산지시 생성 → 절곡 공정 자동 선택 확인
- [ ] STOCK 생산지시 생성 → `project_name='재고생산'` 확인
- [ ] STOCK 생산지시 생성 → `scheduled_date=today` 확인
- [ ] 기존 ORDER 수주 생산지시 → 기존 BOM 매칭 정상 동작 확인
- [ ] 생산지시 목록에서 STOCK 건 표시 확인
---
## 관련 문서
- [재고생산관리 기능 설명](../../features/sales/stock-production.md)
- [재고생산관리 API 명세](../../frontend/api-specs/stock-production-api.md)
- [프론트엔드 구현 요청서](../../frontend/requests/stock-production-react-request.md)
---
**최종 업데이트**: 2026-03-16

View File

@@ -0,0 +1,341 @@
# 재고생산관리 React 구현 요청서
> **작성일**: 2026-03-16
> **요청자**: R&D 실장
> **대상**: 프론트엔드 개발자
> **우선순위**: 🟡 중요
> **API 상태**: ✅ 구현 완료 (개발서버 배포됨)
---
## 1. 개요
수주 없이 **재고 목적으로 생산**하는 경우를 관리하는 메뉴를 추가한다.
기존 수주관리 API를 그대로 사용하며, `order_type_code = 'STOCK'`으로 구분한다.
### 1.1 구현 대상
| 메뉴 | 위치 | 설명 | 난이도 |
|------|------|------|:------:|
| **재고생산관리** | 판매관리 > 재고생산관리 | 재고생산 등록/목록/상세/수정/삭제 | **낮음** (수주 화면 복제 후 단순화) |
### 1.2 참고 문서
| 문서 | 경로 | 용도 |
|------|------|------|
| **API 명세** (필독) | `docs/frontend/api-specs/stock-production-api.md` | 전체 엔드포인트, 요청/응답 형식 |
| 기능 설명 | `docs/features/sales/stock-production.md` | 비즈니스 개념, 수주와의 관계 |
### 1.3 핵심 원칙
```
✅ 수주관리 화면을 복제한 뒤 불필요한 필드 제거
✅ API는 기존 /api/v1/orders 그대로 사용 (order_type=STOCK 필터)
✅ 생성 시 order_type_code: 'STOCK' 필수 전송
❌ 별도 API 엔드포인트 없음
❌ 거래처, 견적, 배송, 할인, 개소(Node) 관련 UI 불필요
```
---
## 2. 파일 구조 (제안)
기존 수주관리 구조를 따른다.
```
src/
├── app/[locale]/(protected)/sales/order-management-sales/
│ └── stocks/ # 재고생산관리 (신규)
│ ├── page.tsx # 목록 페이지
│ └── [id]/
│ ├── page.tsx # 상세 페이지
│ └── production-order/
│ └── page.tsx # 생산지시 생성 페이지
├── components/orders/
│ └── StockProductionRegistration.tsx # 재고생산 등록/수정 폼 (신규)
│ └── (기존 actions.ts에 함수 추가 또는 별도 stockActions.ts)
```
> **대안**: `stocks/` 대신 기존 수주관리 페이지에서 `order_type` 탭으로 분리하는 방식도 가능. 실장 판단에 따름.
---
## 3. 화면별 구현 가이드
### 3.1 재고생산 목록 페이지
**경로**: `/sales/order-management-sales/stocks`
**수주관리 목록 페이지를 복제**한 뒤 다음을 변경:
| 항목 | 수주관리 (현재) | 재고생산 (변경) |
|------|---------------|---------------|
| 페이지 제목 | 수주관리 | **재고생산관리** |
| API 호출 | `getOrders()` | `getOrders({ order_type: 'STOCK' })` |
| 통계 API | `getOrderStats()` | `getOrderStats({ order_type: 'STOCK' })``GET /api/v1/orders/stats?order_type=STOCK` |
| 표시 컬럼 | 수주번호, 거래처, 현장명, 수량, 납기, 금액... | **생산번호, 품목, 수량, 생산사유, 등록일, 상태** |
| 통계 카드 | 이번달 수주금액, 분할대기... | 전체, 등록, 확정, 진행중, 완료 (또는 간소화) |
**목록 테이블 컬럼**:
| 컬럼 | 데이터 | 비고 |
|------|--------|------|
| 번호 | 글로벌 인덱스 | |
| 생산번호 | `order_no` (STK...) | 배지 스타일 |
| 품목 | 대표 `items[0].item_name` + (외 N건) | |
| 수량 | 총 수량 | |
| 생산 사유 | `options.production_reason` | 없으면 `-` |
| 등록일 | `created_at` | YYYY-MM-DD |
| 상태 | `status_code` | 배지 (수주와 동일 색상) |
| 작업 | 상세보기, 삭제 | |
**제거할 컬럼**: 거래처, 현장명, 납기, 금액
### 3.2 재고생산 등록/수정 폼
**수주 등록 폼(`OrderRegistration.tsx`)을 복제**한 뒤 다음을 변경:
#### 제거할 섹션
```
❌ 거래처 선택 (client_id, client_name, client_contact)
❌ 현장명 (site_name) — API가 '재고생산'으로 자동 설정
❌ 견적 선택 (quote_id) / 견적에서 가져오기
❌ 배송 정보 (delivery_date, delivery_method_code)
❌ 운임비용 (options.shipping_cost_code)
❌ 수신자 정보 (options.receiver, receiver_contact, shipping_address)
❌ 할인 (discount_rate, discount_amount)
❌ 금액 계산 (supply_amount, tax_amount, total_amount)
❌ 매출 인식 (sales_recognition)
❌ 개소/구역 (OrderNode) 트리 구조
```
#### 유지할 섹션
```
✅ 생산 사유 (options.production_reason) — 텍스트 입력
✅ 목표 재고 수량 (options.target_stock_qty) — 숫자 입력
✅ 비고 (memo) — 텍스트 입력
✅ 품목 목록 (items[]) — 품목 선택 + 수량 입력
```
#### 품목 입력 테이블
| 필드 | 타입 | 필수 | 비고 |
|------|------|:----:|------|
| 품목 | 품목 선택 (ItemAddDialog) | ✅ | item_id, item_name, item_code |
| 규격 | 텍스트 | - | specification |
| 수량 | 숫자 | ✅ | quantity |
| 단위 | 텍스트 | - | unit (기본: EA) |
> **단가/금액은 불필요**하지만, API validation에서 `unit_price`가 required이므로 `0`을 전송
#### API 요청 예시
```json
{
"order_type_code": "STOCK",
"memo": "봄 시즌 대비 재고 확보",
"options": {
"production_reason": "시즌 대비",
"target_stock_qty": 500
},
"items": [
{
"item_id": 10,
"item_name": "25mm 알루미늄 블라인드",
"specification": "W1000 x H2000",
"quantity": 100,
"unit_price": 0,
"unit": "EA"
}
]
}
```
### 3.3 재고생산 상세 페이지
**수주 상세(`OrderSalesDetailView.tsx`)를 복제**한 뒤 단순화:
| 섹션 | 표시 |
|------|------|
| 생산번호 (order_no) | ✅ |
| 상태 (status_code) | ✅ 배지 |
| 생산 사유 | ✅ `options.production_reason` |
| 목표 재고 수량 | ✅ `options.target_stock_qty` |
| 비고 | ✅ `memo` |
| 품목 목록 | ✅ 테이블 (품목명, 규격, 수량) |
| 거래처/현장/납기/금액 | ❌ 제거 |
| 개소/구역 트리 | ❌ 제거 |
**액션 버튼**:
- 수정 (DRAFT 상태만)
- 삭제 (DRAFT 상태만)
- 확정 (`PATCH /api/v1/orders/{id}/status``{ "status": "CONFIRMED" }`)
- 생산지시 생성 (CONFIRMED 상태만) → 기존 생산지시 생성 페이지 재사용
### 3.4 생산지시 생성 페이지
**기존 `[id]/production-order/page.tsx`를 재사용** 가능.
STOCK 수주의 생산지시는 API가 자동 처리하므로 프론트에서 특별한 분기 불필요:
| 항목 | API 자동 처리 |
|------|-------------|
| 공정 선택 | 절곡 공정 자동 선택 (process_ids 전달 불필요) |
| 현장명 | `'재고생산'` 고정 |
| 작업예정일 | `now()` 자동 (scheduled_date 전달 불필요) |
> 단, 공정 매칭 미리보기 UI에서 STOCK 수주가 BOM 없이도 "절곡" 공정으로 표시되도록 조건 분기 필요할 수 있음.
### 3.5 생산지시 목록 — STOCK 건 표시 (기존 페이지 수정)
**경로**: `/sales/order-management-sales/production-orders/page.tsx`
STOCK 타입 재고생산의 생산지시도 이 목록에 표시된다. 변경 필요 사항:
| 컬럼 | 현재 | STOCK 건 표시 |
|------|------|-------------|
| 현장명 | `siteName` | `'재고생산'` (API가 자동 설정하므로 변경 불필요) |
| 거래처 | `clientName` | 빈 값 또는 `-` |
| 납기 | `deliveryDate` | `-` 표시 (STOCK은 delivery_date 없음) |
| 생산지시일 | `productionOrderedAt` | 정상 표시 |
**구현 방법**: API 응답에 `order_type_code`가 이미 포함됨. 프론트 types에 추가:
```typescript
// types.ts 수정
interface ApiProductionOrder {
// ... 기존 필드
order_type_code?: string; // 추가
}
// transform 함수에서
orderTypeCode: data.order_type_code || 'ORDER',
```
테이블 렌더링에서:
```typescript
// 납기 컬럼
{item.orderTypeCode === 'STOCK' ? '-' : item.deliveryDate}
// 거래처 컬럼
{item.orderTypeCode === 'STOCK' ? '-' : item.clientName}
```
---
## 4. 메뉴 등록
메뉴 위치:
```
판매관리
├── 거래처관리
├── 견적관리
├── 수주관리
├── 재고생산관리 ← 신규 (수주관리 아래)
└── 단가관리
```
> 메뉴 등록은 MNG 메뉴 동기화 기능으로 별도 처리. 프론트에서는 라우트만 구현.
---
## 5. 수주관리와의 차이 요약
```
┌─ 수주관리 ──────────────────┐ ┌─ 재고생산관리 ───────────────┐
│ │ │ │
│ 거래처 선택 │ │ 생산 사유 (텍스트) │
│ 현장명 │ │ 목표 재고 수량 │
│ 견적 연결 │ │ 비고 │
│ 배송/납기/운임 │ │ │
│ 할인/금액 계산 │ ├──────────────────────────────┤
│ 매출 인식 방식 │ │ 품목 목록 │
│ │ │ - 품목 선택 │
│ 개소/구역 트리 (OrderNode) │ │ - 수량만 입력 │
│ 품목 목록 (상세) │ │ (단가/금액/할인 불필요) │
│ - 단가, 할인, 금액 계산 │ │ (개소/구역 불필요) │
│ - floor_code, symbol_code │ │ │
│ │ └──────────────────────────────┘
└──────────────────────────────┘
```
---
## 6. API 빠른 참조
### 6.1 목록 조회
```
GET /api/v1/orders?order_type=STOCK&page=1&size=20
```
### 6.2 통계
```
GET /api/v1/orders/stats?order_type=STOCK
```
### 6.3 생성
```
POST /api/v1/orders
Content-Type: application/json
{
"order_type_code": "STOCK",
"memo": "...",
"options": { "production_reason": "...", "target_stock_qty": 500 },
"items": [{ "item_name": "...", "quantity": 100, "unit_price": 0 }]
}
```
### 6.4 상태 변경
```
PATCH /api/v1/orders/{id}/status
{ "status": "CONFIRMED" }
```
### 6.5 생산지시 생성
```
POST /api/v1/orders/{id}/production-order
{ "priority": "normal" }
```
> 공정/예정일은 API가 자동 처리 (절곡 공정, scheduled_date=now())
### 6.6 수정/삭제
```
PUT /api/v1/orders/{id} — 수정
DELETE /api/v1/orders/{id} — 삭제
```
---
## 7. 구현 체크리스트
- [ ] `stocks/page.tsx` — 재고생산 목록 페이지
- [ ] `stocks/[id]/page.tsx` — 재고생산 상세 페이지
- [ ] `StockProductionRegistration.tsx` — 등록/수정 폼 (수주 폼 단순화)
- [ ] Server Actions — `getOrders({ order_type: 'STOCK' })` 등 (기존 actions.ts 활용)
- [ ] 생산지시 목록 — STOCK 건 납기 `-` 표시, `order_type_code` 타입 추가
- [ ] 메뉴 라우트 등록
---
## 관련 문서
- [API 명세 (상세)](../frontend/api-specs/stock-production-api.md)
- [기능 설명](../features/sales/stock-production.md)
- [개발 변경이력](../dev/changes/20260316_stock_production_order.md)
---
**최종 업데이트**: 2026-03-16