Files
sam-docs/frontend/api-specs/bending-lot-api.md

14 KiB
Raw Blame History

절곡품 재고생산 LOT API 명세

작성일: 2026-03-17 상태: 개발 완료 (백엔드) 대상: React 프론트엔드 개발자


1. 개요

재고생산(STOCK) 등록 시 절곡품 전용 입력 폼을 위한 API이다. 캐스케이딩 드롭다운(품목→종류→모양&길이)으로 품목을 선택하고, LOT 번호를 자동 생성한다.

1.1 API 엔드포인트 요약

Method Path 설명
GET /api/v1/bending/code-map 드롭다운 코드 체계 전체 조회
GET /api/v1/bending/resolve-item 선택 조합 → 품목 매핑 조회
POST /api/v1/bending/generate-lot LOT 번호 생성 (일련번호 포함)
GET /api/v1/bending/material-lots 원자재 LOT 목록 (수입검사 완료 입고)
POST /api/v1/orders 재고생산 저장 (기존 API, options 확장)
PATCH /api/v1/orders/{id}/status 상태 변경 (취소→등록 복원 포함)

1.2 인증

모든 엔드포인트: X-API-KEY + Bearer Token (기존과 동일)


2. 코드맵 조회

GET /api/v1/bending/code-map

캐스케이딩 드롭다운 구성에 필요한 전체 코드 체계를 반환한다. 앱 초기 로드 시 1회 호출하여 캐싱한다.

응답

{
  "success": true,
  "data": {
    "products": [
      { "code": "R", "name": "가이드레일(벽면형)" },
      { "code": "S", "name": "가이드레일(측면형)" },
      { "code": "G", "name": "연기차단재" },
      { "code": "B", "name": "하단마감재(스크린)" },
      { "code": "T", "name": "하단마감재(철재)" },
      { "code": "L", "name": "L-Bar" },
      { "code": "C", "name": "케이스" }
    ],
    "specs": [
      { "code": "M", "name": "본체", "products": ["R", "S"] },
      { "code": "T", "name": "본체(철재)", "products": ["R", "S"] },
      { "code": "C", "name": "C형", "products": ["R", "S"] },
      { "code": "D", "name": "D형", "products": ["R", "S"] },
      { "code": "S", "name": "SUS(마감)", "products": ["R", "S", "B", "T"] },
      { "code": "U", "name": "SUS(마감)2", "products": ["S"] },
      { "code": "E", "name": "EGI(마감)", "products": ["R", "S", "B", "T"] },
      { "code": "I", "name": "화이바원단", "products": ["G"] },
      { "code": "A", "name": "스크린용", "products": ["L"] },
      { "code": "F", "name": "전면부", "products": ["C"] },
      { "code": "P", "name": "점검구", "products": ["C"] },
      { "code": "L", "name": "린텔부", "products": ["C"] },
      { "code": "B", "name": "후면코너부", "products": ["C"] }
    ],
    "lengths": {
      "smoke_barrier": [
        { "code": "53", "name": "W50 × 3000" },
        { "code": "54", "name": "W50 × 4000" },
        { "code": "83", "name": "W80 × 3000" },
        { "code": "84", "name": "W80 × 4000" }
      ],
      "general": [
        { "code": "12", "name": "1219" },
        { "code": "24", "name": "2438" },
        { "code": "30", "name": "3000" },
        { "code": "35", "name": "3500" },
        { "code": "40", "name": "4000" },
        { "code": "41", "name": "4150" },
        { "code": "42", "name": "4200" },
        { "code": "43", "name": "4300" }
      ]
    },
    "material_map": {
      "G:I": "화이바원단",
      "B:S": "SUS 1.2T",
      "B:E": "EGI 1.55T",
      "R:S": "SUS 1.2T",
      "R:M": "EGI 1.55T"
    }
  }
}

프론트엔드 사용법

// 1. 품목(prod) 선택 → 종류(spec) 필터링
const availableSpecs = codeMap.specs.filter(s => s.products.includes(selectedProd));

// 2. 품목 코드가 'G'(연기차단재)이면 smoke_barrier 길이, 아니면 general 길이
const lengths = selectedProd === 'G'
  ? codeMap.lengths.smoke_barrier
  : codeMap.lengths.general;

// 3. 원자재 재질 결정
const material = codeMap.material_map[`${selectedProd}:${selectedSpec}`];
// 예: 'G:I' → '화이바원단', 'R:S' → 'SUS 1.2T'

3. 품목 매핑 조회

GET /api/v1/bending/resolve-item?prod={prodCode}&spec={specCode}&length={lengthCode}

드롭다운에서 3개를 모두 선택했을 때 호출한다. bending_item_mappings 테이블에서 대응하는 items 레코드를 반환한다.

