- plans/ 폴더 신규 생성 (개발 계획 임시 문서용) - hr-api-react-sync-plan.md를 specs → plans로 이동 - INDEX.md 업데이트 (폴더 구조, 워크플로우) - rules/ HR API 규칙 문서 추가 (employee, attendance, department-tree) - pricing API 요청 문서 업데이트
9.9 KiB
9.9 KiB
단가관리 API 분석 및 구현 현황
작성일: 2025-12-08 최종 업데이트: 2025-12-08 상태: ✅ 백엔드 API 구현 완료
1. 구현 현황 요약
✅ 현재 API 구조 (구현 완료)
| Method | Endpoint | 설명 | 상태 |
|---|---|---|---|
GET |
/api/v1/pricing |
목록 조회 (페이지네이션, 필터) | ✅ 완료 |
GET |
/api/v1/pricing/{id} |
단건 조회 | ✅ 완료 |
POST |
/api/v1/pricing |
등록 | ✅ 완료 |
PUT |
/api/v1/pricing/{id} |
수정 | ✅ 완료 |
DELETE |
/api/v1/pricing/{id} |
삭제 (soft delete) | ✅ 완료 |
POST |
/api/v1/pricing/{id}/finalize |
확정 | ✅ 완료 |
GET |
/api/v1/pricing/{id}/revisions |
변경이력 조회 | ✅ 완료 |
POST |
/api/v1/pricing/by-items |
품목별 단가 현황 (다건) | ✅ 완료 |
GET |
/api/v1/pricing/cost |
원가 조회 (수입검사 > 표준원가) | ✅ 완료 |
✅ 완료된 사항
- 새 테이블 구조:
prices,price_revisions테이블 생성 - 기존 테이블 마이그레이션:
price_histories→prices데이터 이관 - 모든 요청 필드: 원가 계산, 마진 관리, 리비전 관리 기능 구현
2. 테이블 스키마 (구현 완료)
2.1 prices 테이블 (신규 생성) ✅
CREATE TABLE prices (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
tenant_id BIGINT NOT NULL,
-- 품목 연결
item_type_code VARCHAR(20) NOT NULL, -- 'PRODUCT' | 'MATERIAL'
item_id BIGINT NOT NULL,
client_group_id BIGINT NULL, -- NULL=기본가
-- 원가 정보
purchase_price DECIMAL(15,4) NULL, -- 매입단가
processing_cost DECIMAL(15,4) NULL, -- 가공비
loss_rate DECIMAL(5,2) NULL, -- LOSS율 (%)
-- 판매가 정보
margin_rate DECIMAL(5,2) NULL, -- 마진율 (%)
sales_price DECIMAL(15,4) NULL, -- 판매단가
rounding_rule ENUM('round','ceil','floor') DEFAULT 'round',
rounding_unit INT DEFAULT 1, -- 1, 10, 100, 1000
-- 메타 정보
supplier VARCHAR(255) NULL,
effective_from DATE NOT NULL,
effective_to DATE NULL,
note TEXT NULL,
-- 상태 관리
status ENUM('draft','active','inactive','finalized') DEFAULT 'draft',
is_final BOOLEAN DEFAULT FALSE,
finalized_at DATETIME NULL,
finalized_by BIGINT NULL,
-- 감사 컬럼
created_by, updated_by, deleted_by, timestamps, soft_deletes
);
2.2 price_revisions 테이블 (변경 이력) ✅
CREATE TABLE price_revisions (
id BIGINT PRIMARY KEY,
tenant_id BIGINT NOT NULL,
price_id BIGINT NOT NULL,
revision_number INT NOT NULL,
changed_at DATETIME NOT NULL,
changed_by BIGINT NOT NULL,
change_reason VARCHAR(500) NULL,
before_snapshot JSON NULL,
after_snapshot JSON NOT NULL
);
2.3 기존 price_histories 테이블 처리 ✅
- ✅
prices테이블로 데이터 마이그레이션 완료 - ✅
price_histories테이블 삭제됨
3. API 엔드포인트 상세 (구현 완료)
3.1 단가 등록 POST /api/v1/pricing ✅
Request Body:
{
"item_type_code": "MATERIAL",
"item_id": 123,
"client_group_id": null,
"purchase_price": 1000,
"processing_cost": 100,
"loss_rate": 5,
"margin_rate": 20,
"rounding_rule": "round",
"rounding_unit": 10,
"supplier": "ABC상사",
"effective_from": "2025-01-01",
"effective_to": null,
"note": "2025년 1분기 단가",
"status": "active"
}
자동 처리:
sales_price자동 계산 (입력 안해도 됨)- 기존 무기한 단가의
effective_to자동 설정 - 최초 리비전 자동 생성
3.2 목록 조회 GET /api/v1/pricing ✅
Query Parameters:
| 파라미터 | 타입 | 설명 |
|---|---|---|
page |
int | 페이지 번호 |
size |
int | 페이지당 개수 (max 100) |
q |
string | 검색어 (공급업체, 비고) |
item_type_code |
string | PRODUCT / MATERIAL |
item_id |
int | 품목 ID |
client_group_id |
int/null | 고객그룹 ID |
status |
string | draft, active, inactive, finalized |
valid_at |
date | 특정 일자에 유효한 단가 |
Response:
{
"success": true,
"message": "message.fetched",
"data": {
"current_page": 1,
"data": [
{
"id": 1,
"item_type_code": "MATERIAL",
"item_id": 123,
"client_group_id": null,
"purchase_price": "1000.0000",
"processing_cost": "100.0000",
"loss_rate": "5.00",
"margin_rate": "20.00",
"sales_price": "1386.0000",
"rounding_rule": "round",
"rounding_unit": 10,
"supplier": "ABC상사",
"effective_from": "2025-01-01",
"effective_to": null,
"status": "active",
"is_final": false,
"client_group": null
}
],
"total": 1
}
}
4. 추가 API 엔드포인트 (구현 완료)
4.1 품목별 단가 현황 POST /api/v1/pricing/by-items ✅
용도: 여러 품목의 현재 유효한 단가를 한번에 조회
Request Body:
{
"items": [
{ "item_type_code": "MATERIAL", "item_id": 123 },
{ "item_type_code": "MATERIAL", "item_id": 124 },
{ "item_type_code": "PRODUCT", "item_id": 10 }
],
"client_group_id": 1,
"date": "2025-12-08"
}
조회 우선순위:
- 고객그룹별 단가 (
client_group_id지정 시) - 기본 단가 (
client_group_id = NULL)
Response:
{
"success": true,
"data": [
{
"item_type_code": "MATERIAL",
"item_id": 123,
"price": { ... },
"has_price": true
},
{
"item_type_code": "MATERIAL",
"item_id": 124,
"price": null,
"has_price": false
}
]
}
4.2 변경 이력 조회 GET /api/v1/pricing/{id}/revisions ✅
Response:
{
"success": true,
"data": {
"data": [
{
"id": 2,
"revision_number": 2,
"changed_at": "2025-12-08T11:00:00.000000Z",
"changed_by": 1,
"change_reason": "마진율 조정",
"before_snapshot": {
"purchase_price": "1000.0000",
"margin_rate": "15.00",
"sales_price": "1265.0000"
},
"after_snapshot": {
"purchase_price": "1000.0000",
"margin_rate": "20.00",
"sales_price": "1386.0000"
},
"changed_by_user": { "id": 1, "name": "홍길동" }
}
]
}
}
4.3 단가 확정 POST /api/v1/pricing/{id}/finalize ✅
동작:
is_final→truestatus→finalized- 확정 후 수정/삭제 불가
Response:
{
"success": true,
"message": "message.pricing.finalized",
"data": {
"id": 5,
"is_final": true,
"finalized_at": "2025-12-08T14:30:00.000000Z",
"finalized_by": 1,
"status": "finalized"
}
}
4.4 원가 조회 GET /api/v1/pricing/cost ✅
용도: 수입검사 입고단가 > 표준원가 우선순위로 원가 조회
Query Parameters:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
item_type_code |
string | ✅ | PRODUCT / MATERIAL |
item_id |
int | ✅ | 품목 ID |
date |
date | ❌ | 조회 기준일 (기본: 오늘) |
Response:
{
"success": true,
"data": {
"item_type_code": "MATERIAL",
"item_id": 123,
"date": "2025-12-08",
"cost_source": "receipt",
"purchase_price": 1050.00,
"receipt_id": 45,
"receipt_date": "2025-12-01",
"price_id": null
}
}
| cost_source | 설명 |
|---|---|
receipt |
수입검사 입고단가 |
standard |
표준원가 (prices 테이블) |
not_found |
단가 미등록 |
5. 비즈니스 로직
5.1 판매단가 자동 계산
총원가 = (매입단가 + 가공비) × (1 + LOSS율/100)
판매단가 = 반올림(총원가 × (1 + 마진율/100), 반올림단위, 반올림규칙)
5.2 상태 흐름
draft → active → finalized
↓
inactive
5.3 주요 검증 규칙
- 동일 품목+고객그룹+시작일 조합 중복 불가
- 확정된 단가는 수정/삭제 불가
- 마진율/LOSS율은 0~100% 범위
- 반올림단위는 1, 10, 100, 1000 중 하나
6. 프론트엔드 작업 현황
| 작업 | 상태 | 비고 |
|---|---|---|
usePricingList 훅 생성 |
⬜ 미완료 | |
| 타입 정의 | ⬜ 미완료 | |
| 단가 목록 페이지 | ⬜ 미완료 | |
| 단가 등록/수정 페이지 | ⬜ 미완료 | |
| 단가 상세 페이지 (이력 포함) | ⬜ 미완료 | |
| 품목별 단가 현황 컴포넌트 | ⬜ 미완료 |
7. 백엔드 참고 파일
컨트롤러/서비스
api/app/Http/Controllers/Api/V1/PricingController.phpapi/app/Services/PricingService.php
모델
api/app/Models/Products/Price.phpapi/app/Models/Products/PriceRevision.php
요청 클래스
api/app/Http/Requests/Pricing/PriceIndexRequest.phpapi/app/Http/Requests/Pricing/PriceStoreRequest.phpapi/app/Http/Requests/Pricing/PriceUpdateRequest.phpapi/app/Http/Requests/Pricing/PriceByItemsRequest.phpapi/app/Http/Requests/Pricing/PriceCostRequest.php
마이그레이션
api/database/migrations/2025_12_08_154633_create_prices_table.phpapi/database/migrations/2025_12_08_154634_create_price_revisions_table.phpapi/database/migrations/2025_12_08_154635_migrate_price_histories_to_prices.phpapi/database/migrations/2025_12_08_154636_drop_price_histories_table.php
라우트
api/routes/api.php(Line 368-379)
8. 관련 문서
- 단가 정책 - 상세 정책 및 계산 공식
최종 업데이트: 2025-12-08