# 수주관리 (Order Management) API 연동 계획

> **작성일**: 2025-01-08
> **목적**: 수주관리 페이지 Mock 데이터 → API 연동
> **상태**: ✅ Phase 3 완료 (100% 완료)

---

## 📍 현재 진행 상태

| 항목 | 내용 |
|------|------|
| **마지막 완료 작업** | 버그 수정 - 목록 페이지 서버 에러 해결 (3건) |
| **다음 작업** | 완료 |
| **진행률** | 3/3 Phase (100%) + 버그 수정 완료 |
| **마지막 업데이트** | 2025-01-09 |
| **커밋** | 버그 수정 커밋 완료 |

---

## 1. 개요

### 1.1 배경
수주관리 페이지는 프론트엔드 UI가 구현되어 있으나, **하드코딩된 Mock 데이터(SAMPLE_ORDERS)**를 사용 중입니다.
실제 비즈니스 운영을 위해 API 연동이 필요합니다.

### 1.2 현재 구현 상태 분석

#### API (Laravel) - ✅ Phase 1 완료
| 구성요소 | 파일 경로 | 상태 |
|---------|----------|------|
| Model | `api/app/Models/Orders/Order.php` | ✅ 존재 |
| Model | `api/app/Models/Orders/OrderItem.php` | ✅ 존재 |
| Model | `api/app/Models/Orders/OrderHistory.php` | ✅ 존재 |
| Model | `api/app/Models/Orders/OrderVersion.php` | ✅ 존재 |
| Model | `api/app/Models/Orders/OrderItemComponent.php` | ✅ 존재 |
| Controller | `api/app/Http/Controllers/Api/V1/OrderController.php` | ✅ **완료** |
| Service | `api/app/Services/OrderService.php` | ✅ **완료** |
| FormRequest | `api/app/Http/Requests/Order/*.php` | ✅ **완료** (3개) |
| Route | `/api/v1/orders` | ✅ **완료** (7개 엔드포인트) |
| Swagger | `api/app/Swagger/v1/OrderApi.php` | ✅ **완료** |

#### Frontend (React/Next.js) - ✅ Phase 2 완료
| 구성요소 | 파일 경로 | 상태 |
|---------|----------|------|
| 목록 페이지 | `react/src/app/[locale]/(protected)/sales/order-management-sales/page.tsx` | ✅ API 연동 |
| 등록 페이지 | `react/src/app/[locale]/(protected)/sales/order-management-sales/new/page.tsx` | ✅ API 연동 |
| 상세 페이지 | `react/src/app/[locale]/(protected)/sales/order-management-sales/[id]/page.tsx` | ✅ API 연동 |
| 수정 페이지 | `react/src/app/[locale]/(protected)/sales/order-management-sales/[id]/edit/page.tsx` | ✅ API 연동 |
| 생산지시 페이지 | `react/src/app/[locale]/(protected)/sales/order-management-sales/[id]/production-order/page.tsx` | ✅ 완료 |
| 등록 컴포넌트 | `react/src/components/orders/OrderRegistration.tsx` | ✅ 완료 |
| 견적선택 다이얼로그 | `react/src/components/orders/QuotationSelectDialog.tsx` | ✅ 완료 |
| 품목추가 다이얼로그 | `react/src/components/orders/ItemAddDialog.tsx` | ✅ 완료 |
| **actions.ts** | `react/src/components/orders/actions.ts` | ✅ **완료** |

### 1.3 연관관계
```
┌─────────────────┐                     ┌─────────────────┐
│     Quote       │────── quote_id ────▶│     Order       │
│    (견적서)      │                     │    (수주)        │
└─────────────────┘                     └─────────────────┘
                                               │
                                               │ sales_order_id
                                               ▼
                                       ┌─────────────────┐
                                       │   WorkOrder     │
                                       │  (작업지시)      │
                                       └─────────────────┘
```

### 1.4 변경 승인 정책

| 분류 | 예시 | 승인 |
|------|------|------|
| ✅ 즉시 가능 | 필드 추가/변경, API 엔드포인트 추가 | 불필요 |
| ⚠️ 컨펌 필요 | 테이블 구조 변경, 기존 API 수정 | **필수** |
| 🔴 금지 | 기존 Order 모델 구조 변경 | 별도 협의 |

---

## 2. 대상 범위

### Phase 1: API 개발 (✅ 완료)

| # | 작업 항목 | 상태 | 비고 |
|---|----------|:----:|------|
| 1.1 | OrderController 생성 | ✅ | CRUD + 상태관리 (7개 메서드) |
| 1.2 | OrderService 생성 | ✅ | 비즈니스 로직 (index, stats, show, store, update, destroy, updateStatus) |
| 1.3 | FormRequest 생성 | ✅ | Store, Update, UpdateStatus (3개) |
| 1.4 | API 라우트 등록 | ✅ | routes/api.php (7개 엔드포인트) |
| 1.5 | Swagger 문서 작성 | ✅ | OrderApi.php (스키마 8개) |

