# 수주(Order) API 스펙

> 작성 일시: 2024-12-18
> 분석 기반: design/mes기획서_리액트 사이트

## 개요

수주 관리 API는 견적→수주→분할→생산지시→출하 프로세스를 지원합니다.

---

## 1. 수주 CRUD API

### 1.1 수주 목록 조회
```
GET /api/orders
```

**Query Parameters:**
| 파라미터 | 타입 | 필수 | 설명 |
|----------|------|------|------|
| status | string | - | 상태 필터 (수주등록, 수주확정, 생산지시완료) |
| search | string | - | 검색어 (로트번호, 견적번호, 발주처, 현장명) |
| page | number | - | 페이지 번호 (기본: 1) |
| per_page | number | - | 페이지당 개수 (기본: 20) |
| sort | string | - | 정렬 기준 (기본: -id, 최신순) |

**Response:**
```json
{
  "data": [
    {
      "id": 1,
      "order_no": "KD-SO-241218-01",
      "order_date": "2024-12-18",
      "quote_no": "QT-241215-01",
      "customer_name": "ABC건설",
      "site_name": "강남 타워",
      "status": "수주확정",
      "total_amount": 85000000,
      "due_date": "2024-12-30",
      "delivery_method": "직접배차",
      "split_count": 2,
      "production_status": "대기",
      "shipment_progress": 0
    }
  ],
  "meta": {
    "current_page": 1,
    "per_page": 20,
    "total": 100,
    "this_month_amount": 500000000,
    "split_pending_count": 5,
    "production_pending_count": 3,
    "shipment_pending_count": 8
  }
}
```

### 1.2 수주 상세 조회
```
GET /api/orders/{id}
```

**Response:**
```json
{
  "data": {
    "id": 1,
    "order_no": "KD-SO-241218-01",
    "order_date": "2024-12-18",
    "order_type": "from-quote",
    "quote_id": 10,
    "quote_no": "QT-241215-01",
    "parent_order_no": null,
    "customer_id": 5,
    "customer_name": "ABC건설",
    "credit_grade": "A",
    "site_name": "강남 타워",
    "site_code": "S-001",
    "manager": "김담당",
    "contact": "010-1234-5678",
    "due_date": "2024-12-30",
    "status": "수주확정",
    "payment_status": "미입금",
    "accounting_status": "미확인",
    "delivery_method": "직접배차",
    "delivery_address": "서울시 강남구 테헤란로 123",
    "receiver_name": "박수령",
    "receiver_phone": "010-9876-5432",
    "total_amount": 85000000,
    "note": "특이사항 없음",
    "items": [
      {
        "id": 1,
        "product_code": "SCR-001",
        "product_name": "국민방화스크린셔터",
        "category": "스크린",
        "floor": "B2",
        "location": "주차장 입구",
        "open_width": 5000,
        "open_height": 3500,
        "prod_width": 5140,
        "prod_height": 3900,
        "qty": 2,
        "unit_price": 8000000,
        "amount": 16000000,
        "production_spec": {
          "guide_rail_type": "백면형",
          "guide_rail_spec": "120-70",
          "shaft": 4,
          "capacity": 160,
          "finish": "SUS마감"
        }
      }
    ],
    "splits": [
      {
        "id": 1,
        "split_no": "KD-SO-241218-01-01",
        "split_order": 1,
        "split_type": "개소별",
        "due_date": "2024-12-25",
        "item_ids": [1, 2],
        "production_status": "작업지시",
        "shipment_status": "출고대기",
        "production_order_no": "KD-PL-241218-01",
        "total_qty": 2,
        "completed_qty": 0
      }
    ],
    "motor_spec": { ... },
    "bom_data": { ... },
    "calculated_items": [ ... ],
    "change_history": [ ... ],
    "created_at": "2024-12-18 10:00:00",
    "created_by": "admin"
  }
}
```

### 1.3 수주 등록
```
POST /api/orders
```

**Request Body:**
```json
{
  "order_date": "2024-12-18",
  "order_type": "from-quote",
  "quote_id": 10,
  "customer_id": 5,
  "customer_name": "ABC건설",
  "site_name": "강남 타워",
  "manager": "김담당",
  "contact": "010-1234-5678",
  "due_date": "2024-12-30",
  "delivery_method": "직접배차",
  "delivery_address": "서울시 강남구 테헤란로 123",
  "receiver_name": "박수령",
  "receiver_phone": "010-9876-5432",
  "note": "특이사항",
  "items": [
    {
      "product_name": "국민방화스크린셔터",
      "category": "스크린",
      "floor": "B2",
      "location": "주차장 입구",
      "open_width": 5000,
      "open_height": 3500,
      "qty": 2,
      "unit_price": 8000000,
      "guide_rail_type": "백면형",
      "guide_rail_spec": "120-70",
      "finish": "SUS마감"
    }
  ]
}
```

