Files
sam-docs/front/[API-2025-12-08] pricing-api-enhancement-request.md

358 lines
9.6 KiB
Markdown
Raw Normal View History

# 단가관리 API 개선 요청서
> **작성일**: 2025-12-08
> **요청자**: 프론트엔드 개발팀
> **대상**: sam-api 백엔드 팀
---
## 1. 현황 요약
### 현재 API 구조
| Endpoint | Method | 상태 |
|----------|--------|------|
| `/api/v1/pricing` | GET | 목록 조회 |
| `/api/v1/pricing/show` | GET | 단일 가격 조회 |
| `/api/v1/pricing/bulk` | POST | 일괄 가격 조회 |
| `/api/v1/pricing/upsert` | POST | 등록/수정 |
| `/api/v1/pricing/{id}` | DELETE | 삭제 |
### ✅ 이미 지원됨 (품목 정보)
- `item_type_code` (품목유형) - PriceHistory 테이블
- `item_code`, `item_name`, `specification`, `unit` - item 관계 JOIN으로 조회 가능
### ❌ 문제점 (단가 상세 정보)
- 프론트엔드 단가관리 화면에서 요구하는 **단가 계산 필드** 대부분 누락
- 현재 `price_histories` 테이블은 **단순 가격 이력**만 저장 (`price` 단일 필드)
- 프론트엔드는 **원가 계산, 마진 관리, 리비전 관리** 기능 필요
---
## 2. 테이블 스키마 변경 요청
### 2.1 `price_histories` 테이블 필드 추가
```sql
ALTER TABLE price_histories ADD COLUMN purchase_price DECIMAL(15,4) NULL COMMENT '매입단가(입고가)';
ALTER TABLE price_histories ADD COLUMN processing_cost DECIMAL(15,4) NULL COMMENT '가공비';
ALTER TABLE price_histories ADD COLUMN loss_rate DECIMAL(5,2) NULL COMMENT 'LOSS율(%)';
ALTER TABLE price_histories ADD COLUMN rounding_rule ENUM('round','ceil','floor') DEFAULT 'round' COMMENT '반올림 규칙';
ALTER TABLE price_histories ADD COLUMN rounding_unit INT DEFAULT 1 COMMENT '반올림 단위(1,10,100,1000)';
ALTER TABLE price_histories ADD COLUMN margin_rate DECIMAL(5,2) NULL COMMENT '마진율(%)';
ALTER TABLE price_histories ADD COLUMN sales_price DECIMAL(15,4) NULL COMMENT '판매단가';
ALTER TABLE price_histories ADD COLUMN supplier VARCHAR(255) NULL COMMENT '공급업체';
ALTER TABLE price_histories ADD COLUMN author VARCHAR(100) NULL COMMENT '작성자';
ALTER TABLE price_histories ADD COLUMN receive_date DATE NULL COMMENT '입고일';
ALTER TABLE price_histories ADD COLUMN note TEXT NULL COMMENT '비고';
ALTER TABLE price_histories ADD COLUMN revision_number INT DEFAULT 0 COMMENT '리비전 번호';
ALTER TABLE price_histories ADD COLUMN is_final BOOLEAN DEFAULT FALSE COMMENT '최종 확정 여부';
ALTER TABLE price_histories ADD COLUMN finalized_at DATETIME NULL COMMENT '확정일시';
ALTER TABLE price_histories ADD COLUMN finalized_by INT NULL COMMENT '확정자 ID';
ALTER TABLE price_histories ADD COLUMN status ENUM('draft','active','inactive','finalized') DEFAULT 'draft' COMMENT '상태';
```
### 2.2 기존 `price` 필드 처리 방안
**옵션 A (권장)**: `price` 필드를 `sales_price`로 마이그레이션
```sql
UPDATE price_histories SET sales_price = price WHERE price_type_code = 'SALE';
UPDATE price_histories SET purchase_price = price WHERE price_type_code = 'PURCHASE';
-- 이후 price 필드 deprecated 또는 삭제
```
**옵션 B**: `price` 필드 유지, 새 필드와 병행 사용
- 기존 로직 호환성 유지
- 점진적 마이그레이션
---
## 3. API 엔드포인트 수정 요청
### 3.1 `POST /api/v1/pricing/upsert` 수정
**현재 Request Body:**
```json
{
"item_type_code": "PRODUCT",
"item_id": 10,
"price_type_code": "SALE",
"client_group_id": 1,
"price": 50000.00,
"started_at": "2025-01-01",
"ended_at": "2025-12-31"
}
```
**요청 Request Body:**
```json
{
"item_type_code": "PRODUCT",
"item_id": 10,
"client_group_id": 1,
"purchase_price": 45000,
"processing_cost": 5000,
"loss_rate": 3.5,
"rounding_rule": "round",
"rounding_unit": 100,
"margin_rate": 20.0,
"sales_price": 60000,
"supplier": "ABC공급",
"author": "홍길동",
"receive_date": "2025-01-01",
"started_at": "2025-01-01",
"ended_at": null,
"note": "2025년 1분기 단가",
"is_revision": false,
"revision_reason": "가격 인상"
}
```
### 3.2 `GET /api/v1/pricing` 수정 (목록 조회)
**현재 Response:**
```json
{
"data": {
"data": [
{
"id": 1,
"item_type_code": "PRODUCT",
"item_id": 10,
"price_type_code": "SALE",
"price": 50000,
"started_at": "2025-01-01"
}
]
}
}
```
**요청 Response:**
```json
{
"data": {
"data": [
{
"id": 1,
"item_type_code": "PRODUCT",
"item_id": 10,
"item_code": "SCREEN-001",
"item_name": "스크린 셔터 기본형",
"specification": "표준형",
"unit": "SET",
"purchase_price": 45000,
"processing_cost": 5000,
"loss_rate": 3.5,
"margin_rate": 20.0,
"sales_price": 60000,
"started_at": "2025-01-01",
"ended_at": null,
"status": "active",
"revision_number": 1,
"is_final": false,
"supplier": "ABC공급",
"created_at": "2025-01-01 10:00:00"
}
]
}
}
```
**핵심 변경**: 품목 정보 JOIN 필요 (`item_masters` 또는 `products`/`materials` 테이블)
---
## 4. 신규 API 엔드포인트 요청
### 4.1 품목 기반 단가 현황 조회 (신규)
**용도**: 품목 마스터 기준으로 단가 등록/미등록 현황 조회
**Endpoint**: `GET /api/v1/pricing/by-items`
**Query Parameters:**
| 파라미터 | 타입 | 설명 |
|---------|------|------|
| `item_type_code` | string | 품목 유형 (FG, PT, SM, RM, CS) |
| `search` | string | 품목코드/품목명 검색 |
| `status` | string | `all`, `registered`, `not_registered` |
| `size` | int | 페이지당 항목 수 |
| `page` | int | 페이지 번호 |
**Response:**
```json
{
"data": {
"data": [
{
"item_id": 1,
"item_code": "SCREEN-001",
"item_name": "스크린 셔터 기본형",
"item_type": "FG",
"specification": "표준형",
"unit": "SET",
"pricing_id": null,
"has_pricing": false,
"purchase_price": null,
"sales_price": null,
"margin_rate": null,
"status": "not_registered"
},
{
"item_id": 2,
"item_code": "GR-001",
"item_name": "가이드레일 130×80",
"item_type": "PT",
"specification": "130×80×2438",
"unit": "EA",
"pricing_id": 5,
"has_pricing": true,
"purchase_price": 45000,
"sales_price": 60000,
"margin_rate": 20.0,
"effective_date": "2025-01-01",
"status": "active",
"revision_number": 1,
"is_final": false
}
],
"stats": {
"total_items": 100,
"registered": 45,
"not_registered": 55,
"finalized": 10
}
}
}
```
### 4.2 단가 이력 조회 (신규)
**Endpoint**: `GET /api/v1/pricing/{id}/revisions`
**Response:**
```json
{
"data": [
{
"revision_number": 2,
"revision_date": "2025-06-01",
"revision_by": "김철수",
"revision_reason": "원자재 가격 인상",
"previous_purchase_price": 40000,
"previous_sales_price": 55000,
"new_purchase_price": 45000,
"new_sales_price": 60000
},
{
"revision_number": 1,
"revision_date": "2025-01-01",
"revision_by": "홍길동",
"revision_reason": "최초 등록",
"previous_purchase_price": null,
"previous_sales_price": null,
"new_purchase_price": 40000,
"new_sales_price": 55000
}
]
}
```
### 4.3 단가 확정 (신규)
**Endpoint**: `POST /api/v1/pricing/{id}/finalize`
**Request Body:**
```json
{
"finalize_reason": "2025년 1분기 단가 확정"
}
```
**Response:**
```json
{
"data": {
"id": 5,
"is_final": true,
"finalized_at": "2025-12-08 14:30:00",
"finalized_by": 1,
"status": "finalized"
},
"message": "단가가 최종 확정되었습니다."
}
```
---
## 5. 프론트엔드 타입 참조
프론트엔드에서 사용하는 타입 정의 (`src/components/pricing/types.ts`):
```typescript
interface PricingData {
id: string;
itemId: string;
itemCode: string;
itemName: string;
itemType: string;
specification?: string;
unit: string;
// 단가 정보
effectiveDate: string; // started_at
receiveDate?: string; // receive_date
author?: string; // author
purchasePrice?: number; // purchase_price
processingCost?: number; // processing_cost
loss?: number; // loss_rate
roundingRule?: RoundingRule; // rounding_rule
roundingUnit?: number; // rounding_unit
marginRate?: number; // margin_rate
salesPrice?: number; // sales_price
supplier?: string; // supplier
note?: string; // note
// 리비전 관리
currentRevision: number; // revision_number
isFinal: boolean; // is_final
revisions?: PricingRevision[];
finalizedDate?: string; // finalized_at
finalizedBy?: string; // finalized_by
status: PricingStatus; // status
}
```
---
## 6. 우선순위
| 순위 | 항목 | 중요도 |
|------|------|--------|
| 1 | 테이블 스키마 변경 (필드 추가) | 🔴 필수 |
| 2 | `POST /pricing/upsert` 수정 | 🔴 필수 |
| 3 | `GET /pricing/by-items` 신규 | 🔴 필수 |
| 4 | `GET /pricing` 응답 확장 | 🟡 중요 |
| 5 | `GET /pricing/{id}/revisions` 신규 | 🟡 중요 |
| 6 | `POST /pricing/{id}/finalize` 신규 | 🟢 권장 |
---
## 7. 질문/협의 사항
1. **기존 price 필드 처리**: 마이그레이션 vs 병행 사용?
2. **리비전 테이블 분리**: `price_history_revisions` 별도 테이블 vs 현재 테이블 확장?
3. **품목 연결**: `item_masters` 테이블 사용 vs `products`/`materials` 각각 JOIN?
---
**연락처**: 프론트엔드 개발팀
**관련 파일**: `src/components/pricing/types.ts`