파라미터

파라미터 필수 설명 예시
prod O 제품 코드 R
spec O 종류 코드 M
length O 모양&길이 코드 42

성공 응답 (200)

{
  "success": true,
  "data": {
    "item_id": 15604,
    "item_code": "BD-RM-42",
    "item_name": "가이드레일(벽면) 본체 4200mm",
    "specification": "EGI 1.55T 4200mm",
    "unit": "EA"
  }
}

매핑 없음 응답 (404)

{
  "success": false,
  "message": "[404] 해당 조합에 매핑된 품목이 없습니다."
}

참고: 매핑이 없으면 품목 없이도 저장 가능하다 (item_id=null). 추후 관리자가 MNG에서 매핑을 등록하면 연결된다.


4. LOT 번호 생성

POST /api/v1/bending/generate-lot

저장 직전에 호출하여 일련번호가 확정된 LOT 번호를 받는다.

요청

{
  "prod_code": "G",
  "spec_code": "I",
  "length_code": "53",
  "reg_date": "2026-03-17"
}
필드 필수 설명
prod_code O 제품 코드
spec_code O 종류 코드
length_code O 모양&길이 코드
reg_date 등록일 (미입력 시 오늘)

응답

{
  "success": true,
  "data": {
    "lot_base": "GI6317-53",
    "lot_number": "GI6317-53-001",
    "date_code": "6317",
    "material": "화이바원단"
  }
}

LOT 번호 구조

GI6317-53-001
││││││  ││ └── 일련번호 (같은 날 같은 조합의 순번)
││││││  └┴── 모양&길이 코드
││││└┴────── 일 (17일)
│││└──────── 월 (3월)
││└───────── 년 (2026 → 6)
│└────────── 종류 (화이바원단)
└─────────── 제품 (연기차단재)

날짜코드 월 변환: 1~9 그대로, 10=A, 11=B, 12=C


5. 원자재 LOT 목록 조회

GET /api/v1/bending/material-lots?material={재질명}

수입검사가 완료된(status=completed) 입고 건 중 재질이 일치하는 LOT 목록을 반환한다. 원자재 LOT 선택 모달에서 사용한다.

파라미터

파라미터 필수 설명 예시
material 원자재 재질명 (부분 일치 검색) SUS 1.2T, EGI 1.55T, 화이바원단

응답

{
  "success": true,
  "data": [
    {
      "id": 42,
      "lot_no": "RM-20260301-001",
      "supplier_lot": "SUP-2026-A123",
      "item_name": "SUS 1.2T",
      "specification": "1219 × 2438",
      "receiving_qty": "500.00",
      "receiving_date": "2026-03-01",
      "supplier": "○○철강",
      "options": {
        "inspection_status": "적",
        "inspection_result": "합격"
      }
    }
  ]
}

프론트엔드 사용법

// 원자재 재질은 code-map의 material_map에서 결정
const material = codeMap.material_map[`${prodCode}:${specCode}`];
// 예: 'SUS 1.2T', 'EGI 1.55T', '화이바원단'

// 해당 재질의 입고 LOT 목록 조회
const lots = await fetchMaterialLots(material);
// → 모달에서 사용자가 LOT 선택

6. 취소 → 등록 복원

PATCH /api/v1/orders/{id}/status

기존 상태 변경 API를 사용한다. CANCELLED → DRAFT 전환이 허용된다.

요청

{
  "status": "DRAFT"
}

상태 전환 규칙

현재 상태 가능한 전환
DRAFT CONFIRMED, CANCELLED
CONFIRMED IN_PROGRESS, CANCELLED
IN_PROGRESS COMPLETED, CANCELLED
COMPLETED (변경 불가)
CANCELLED DRAFT (복원)

프론트엔드 구현

취소 상태일 때 "수정" 버튼 또는 "복원" 버튼을 표시하고, 클릭 시 updateStockOrderStatus(id, 'draft')를 호출한다.


7. 담당자 기본값

STOCK 주문 생성 시 options.manager_name이 비어 있으면 로그인 사용자 이름이 자동 설정된다. 프론트엔드에서 별도 처리 불필요. 저장 후 응답에서 manager_name이 채워져 돌아온다.


8. 재고생산 저장 (기존 API 확장)

POST /api/v1/orders

기존 수주 생성 API를 사용한다. options.bending_lot에 LOT 정보를 추가한다.

요청 예시