**자동 처리:**
- `order_no`: 자동 생성 (KD-SO-YYMMDD-##)
- `site_code`: 자동 생성
- `status`: '수주등록' 초기화
- `payment_status`: '미입금' 초기화
- `prod_width`, `prod_height`, `shaft`, `capacity`: 자동 계산
- `motor_spec`, `bom_data`: 자동 생성

**Response:** 201 Created
```json
{
  "data": {
    "id": 1,
    "order_no": "KD-SO-241218-01",
    "status": "수주등록",
    ...
  },
  "message": "수주가 등록되었습니다."
}
```

### 1.4 수주 수정
```
PUT /api/orders/{id}
```

**Request Body:** (변경할 필드만)
```json
{
  "due_date": "2024-12-31",
  "delivery_method": "상차(선불)",
  "note": "수정된 메모"
}
```

### 1.5 수주 삭제
```
DELETE /api/orders/{id}
```

### 1.6 수주 일괄 삭제
```
DELETE /api/orders
```

**Request Body:**
```json
{
  "ids": [1, 2, 3]
}
```

---

## 2. 견적→수주 전환 API

### 2.1 견적에서 수주 전환
```
POST /api/orders/from-quote/{quoteId}
```

**Request Body:**
```json
{
  "ship_date": "2024-12-25",
  "ship_date_undecided": false,
  "due_date": "2024-12-30",
  "due_date_undecided": false,
  "delivery_method": "상차",
  "freight_cost": "선불",
  "receiver_name": "박수령",
  "receiver_phone": "010-9876-5432",
  "delivery_address": "서울시 강남구",
  "delivery_address_detail": "테헤란로 123",
  "note": "수주전환 메모"
}
```

**Response:** 201 Created
```json
{
  "data": {
    "order": { ... },
    "quote": {
      "id": 10,
      "status": "수주전환",
      "converted_order_no": "KD-SO-241218-01"
    }
  },
  "message": "견적이 수주로 전환되었습니다."
}
```

### 2.2 추가분 수주 등록
```
POST /api/orders/{orderId}/additional
```

**Request Body:**
```json
{
  "items": [
    {
      "product_name": "국민방화스크린셔터",
      "floor": "1F",
      "location": "로비",
      "open_width": 4000,
      "open_height": 3000,
      "qty": 1,
      "unit_price": 7500000
    }
  ],
  "note": "추가 발주"
}
```

**자동 처리:**
- `order_no`: 원수주번호-A, B, C... 형식
- `order_type`: 'additional'
- `parent_order_no`: 원 수주번호

---

## 3. 분할 관리 API

### 3.1 분할 추가
```
POST /api/orders/{id}/splits
```

**Request Body:**
```json
{
  "split_type": "개소별",
  "due_date": "2024-12-25",
  "item_ids": [1, 2, 3]
}
```

**자동 처리:**
- `split_no`: {order_no}-{순번2자리}
- `production_status`: '작업대기'
- `shipment_status`: '출고대기'

**Response:**
```json
{
  "data": {
    "id": 1,
    "split_no": "KD-SO-241218-01-01",
    "split_order": 1,
    ...
  }
}
```

### 3.2 분할 수정
```
PUT /api/orders/{id}/splits/{splitId}
```

### 3.3 분할 삭제
```
DELETE /api/orders/{id}/splits/{splitId}
```

---

## 4. 생산지시 API

### 4.1 전체 생산지시 (분할 없이)
```
POST /api/orders/{id}/production-orders
```

**자동 처리:**
- 품목 카테고리별 작업지시 자동 분리 (스크린/슬랫/절곡)
- 작업지시번호 자동 생성 (KD-PL-YYMMDD-##)
- 공정별 팀 자동 배정

**Response:**
```json
{
  "data": {
    "work_orders": [
      {
        "id": 1,
        "work_order_no": "KD-PL-241218-01",
        "process_type": "스크린",
        "status": "작업대기",
        "assignee": "스크린팀"
      },
      {
        "id": 2,
        "work_order_no": "KD-PL-241218-02",
        "process_type": "절곡",
        "status": "작업대기",
        "assignee": "절곡팀"
      }
    ]
  },
  "message": "생산지시가 생성되었습니다."
}
```

### 4.2 분할 단위 생산지시
```
POST /api/orders/{id}/splits/{splitId}/production-orders
```

---

## 5. 문서 출력 API

### 5.1 계약서 출력
```
GET /api/orders/{id}/documents/contract
```

### 5.2 거래명세서 출력
```
GET /api/orders/{id}/documents/statement
```

**조건:**
- 입금후출고 거래처는 입금 확인 후에만 발행 가능

### 5.3 발주서 출력
```
GET /api/orders/{id}/documents/purchase-order
```

**Query Parameters:**
| 파라미터 | 타입 | 설명 |
|----------|------|------|
| format | string | 출력 형식 (pdf, html) |

---

## 6. 수주 상태 값

### 수주 상태 (status)
| 상태 | 설명 | 다음 상태 |
|------|------|-----------|
| 수주등록 | 초기 등록 | 수주확정 |
| 수주확정 | 확정 완료 | 생산중 |
| 생산중 | 생산 진행 | 생산완료 |
| 생산완료 | 생산 완료 | 출하완료 |
| 생산지시완료 | 생산지시 완료 | - |
| 출하완료 | 출하 완료 | - |

### 결제 상태 (payment_status)
| 상태 | 설명 |
|------|------|
| 미입금 | 입금 전 |
| 입금완료 | 입금 확인됨 |

### 회계 상태 (accounting_status)
| 상태 | 설명 |
|------|------|
| 미확인 | 확인 전 |
| 입금확인 | 경리 확인 완료 |

---

## 7. 데이터 모델

### Order (수주)
```
orders
├── id (PK)
├── tenant_id (FK)
├── order_no (UNIQUE)
├── order_date
├── order_type (enum: from-quote, direct, additional)
├── quote_id (FK, nullable)
├── parent_order_id (FK, nullable)
├── customer_id (FK)
├── site_id (FK)
├── manager
├── contact
├── due_date
├── status
├── payment_status
├── accounting_status
├── delivery_method
├── delivery_address
├── receiver_name
├── receiver_phone
├── total_amount
├── note
├── motor_spec (JSON)
├── bom_data (JSON)
├── created_by
├── created_at
├── updated_at
└── deleted_at
```

### OrderItem (수주 품목)
```
order_items
├── id (PK)
├── order_id (FK)
├── product_code
├── product_name
├── category (enum: 스크린, 슬랫, 절곡, 조립)
├── floor
├── location
├── open_width
├── open_height
├── prod_width (계산)
├── prod_height (계산)
├── qty
├── unit_price
├── amount
├── production_spec (JSON)
├── created_at
└── updated_at
```

### OrderSplit (수주 분할)
```
order_splits
├── id (PK)
├── order_id (FK)
├── split_no
├── split_order
├── split_type
├── due_date
├── production_status
├── shipment_status
├── production_order_no
├── total_qty
├── completed_qty
├── created_at
└── updated_at
```

### OrderSplitItem (분할 품목 연결)
```
order_split_items
├── id (PK)
├── split_id (FK)
└── item_id (FK)
```

---

## 8. 검증 규칙

### 수주 등록 시
```
customer_name: required
site_name: required
due_date: required, date, after:order_date
items: required, array, min:1
items.*.product_name: required
items.*.open_width: required, integer, min:500, max:15000
items.*.open_height: required, integer, min:500, max:10000
items.*.qty: required, integer, min:1
```

### 자동 계산 규칙
```javascript
// 제작 사이즈
prod_width = open_width + 140
prod_height = MAX(open_height + 400, 2950)

// 샤프트/용량
shaft = open_width > 6000 ? 5 : 4  // 인치
capacity = open_width > 6000 ? 300 : 160  // kg

// 금액
amount = qty * unit_price
total_amount = SUM(items.amount)
```

---

## 9. 이벤트/후크

### 수주 생성 시
- 변경 이력 기록
- 견적 상태 업데이트 (수주전환)

### 생산지시 생성 시
- 작업지시 자동 생성 (공정별)
- 분할 상태 업데이트

### 상태 변경 시
- 변경 이력 기록
- 알림 발송 (설정된 경우)