57f0c3426f
- 엑셀 내보내기 전체 제거: /export, /{id}/export, _build_xlsx,
_flatten_for_sheet, shipments_for_export, SHEET_COLUMNS
- 미사용 라우트 제거: /api/calendar, /api/products/search, /api/box-calc,
/{id}/status(상태변경 UI 삭제됨)
- 미사용 db 메서드 제거: deactivate_box_rule, get_box_rule, box_rule_map
- form.html window.CPG + cpg-search-pop, cupang.js CFG, 검색 드롭다운 CSS 제거
- 템플릿 미사용 statuses 컨텍스트 제거, router import 정리
- 캐시 버전 k
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
97 lines
2.7 KiB
Python
97 lines
2.7 KiB
Python
"""쿠팡 밀크런 모듈 상수 및 공용 헬퍼.
|
|
|
|
- 데이터 저장은 cupang_db(PostgreSQL) 전용이다(`db.py`).
|
|
운영 데이터가 JSON 과 DB 로 갈라지는 것을 막기 위해 JSON 폴백을 두지 않는다.
|
|
CUPANG_DB_URL 미설정 시 라우터가 "설정 필요" 안내 페이지를 보여준다.
|
|
- 이 모듈에는 DB/JSON 양쪽이 공유하는 상수와 순수 계산 헬퍼만 둔다.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import math
|
|
from typing import Any
|
|
|
|
# 출고 묶음 상태 (expense 의 STATUSES 패턴과 동일하게 한글 라벨 그대로 저장)
|
|
STATUSES: tuple[str, ...] = (
|
|
"작성중",
|
|
"출고준비",
|
|
"출고완료",
|
|
"센터입고완료",
|
|
"취소",
|
|
)
|
|
|
|
# 출고방식 기본 후보 (자유 입력 허용, 아래는 select 기본값)
|
|
SHIP_METHODS: tuple[str, ...] = ("택배", "직접배송", "화물", "파렛트", "기타")
|
|
|
|
# 초기 입고센터 seed — cupang_db_init.sql 에도 동일 목록을 INSERT 한다.
|
|
# 화면에서 추가/수정/비활성화 가능. 사용 중인 센터는 hard delete 하지 않는다.
|
|
DEFAULT_CENTERS: tuple[str, ...] = (
|
|
"대구3",
|
|
"인천32",
|
|
"이천1",
|
|
"인천42",
|
|
"인천26",
|
|
"인천16",
|
|
"인천28",
|
|
"안성8",
|
|
"천안8(RC)",
|
|
"시흥2",
|
|
"인천36",
|
|
"MGMH5",
|
|
"XRC10(RC)",
|
|
"인천14",
|
|
"경기광주5",
|
|
"경기광주3",
|
|
"XRC06(RC)",
|
|
"용인1",
|
|
"인천30",
|
|
"마장1",
|
|
"안성4",
|
|
"대구6",
|
|
"전라광주2",
|
|
"창원1",
|
|
"고양1",
|
|
"동탄1",
|
|
"이천4",
|
|
"XRC09(RC)",
|
|
)
|
|
|
|
|
|
def compute_boxes(quantity: int, units_per_box: int | None) -> dict[str, Any]:
|
|
"""수량 + 박스당 입수량으로 필요한 박스 수를 계산한다.
|
|
|
|
클라이언트 계산을 신뢰하지 않고 서버에서 이 함수로 재계산한다.
|
|
|
|
- units_per_box 가 없거나 0 이하면 "미설정" — 자동 계산하지 않는다.
|
|
- full_boxes = quantity // units_per_box
|
|
- remainder_units = quantity % units_per_box
|
|
- required_boxes = ceil(quantity / units_per_box)
|
|
"""
|
|
try:
|
|
qty = int(quantity)
|
|
except (TypeError, ValueError):
|
|
qty = 0
|
|
|
|
upb: int | None
|
|
try:
|
|
upb = int(units_per_box) if units_per_box is not None else None
|
|
except (TypeError, ValueError):
|
|
upb = None
|
|
|
|
if not upb or upb <= 0 or qty <= 0:
|
|
return {
|
|
"configured": False,
|
|
"units_per_box": upb if (upb and upb > 0) else None,
|
|
"full_boxes": None,
|
|
"remainder_units": None,
|
|
"required_boxes": None,
|
|
}
|
|
|
|
return {
|
|
"configured": True,
|
|
"units_per_box": upb,
|
|
"full_boxes": qty // upb,
|
|
"remainder_units": qty % upb,
|
|
"required_boxes": math.ceil(qty / upb),
|
|
}
|