{
  "order_type_code": "STOCK",
  "memo": "절곡품 재고생산",
  "options": {
    "production_reason": "절곡품 재고생산",
    "target_stock_qty": 100,
    "bending_lot": {
      "lot_number": "GI6317-53-001",
      "prod_code": "G",
      "spec_code": "I",
      "length_code": "53",
      "raw_lot_no": "RM-20260301-001",
      "fabric_lot_no": "FB-20260215-003",
      "material": "화이바원단"
    }
  },
  "items": [
    {
      "item_id": 15604,
      "item_code": "BD-GI-53",
      "item_name": "연기차단재 화이바원단 W50×3000",
      "specification": "화이바원단",
      "quantity": 100,
      "unit": "EA",
      "unit_price": 0
    }
  ]
}

options.bending_lot 필드

필드 타입 필수 설명
lot_number string O 확정된 LOT 번호 (generate-lot API 결과)
prod_code string O 제품 코드
spec_code string O 종류 코드
length_code string O 모양&길이 코드
raw_lot_no string 원자재(철판) LOT 번호 (선택)
fabric_lot_no string 원단 LOT 번호 — 연기차단재(G)만 해당 (선택)
material string 원자재 재질명

6. 프론트엔드 구현 가이드

6.1 화면 구성 (레거시 5130 참고)

┌──────────────────────────────────────────────┐
│           절곡품 재고생산 등록                   │
├──────────────────────────────────────────────┤
│ 등록일  [날짜피커]          작성자  [자동표시]    │
│                                              │
│ 생산품 LOT  [GI6317-53-001] (자동, readonly)  │
│                                              │
│ 품목명  [Select ▾]          종류  [Select ▾]  │
│                                              │
│ 모양&길이  [Select ▾]       수량  [숫자입력]    │
│                                              │
│ 원자재(철판) LOT  [선택 버튼 → 모달]            │
│ 원단 LOT(연기차단재)  [선택 버튼 → 모달]        │
│   ↑ 품목이 G(연기차단재)일 때만 표시            │
│                                              │
│ 메모  [텍스트 입력]                             │
├──────────────────────────────────────────────┤
│              ← 목록     [저장]  [취소]         │
└──────────────────────────────────────────────┘

6.2 동작 흐름

1. 페이지 로드
   └→ GET /bending/code-map 호출 → 드롭다운 옵션 세팅

2. 품목명 Select 변경
   └→ specs 필터링: codeMap.specs.filter(s => s.products.includes(prod))
   └→ lengths 결정: prod === 'G' ? smoke_barrier : general
   └→ 종류/모양&길이 초기화

3. 종류 Select 변경
   └→ LOT 프리뷰 갱신 (프론트 날짜코드 생성)
   └→ material 결정: codeMap.material_map[`${prod}:${spec}`]

4. 모양&길이 Select 변경
   └→ GET /bending/resolve-item?prod=&spec=&length= 호출
   └→ 매핑된 품목 정보 표시 (또는 "매핑 없음" 안내)

5. 저장 버튼 클릭
   └→ POST /bending/generate-lot 호출 → lot_number 확정
   └→ POST /orders 호출 (STOCK + bending_lot + items)
   └→ 상세 페이지로 이동

6.3 LOT 프리뷰 (프론트 날짜코드 생성)

function generateDateCode(date: Date): string {
  const year = date.getFullYear() % 10;
  const month = date.getMonth() + 1;
  const day = date.getDate();
  const monthCode = month >= 10
    ? String.fromCharCode(55 + month)  // A=10, B=11, C=12
    : String(month);
  return `${year}${monthCode}${String(day).padStart(2, '0')}`;
}

// 프리뷰: GI6317-53 (일련번호 제외)
const lotPreview = `${prodCode}${specCode}${generateDateCode(regDate)}-${lengthCode}`;

6.4 원자재/원단 LOT 선택

원자재 LOT 목록은 기존 재고 API를 활용한다:

GET /api/v1/stock-lots?material={재질명}&status=available

이 엔드포인트가 아직 없으면 stocks 관련 API에서 item_name 검색으로 대체 가능하다.

6.5 상세 페이지 LOT 정보 표시

StockProductionDetail.tsx에서 order.options.bending_lot이 있으면 LOT 정보를 추가 표시한다:

const bendingLot = order.options?.bending_lot;
if (bendingLot) {
  // 생산품 LOT: GI6317-53-001
  // 원자재 LOT: RM-20260301-001
  // 원단 LOT: FB-20260215-003
  // 원자재: 화이바원단
}

7. 기존 폼과의 관계

기존 StockProductionForm.tsx를 전면 교체한다.

  • 기존: ItemAddDialog로 수동 품목 입력 (수주 폼 재활용)
  • 변경: BendingLotForm으로 캐스케이딩 드롭다운 + LOT 자동 생성

일반 재고생산 모드는 고려하지 않는다. 재고생산 = 절곡품 LOT 입력으로 통일.


관련 문서


최종 업데이트: 2026-03-17