# 출하계획 동시 등록 컴포넌트 (v2-shipping-plan-editor) 설계서

## 개요

수주 목록에서 다건 선택 후 "출하계획" 버튼 클릭 시 모달로 열리는 출하계획 일괄 등록 화면.
기존 ScreenModal + modalScreenId 매커니즘을 활용하여, DB 기반 화면(screen_definitions)으로 구현한다.

## 핵심 기능

1. 선택된 수주를 **품목(part_code) 기준으로 그룹핑**
2. 그룹별 **5칸 집계 카드**: 총수주잔량, 총 출하계획량, 현재고, 가용재고, 생산중수량
3. 그룹별 상세 테이블: 기존 계획(기존) + 신규 입력(신규) 구분 표시
4. 출하계획량만 입력 → 확인 시 shipment_plan에 일괄 INSERT

## 테이블 관계

```
sales_order_mng (수주)
  ├─ id (PK)
  ├─ part_code (품목코드) ← 그룹핑 기준
  ├─ part_name (품명)
  ├─ order_qty (수주수량)
  ├─ ship_qty (출하수량)
  ├─ balance_qty (잔량) = order_qty - ship_qty
  ├─ partner_id (거래처)
  └─ due_date (납기일)

shipment_plan (출하계획)
  ├─ sales_order_id (FK → sales_order_mng.id)
  ├─ plan_qty (출하계획수량)
  ├─ plan_date (출하예정일)
  ├─ shipment_plan_no (자동 채번)
  └─ status (READY)

inventory_stock (재고)
  ├─ item_code (품목코드)
  └─ current_qty (현재고)

production_plan_mng (생산계획)
  ├─ item_code (품목코드)
  ├─ plan_qty (계획수량)
  ├─ completed_qty (완료수량)
  └─ status (진행중 = in_progress / planned)
```

## 집계 카드 데이터 소스

| 카드 | 계산 방법 |
|------|----------|
| 총수주잔량 | SUM(sales_order_mng.balance_qty) WHERE part_code = ? |
| 총 출하계획량 | SUM(shipment_plan.plan_qty) WHERE sales_order_id IN (해당 품목 수주들) |
| 현재고 | SUM(inventory_stock.current_qty) WHERE item_code = part_code |
| 가용재고 | 현재고 - 총 출하계획량 (기존 계획분) |
| 생산중수량 | SUM(production_plan_mng.plan_qty - completed_qty) WHERE item_code = part_code AND status IN ('in_progress', 'planned') |

## 상세 테이블 컬럼

| 컬럼 | 소스 | 편집 |
|------|------|------|
| 구분 | "기존" or "신규" | 읽기 전용 (배지) |
| 수주번호 | sales_order_mng.order_no | 읽기 전용 |
| 거래처 | sales_order_mng.partner_id (엔티티 조인) | 읽기 전용 |
| 납기일 | sales_order_mng.due_date | 읽기 전용 |
| 미출하 | sales_order_mng.balance_qty | 읽기 전용 |
| 출하계획량 | 입력값 / shipment_plan.plan_qty | **입력 가능** |

## 데이터 흐름

```
1. 수주 목록에서 체크박스 선택 → "출하계획" 버튼 클릭
2. openScreenModal 이벤트 발생 (selectedData = 선택된 수주 배열)
3. ScreenModal이 모달 화면 로드 (v2-shipping-plan-editor 컴포넌트)
4. 컴포넌트가 groupedData (= selectedData) 수신
5. part_code 기준 그룹핑
6. 백엔드 API 호출: GET /api/shipping-plan/aggregate
   → 품목별 재고, 생산중수량, 기존 출하계획 조회
7. UI 렌더링 (집계 카드 + 상세 테이블)
8. 사용자가 출하계획량 입력
9. 확인 버튼 → POST /api/shipping-plan/batch
   → shipment_plan INSERT + sales_order_mng.plan_ship_qty UPDATE
```

## 파일 구조

```
frontend/lib/registry/components/v2-shipping-plan-editor/
  ├── index.ts                              # createComponentDefinition
  ├── ShippingPlanEditorRenderer.tsx         # AutoRegisteringComponentRenderer
  ├── ShippingPlanEditorComponent.tsx        # 메인 UI 컴포넌트
  └── types.ts                              # 타입 정의

frontend/lib/api/
  └── shipping.ts                           # API 클라이언트 함수

backend-node/src/
  ├── controllers/shippingPlanController.ts  # API 핸들러
  └── routes/shippingPlanRoutes.ts          # 라우터
```

## 백엔드 API

### GET /api/shipping-plan/aggregate
품목별 집계 + 기존 출하계획 조회

Request: `?partCodes=ITEM001,SEAL-100&orderIds=172,175,178`
Response:
```json
{
  "success": true,
  "data": {
    "ITEM001": {
      "totalBalance": 1700,
      "totalPlanQty": 500,
      "currentStock": 1000,
      "availableStock": 500,
      "inProductionQty": 300,
      "existingPlans": [
        { "id": 76, "salesOrderId": 172, "planQty": 500, "planDate": "2025-12-10", "shipmentPlanNo": "SPL-..." }
      ]
    }
  }
}
```

### POST /api/shipping-plan/batch
출하계획 일괄 저장

Request:
```json
{
  "plans": [
    { "salesOrderId": 172, "planQty": 1000 },
    { "salesOrderId": 175, "planQty": 500 }
  ]
}
```

## 구현 상태

### 완료
- [x] types.ts (타입 정의)
- [x] index.ts (컴포넌트 정의)
- [x] ShippingPlanEditorRenderer.tsx (레지스트리 등록)
- [x] ShippingPlanEditorComponent.tsx (메인 UI)
- [x] frontend/lib/api/shipping.ts (API 클라이언트)
- [x] backend-node/src/controllers/shippingPlanController.ts (집계 + 일괄 저장)
- [x] backend-node/src/routes/shippingPlanRoutes.ts (라우터)
- [x] screen_definitions (screen_id: 4573, screen_code: *_SHIP_PLAN_EDITOR)
- [x] screen_layouts_v2 (layout_id: 11562)

### 연동 정보
| 항목 | 마스터(*) | 탑씰(COMPANY_7) |
|------|-----------|-----------------|
| screen_id | 4573 | 4574 |
| screen_code | *_SHIP_PLAN_EDITOR | TOPSEAL_SHIP_PLAN_EDITOR |
| layout_id | 11562 | 11563 |

탑씰 수주관리 화면(screen_id: 156)의 "출하계획" 버튼(comp_33659)이
targetScreenId: 4574로 연결되어, 체크박스 선택 → 버튼 클릭 → 모달 오픈.
선택된 수주 데이터는 `groupedData` prop으로 전달됨.

## 테스트 계획

### 1단계: 기본 기능
- [ ] 수주 선택 → 모달 열기 → groupedData 수신 확인
- [ ] part_code 기준 그룹핑 확인
- [ ] 집계 카드 데이터 표시 확인

### 2단계: CRUD
- [ ] 출하계획량 입력 → 집계 자동 재계산
- [ ] 확인 버튼 → shipment_plan INSERT 확인
- [ ] 기존 계획 "기존" 배지 표시 확인

### 3단계: 검증
- [ ] 출하계획량 > 미출하 시 에러 처리
- [ ] 멀티테넌시 (company_code) 필터링 확인
