"""按供应商名对上搜到的仓。无 sku_id 时靠条形码结果 + 商家全称。""" from __future__ import annotations from dataclasses import dataclass, field from typing import Any SELF_OPERATED_PREFIX = "[自营]" PACK_KEYS = ("middlePackNum", "midPackQty", "packNum", "packQty") @dataclass class CartOffer: sku_id: str vendor_raw: str vendor_norm: str stock: float | None price: float | None = None extra: dict[str, Any] = field(default_factory=dict) def normalize_supplier(raw: str) -> str: text = (raw or "").replace("\u3000", " ").strip() if text.startswith(SELF_OPERATED_PREFIX): text = text[len(SELF_OPERATED_PREFIX) :] return " ".join(text.split()) def match_offer(offers: list[CartOffer], supplier_name: str) -> CartOffer | None: target = normalize_supplier(supplier_name) if not target: return None matched = [ offer for offer in offers if normalize_supplier(offer.vendor_raw) == target or normalize_supplier(offer.vendor_norm) == target ] if not matched: return None return min(matched, key=_offer_rank) def middle_pack(offer: CartOffer) -> int | None: raw = offer.extra.get("raw") if isinstance(offer.extra.get("raw"), dict) else offer.extra if not isinstance(raw, dict): return None for key in PACK_KEYS: value = _positive_int(raw.get(key)) if value is not None: return value return None def qty_fits_pack(qty: int, pack: int | None) -> bool: if pack is None or pack <= 1: return True return qty % pack == 0 def _offer_rank(offer: CartOffer) -> tuple[int, float, float]: price = offer.price stock = offer.stock return ( 0 if price is not None else 1, float(price) if price is not None else 0.0, -float(stock) if stock is not None else 0.0, ) def _positive_int(value: object) -> int | None: if value is None or value == "": return None try: number = int(float(str(value))) except (TypeError, ValueError): return None if number <= 0: return None return number