feat(malaysia): 뚜껑(MD-) 랙 위치확인 배치 허용, 재고는 미반영
뚜껑(MD-0000~0005)을 재고조사 랙 입력 드롭다운에 노출해 창고 랙 어디에 있는지 위치만 기록할 수 있게 함. 재고에는 반영하지 않음. - store.LID_ITEMS / lid_name_map 추가 - validate_rack_code 신설(개별/세트/뚜껑 허용) → replace_rack· reposition_rack 검증에 적용. 직접 라인 입력(validate_stocktake_code)은 여전히 MD- 차단해 재고 오염 방지. - aggregate_rack 에서 MD- 집계 제외 → daily_stocktake_line 미생성. - 랙 드롭다운 목록에 LID_ITEMS 추가, 랙 보기 이름맵에 뚜껑 이름 병합. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -25,7 +25,22 @@ STOCKTAKE_STATUSES: tuple[str, ...] = ("draft", "finalized", "cancelled")
|
||||
# ── 코드 prefix ──
|
||||
INDIVIDUAL_PREFIXES: tuple[str, ...] = ("MT-", "MX-", "MZ-")
|
||||
SET_PREFIX: str = "MY-"
|
||||
BLOCKED_PREFIX: str = "MD-" # 뚜껑 — 재고관리 대상에서 제외
|
||||
BLOCKED_PREFIX: str = "MD-" # 뚜껑 — 재고(입출고/조사 집계) 대상에서 제외
|
||||
|
||||
# 뚜껑(MD-) 아이템 목록 — 재고에는 반영하지 않고 '창고 랙 위치 확인' 용도로만
|
||||
# 랙 칸에 배치할 수 있다(드롭다운 노출). malaysia_items 테이블엔 넣지 않는다.
|
||||
LID_ITEMS: tuple[dict[str, str], ...] = (
|
||||
{"item_code": "MD-0000", "item_name": "Lid XS", "kind": "lid"},
|
||||
{"item_code": "MD-0001", "item_name": "Lid S", "kind": "lid"},
|
||||
{"item_code": "MD-0002", "item_name": "Lid M", "kind": "lid"},
|
||||
{"item_code": "MD-0003", "item_name": "Lid L", "kind": "lid"},
|
||||
{"item_code": "MD-0005", "item_name": "Lid 5ℓ", "kind": "lid"},
|
||||
)
|
||||
|
||||
|
||||
def lid_name_map() -> dict[str, str]:
|
||||
"""뚜껑 코드 → 이름(랙 보기 표시용)."""
|
||||
return {it["item_code"]: it["item_name"] for it in LID_ITEMS}
|
||||
|
||||
# ── 창고 랙 레이아웃 (재고조사 랙 입력용) ──
|
||||
# 그림 고정: A/B 두 면, 각 면 3행 × 3열, 각 열은 2분할 → 면당 18칸, 총 36칸.
|
||||
@@ -87,6 +102,9 @@ def aggregate_rack(entries: Iterable[dict[str, Any]]) -> dict[str, int]:
|
||||
code = _norm(e.get("sku_code"))
|
||||
if not code:
|
||||
continue
|
||||
# 뚜껑(MD-)은 위치 확인용일 뿐 재고에 반영하지 않으므로 집계 제외.
|
||||
if is_blocked_code(code):
|
||||
continue
|
||||
try:
|
||||
upb = int(e.get("units_per_box") or 0)
|
||||
box = int(e.get("box_count") or 0)
|
||||
@@ -166,6 +184,22 @@ def validate_stocktake_code(code: str) -> str:
|
||||
return c
|
||||
|
||||
|
||||
def validate_rack_code(code: str) -> str:
|
||||
"""창고 랙 칸에 배치할 수 있는 코드 검증.
|
||||
|
||||
낱개(MT-/MX-/MZ-)·세트(MY-)에 더해 뚜껑(MD-)도 허용한다.
|
||||
뚜껑은 위치 확인 용도로만 랙에 두며, aggregate_rack 에서 집계 제외되어
|
||||
재고(daily_stocktake_line)에는 반영되지 않는다.
|
||||
"""
|
||||
c = _norm(code)
|
||||
if not c:
|
||||
raise ValueError("SKU 코드가 비어 있습니다.")
|
||||
kind = classify_code(c)
|
||||
if kind not in ("individual", "set", "blocked"):
|
||||
raise ValueError(f"허용되지 않는 코드입니다(MT-/MX-/MZ-/MY-/MD- 만 가능): {c}")
|
||||
return c
|
||||
|
||||
|
||||
def validate_bom_set_code(code: str) -> str:
|
||||
"""set_bom 의 set_code 검증 — MY- 만 허용."""
|
||||
c = _norm(code)
|
||||
|
||||
Reference in New Issue
Block a user