### Phase 2: Frontend 연동 (✅ 완료)

| # | 작업 항목 | 상태 | 비고 |
|---|----------|:----:|------|
| 2.1 | actions.ts 생성 | ✅ | API 호출 함수 + 타입 정의 + 변환 함수 |
| 2.2 | 목록 페이지 연동 | ✅ | getOrders(), getOrderStats() 연동 |
| 2.3 | 상세 페이지 연동 | ✅ | getOrderById() 연동 + 타입 오류 수정 |
| 2.4 | 등록 페이지 연동 | ✅ | createOrder() 연동 |
| 2.5 | 수정 페이지 연동 | ✅ | updateOrder() 연동 + 타입 오류 수정 |

### Phase 3: 고급 기능 (✅ 완료)

| # | 작업 항목 | 상태 | 비고 |
|---|----------|:----:|------|
| 3.1 | 견적서 → 수주 변환 | ✅ | QuotationSelectDialog + createOrderFromQuote() |
| 3.2 | 생산지시 생성 연동 | ✅ | createProductionOrder() + production-order 페이지 |
| 3.3 | 상태 흐름 관리 | ✅ | 수주확정 다이얼로그 + updateOrderStatus() |

---

## 3. API 엔드포인트 설계

### 3.1 REST API

| Method | Endpoint | 설명 | 우선순위 |
|--------|----------|------|:--------:|
| GET | `/api/v1/orders` | 수주 목록 조회 (페이징/필터) | 🔴 |
| GET | `/api/v1/orders/stats` | 수주 통계 | 🔴 |
| GET | `/api/v1/orders/{id}` | 수주 상세 조회 | 🔴 |
| POST | `/api/v1/orders` | 수주 생성 | 🔴 |
| PUT | `/api/v1/orders/{id}` | 수주 수정 | 🟡 |
| DELETE | `/api/v1/orders/{id}` | 수주 삭제 | 🟡 |
| PATCH | `/api/v1/orders/{id}/status` | 상태 변경 | 🟡 |
| POST | `/api/v1/orders/{id}/production-order` | 생산지시 생성 | 🟢 |
| POST | `/api/v1/orders/from-quote/{quoteId}` | 견적→수주 변환 | 🟢 |

### 3.2 데이터 스키마

#### Order (수주) - 기존 모델 기반
```typescript
interface Order {
  id: number;
  tenantId: number;
  quoteId?: number;           // 원본 견적
  orderNo: string;            // 수주번호 (KD-TS-YYMMDD-NN)
  orderTypeCode: 'ORDER' | 'PURCHASE';
  statusCode: 'DRAFT' | 'CONFIRMED' | 'IN_PROGRESS' | 'COMPLETED' | 'CANCELLED';
  clientId?: number;
  clientName?: string;
  siteName?: string;          // 현장명
  quantity: number;
  supplyAmount: number;
  taxAmount: number;
  totalAmount: number;
  deliveryDate?: Date;
  deliveryMethodCode?: string;
  memo?: string;
  createdBy?: number;
  updatedBy?: number;
  createdAt: Date;
  updatedAt: Date;
  // Relations
  items?: OrderItem[];
  client?: Client;
}
```

#### OrderItem (수주 품목)
```typescript
interface OrderItem {
  id: number;
  orderId: number;
  itemId?: number;
  itemName: string;
  specification?: string;
  quantity: number;
  unit?: string;
  unitPrice: number;
  supplyAmount: number;
  taxAmount: number;
  totalAmount: number;
  sortOrder: number;
}
```

---

## 4. 작업 절차

### Step 1: API 개발 (Backend)

```
1. OrderService 생성
   ├── index(): 목록 조회 (페이징, 필터링)
   ├── show(): 상세 조회
   ├── store(): 생성
   ├── update(): 수정
   ├── destroy(): 삭제
   ├── updateStatus(): 상태 변경
   ├── stats(): 통계 조회
   └── createFromQuote(): 견적→수주 변환

2. OrderController 생성
   ├── FormRequest DI
   └── ApiResponse::handle() 사용

3. FormRequest 생성
   ├── StoreOrderRequest
   └── UpdateOrderRequest

4. 라우트 등록
   └── Route::prefix('orders')->group(...)

5. Swagger 문서 작성
   └── app/Swagger/v1/OrderApi.php
```

### Step 2: Frontend 연동

```
1. actions.ts 생성
   ├── getOrders(): 목록 조회
   ├── getOrderById(): 상세 조회
   ├── createOrder(): 생성
   ├── updateOrder(): 수정
   ├── deleteOrder(): 삭제
   ├── updateOrderStatus(): 상태 변경
   └── getOrderStats(): 통계 조회

2. 페이지별 연동
   ├── page.tsx: SAMPLE_ORDERS → getOrders()
   ├── [id]/page.tsx: Mock → getOrderById()
   ├── new/page.tsx: Mock → createOrder()
   └── [id]/edit/page.tsx: Mock → updateOrder()
```

---

## 5. 의존성

