"""쿠팡 밀크런 모듈 상수 및 공용 헬퍼. - 데이터 저장은 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), }