# 수주(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. 이벤트/후크 ### 수주 생성 시 - 변경 이력 기록 - 견적 상태 업데이트 (수주전환) ### 생산지시 생성 시 - 작업지시 자동 생성 (공정별) - 분할 상태 업데이트 ### 상태 변경 시 - 변경 이력 기록 - 알림 발송 (설정된 경우)