| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- """运输计划打印数据聚合(一车多卸)"""
- from __future__ import annotations
- from decimal import Decimal
- from typing import Optional
- from sqlalchemy.orm import Session
- from app.schemas.pl.plan import (
- DeliveryPrintCustomerOption,
- DeliverySlipPrintRead,
- PlanDeliveryRead,
- PlanStopProductRead,
- )
- from app.services.pl_plan_stop_service import load_plan_stops_grouped
- def _customer_key(customer_id: Optional[str], customer_name: Optional[str]) -> str:
- cid = (customer_id or "").strip()
- if cid:
- return f"id:{cid}"
- name = (customer_name or "").strip()
- if name:
- return f"name:{name}"
- return ""
- def _resolve_customer_id(customer_id: Optional[str], customer_name: Optional[str]) -> str:
- cid = (customer_id or "").strip()
- if cid:
- return cid
- return (customer_name or "").strip()
- def list_delivery_print_customers(
- deliveries: list[PlanDeliveryRead],
- ) -> list[DeliveryPrintCustomerOption]:
- grouped: dict[str, dict] = {}
- for delivery in deliveries:
- key = _customer_key(delivery.customer_id, delivery.customer_name)
- if not key:
- continue
- if key not in grouped:
- grouped[key] = {
- "customer_id": _resolve_customer_id(delivery.customer_id, delivery.customer_name),
- "customer_name": (delivery.customer_name or "").strip() or "—",
- "delivery_count": 0,
- "min_seq": delivery.seq or 9999,
- }
- grouped[key]["delivery_count"] += 1
- grouped[key]["min_seq"] = min(grouped[key]["min_seq"], delivery.seq or 9999)
- rows = sorted(grouped.values(), key=lambda item: (item["min_seq"], item["customer_name"]))
- return [
- DeliveryPrintCustomerOption(
- customer_id=item["customer_id"],
- customer_name=item["customer_name"],
- delivery_count=item["delivery_count"],
- )
- for item in rows
- ]
- def _delivery_matches_customer(
- delivery: PlanDeliveryRead,
- customer_id: str,
- ) -> bool:
- target = (customer_id or "").strip()
- if not target:
- return False
- delivery_id = (delivery.customer_id or "").strip()
- if delivery_id and delivery_id == target:
- return True
- delivery_name = (delivery.customer_name or "").strip()
- return not delivery_id and delivery_name == target
- def _merge_stop_products(products: list[PlanStopProductRead]) -> list[PlanStopProductRead]:
- merged: dict[str, PlanStopProductRead] = {}
- order: list[str] = []
- for product in products:
- key = (product.product_id or "").strip() or product.id
- if key not in merged:
- merged[key] = product.model_copy(deep=True)
- order.append(key)
- continue
- existing = merged[key]
- for field in ("plan_qty", "outbound_qty", "inbound_qty"):
- left = getattr(existing, field, None)
- right = getattr(product, field, None)
- if left is None and right is None:
- continue
- total = (left or Decimal("0")) + (right or Decimal("0"))
- setattr(existing, field, total)
- if not (existing.remark or "").strip() and (product.remark or "").strip():
- existing.remark = product.remark
- return [merged[key] for key in order]
- def build_delivery_slip_print(
- db: Session,
- *,
- tenant_no: str,
- plan_id: str,
- plan_no: str,
- plan_date: Optional[str],
- customer_id: str,
- ) -> DeliverySlipPrintRead:
- stops = load_plan_stops_grouped(db, tenant_no, [plan_id]).get(plan_id)
- if not stops:
- raise ValueError("计划未配置送货段")
- _load, deliveries = stops
- if not deliveries:
- raise ValueError("计划未配置送货段")
- matched = [item for item in deliveries if _delivery_matches_customer(item, customer_id)]
- if not matched:
- raise ValueError("未找到匹配的送货客户")
- matched.sort(key=lambda item: (item.seq or 9999, item.create_time))
- primary = matched[0]
- products: list[PlanStopProductRead] = []
- for delivery in matched:
- products.extend(delivery.products or [])
- merged_products = _merge_stop_products(products)
- return DeliverySlipPrintRead(
- plan_id=plan_id,
- plan_no=plan_no or "",
- plan_date=plan_date,
- customer_id=_resolve_customer_id(primary.customer_id, primary.customer_name),
- receiving_unit=(primary.customer_name or "").strip(),
- receive_contact=(primary.contact or "").strip(),
- delivery_address=(primary.address or "").strip() or None,
- products=merged_products,
- )
- def get_delivery_slip_print_context(
- db: Session,
- *,
- tenant_no: str,
- plan_id: str,
- plan_no: str,
- plan_date: Optional[str],
- customer_id: Optional[str] = None,
- ) -> DeliverySlipPrintRead:
- stops = load_plan_stops_grouped(db, tenant_no, [plan_id]).get(plan_id)
- deliveries = stops[1] if stops else []
- customers = list_delivery_print_customers(deliveries)
- if not customer_id:
- return DeliverySlipPrintRead(
- plan_id=plan_id,
- plan_no=plan_no or "",
- plan_date=plan_date,
- customers=customers,
- )
- detail = build_delivery_slip_print(
- db,
- tenant_no=tenant_no,
- plan_id=plan_id,
- plan_no=plan_no,
- plan_date=plan_date,
- customer_id=customer_id,
- )
- detail.customers = customers
- return detail
|