feat(dispatch): 말레이시아 재고 차감 버튼(날짜 1회성)
- 달력 다운로드 아래 '말레이시아 재고 차감' 버튼. 선택 날짜 출고를 말레이시아 재고관리에 OUT 으로 반영(movement_date=해당 날짜) · 낱개(MT/MX/MZ)=낱개 OUT, 콤보(MY-)=세트 OUT(재고관리가 BOM 분해) · _N 배수 반영, MD-(뚜껑) 제외 - 날짜당 1회만: dispatch_stock_deductions 마커로 재차감 차단(이중 출고 방지) · 마커 선점 후 반영, 콤보 BOM 누락은 사전검증으로 차단 - export.split_singles_combos, db 차감 가드 메서드, 라우터 POST /dispatch/stock-deduct - 스키마: dispatch_stock_deductions (init + 마이그레이션 dispatch_add_deductions.sql) - 이미 차감된 날짜는 버튼 비활성 + 안내 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -309,6 +309,55 @@ class DispatchStore:
|
||||
for r in rows
|
||||
]
|
||||
|
||||
# ════════════════════════════════════════════════════════════
|
||||
# 말레이시아 재고 차감 1회성 가드
|
||||
# ════════════════════════════════════════════════════════════
|
||||
def deduction_exists(self, *, dispatch_date: str) -> bool:
|
||||
with self._pool.connection() as conn:
|
||||
row = conn.execute(
|
||||
"SELECT 1 FROM dispatch_stock_deductions WHERE dispatch_date = %s",
|
||||
(dispatch_date,),
|
||||
).fetchone()
|
||||
return row is not None
|
||||
|
||||
def list_deducted_dates(self) -> list[str]:
|
||||
with self._pool.connection() as conn:
|
||||
rows = conn.execute(
|
||||
"SELECT dispatch_date FROM dispatch_stock_deductions "
|
||||
"ORDER BY dispatch_date DESC"
|
||||
).fetchall()
|
||||
out: list[str] = []
|
||||
for r in rows:
|
||||
d = r["dispatch_date"]
|
||||
out.append(d.isoformat() if isinstance(d, date) else str(d))
|
||||
return out
|
||||
|
||||
def record_deduction(
|
||||
self,
|
||||
*,
|
||||
dispatch_date: str,
|
||||
warehouse_code: str,
|
||||
single_lines: int,
|
||||
combo_lines: int,
|
||||
worker_name: str = "",
|
||||
) -> None:
|
||||
"""차감 완료 기록. 이미 있으면 충돌(재차감 차단)."""
|
||||
with self._pool.connection() as conn:
|
||||
conn.execute(
|
||||
"""
|
||||
INSERT INTO dispatch_stock_deductions
|
||||
(dispatch_date, warehouse_code, single_lines, combo_lines, worker_name)
|
||||
VALUES (%s,%s,%s,%s,%s)
|
||||
""",
|
||||
(
|
||||
dispatch_date,
|
||||
(warehouse_code or "").strip(),
|
||||
int(single_lines),
|
||||
int(combo_lines),
|
||||
(worker_name or "").lower().strip(),
|
||||
),
|
||||
)
|
||||
|
||||
def parcel_batch_id(self, *, parcel_id: int) -> int | None:
|
||||
with self._pool.connection() as conn:
|
||||
row = conn.execute(
|
||||
|
||||
Reference in New Issue
Block a user