"""1 号药城导出行 → 表 2 operate_type=2。不对加购行。""" from __future__ import annotations from dataclasses import dataclass, replace from decimal import Decimal, ROUND_HALF_UP from typing import Any YAOEX_PLATFORM_TYPE = 66 OPERATE_TYPE_PAY = 2 PUSH_NOT_SENT = 0 UNASSIGNED_OMS_ID = 0 PAID_STATUSES = {"待发货", "待收货", "已完成"} def money4(value: object) -> Decimal: return Decimal(str(value)).quantize(Decimal("0.0001"), rounding=ROUND_HALF_UP) @dataclass(frozen=True) class MallLine: order_no: str parent_order_no: str supplier_name: str status: str goods_name: str product_code: str bar_code: str unit_price: Decimal pay_price: Decimal qty: int goods_amount: Decimal order_paid: Decimal pay_order_dtl_id: str = "" @dataclass class MatchResult: rows: list[dict[str, Any]] unmatched: list[tuple[MallLine, str]] skipped_dup: list[MallLine] skipped_status: list[MallLine] def attach_detail_ids( lines: list[MallLine], details: dict[str, dict[str, Any]] ) -> list[MallLine]: remaining: dict[str, list[dict[str, Any]]] = {} for order_no, payload in details.items(): remaining[order_no] = list(payload.get("productList") or []) attached: list[MallLine] = [] for line in lines: pool = remaining.get(line.order_no) or [] idx = _find_product(pool, line) if idx is None: attached.append(line) continue product = pool.pop(idx) dtl_id = product.get("orderDetailId") attached.append(replace(line, pay_order_dtl_id="" if dtl_id is None else str(dtl_id))) return attached def match_pay_lines( lines: list[MallLine], existing_keys: set[tuple[str, str]], ) -> MatchResult: result = MatchResult(rows=[], unmatched=[], skipped_dup=[], skipped_status=[]) seen = set(existing_keys) for line in lines: if line.status not in PAID_STATUSES: result.skipped_status.append(line) continue if not line.pay_order_dtl_id: result.unmatched.append((line, "NO_DTL_ID")) continue key = (line.order_no, line.pay_order_dtl_id) if key in seen: result.skipped_dup.append(line) continue seen.add(key) result.rows.append(build_pay_row(line)) return result def build_pay_row(line: MallLine) -> dict[str, Any]: price = money4(line.pay_price) qty = int(line.qty) return { "operate_type": OPERATE_TYPE_PAY, "oms_id": UNASSIGNED_OMS_ID, "platform_type": YAOEX_PLATFORM_TYPE, "supplier_name": line.supplier_name, "bar_code": line.bar_code, "purchase_price": price, "purchase_qty": qty, "purchase_total": money4(price * qty), "status": None, "fail_reason": None, "pay_order_no": line.order_no, "pay_order_dtl_id": line.pay_order_dtl_id, "push_status": PUSH_NOT_SENT, "org_code": None, "multi_platform_flag": 0, } def _find_product(pool: list[dict[str, Any]], line: MallLine) -> int | None: for idx, product in enumerate(pool): qty = int(Decimal(str(product.get("quantity") or 0))) pay_price = money4(product.get("payPrice4") or 0) name = str(product.get("productName") or "") if qty != line.qty: continue if pay_price != money4(line.pay_price): continue if name and line.goods_name and name != line.goods_name: continue return idx return None