Files
sam-react-prod/claudedocs/sales/[API-2025-12-08] pricing-api-enhancement-request.md
byeongcheolryu ded0bc2439 fix: TypeScript 타입 오류 수정 및 설정 페이지 추가
- BOMItem Omit 타입 시그니처 통일 (useTemplateManagement, SectionsTab, ItemMasterContext)
- HeadersInit → Record<string, string> 타입 변경
- Zustand useShallow 마이그레이션 (zustand/react/shallow)
- DataTable, ListPageTemplate 제네릭 타입 제약 추가
- 설정 관리 페이지 추가 (직급, 직책, 휴가정책, 근무일정, 권한)
- HR 관리 페이지 추가 (급여, 휴가)
- 단가관리 페이지 리팩토링

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 18:07:47 +09:00

9.6 KiB
Raw Blame 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 테이블 필드 추가

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로 마이그레이션

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:

{
  "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:

{
  "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:

{
  "data": {
    "data": [
      {
        "id": 1,
        "item_type_code": "PRODUCT",
        "item_id": 10,
        "price_type_code": "SALE",
        "price": 50000,
        "started_at": "2025-01-01"
      }
    ]
  }
}

요청 Response:

{
  "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:

{
  "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:

{
  "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:

{
  "finalize_reason": "2025년 1분기 단가 확정"
}

Response:

{
  "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):

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