### 5.1 필수 선행 작업
- **없음** - Order 모델 이미 존재, 바로 작업 가능

### 5.2 연관 기능 (선택적)
- **견적관리 (Quote)**: 견적→수주 변환 시 필요
- **거래처관리 (Client)**: 거래처 연동
- **품목관리 (Item)**: 품목 마스터 연동

### 5.3 후속 연동
- **작업지시 (WorkOrder)**: 생산지시 생성 시 `sales_order_id` 연결
- **출하관리**: 수주 완료 후 출하 처리

---

## 6. 참고 문서

- **빠른 시작**: `docs/quickstart/quick-start.md`
- **API 규칙**: `docs/standards/api-rules.md`
- **품질 체크리스트**: `docs/standards/quality-checklist.md`
- **DB 스키마**: `docs/specs/database-schema.md`
- **Swagger 가이드**: `docs/guides/swagger-guide.md`

### 참고 코드
- **작업지시 API (참고용)**: `api/app/Http/Controllers/Api/V1/WorkOrderController.php`
- **공정관리 actions.ts (참고용)**: `react/src/components/process-management/actions.ts`

---

## 7. 검증 방법

### 7.1 API 테스트
```bash
# 목록 조회
curl -X GET "http://api.sam.kr/api/v1/orders" -H "X-Api-Key: ..."

# 상세 조회
curl -X GET "http://api.sam.kr/api/v1/orders/1" -H "X-Api-Key: ..."

# 통계 조회
curl -X GET "http://api.sam.kr/api/v1/orders/stats" -H "X-Api-Key: ..."
```

### 7.2 성공 기준
| 기준 | 측정 방법 |
|------|----------|
| API CRUD 동작 | Swagger UI 테스트 통과 |
| 목록 페이지 | 실제 데이터 표시 |
| 상세 페이지 | 수주 정보 정상 표시 |
| 등록/수정 | 데이터 저장 및 조회 |
| 상태 변경 | DRAFT → CONFIRMED 전환 |

---

## 8. 자기완결성 점검

| # | 검증 항목 | 상태 | 비고 |
|---|----------|:----:|------|
| 1 | 작업 목적이 명확한가? | ✅ | Mock → API 연동 |
| 2 | 성공 기준이 정의되어 있는가? | ✅ | 섹션 7 참조 |
| 3 | 작업 범위가 구체적인가? | ✅ | Phase 1-3 단계별 정의 |
| 4 | 의존성이 명시되어 있는가? | ✅ | 선행 작업 없음 |
| 5 | 참고 파일 경로가 정확한가? | ✅ | 모든 경로 검증됨 |
| 6 | 단계별 절차가 실행 가능한가? | ✅ | Step 1-2 상세 정의 |
| 7 | 검증 방법이 명시되어 있는가? | ✅ | curl 테스트 + 기준 |
| 8 | 모호한 표현이 없는가? | ✅ | 구체적 파일/엔드포인트 명시 |

---

## 9. 버그 수정 이력

### 2025-01-09: 목록 페이지 서버 에러 수정

| # | 파일 | 문제 | 수정 내용 |
|---|------|------|----------|
| 1 | `react/.../page.tsx:120` | API 응답 데이터 구조 불일치 | `ordersResult.data` → `ordersResult.data.items` |
| 2 | `api/.../OrderService.php:113` | Quote 필드명 오류 | `quote:id,quote_no,site_name` → `quote:id,quote_number,site_name` |
| 3 | `react/.../actions.ts:384` | Quote 필드명 오류 | `apiData.quote?.quote_no` → `apiData.quote?.quote_number` |

**원인 분석:**
- `getOrders()` 함수는 `{ items: Order[], total, page, totalPages }` 구조를 반환하나, 페이지에서 `ordersResult.data`를 직접 사용하여 타입 불일치 발생
- Quote 모델의 필드명이 `quote_number`인데 `quote_no`로 잘못 참조

**영향 범위:**
- 수주 목록 페이지 접근 시 서버 에러 발생
- 견적 연동 수주의 견적번호 표시 오류

### 2025-01-09: 수주 등록 페이지 거래처 API 연동

| # | 파일 | 변경 내용 |
|---|------|----------|
| 1 | `react/.../OrderRegistration.tsx` | `SAMPLE_CLIENTS` 하드코딩 제거 |
| 2 | `react/.../OrderRegistration.tsx` | `useClientList` 훅으로 실제 API 연동 |
| 3 | `react/.../OrderRegistration.tsx` | 로딩 상태 처리 ("불러오는 중...") |
| 4 | `react/.../OrderRegistration.tsx` | 견적 선택 시 발주처 필드 비활성화 |

**개선 내용:**
- 발주처(거래처) 드롭다운이 `/api/proxy/clients` API에서 실제 데이터 조회
- 견적 선택 시 발주처가 자동 설정되고 필드 비활성화
- 로딩 중 "불러오는 중..." 플레이스홀더 표시

---

*이 문서는 독립 세션에서 바로 작업 시작 가능하도록 설계되었습니다.*