Files
shanxia2.0/backend/app/services/pl_plan_print_service.py
T
2026-08-27 14:23:18 +08:00

170 lines
5.4 KiB
Python

"""运输计划打印数据聚合(一车多卸)"""
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