| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- """运输计划列表:聚合司机/现场/出入库现场等单据附件。"""
- from __future__ import annotations
- import json
- from typing import Optional
- from sqlalchemy.orm import Session
- from app.models.pl_models import (
- PlInboundOrder,
- PlOutboundOrder,
- PlPlan,
- PlPlanDelivery,
- PlTransport,
- PlTransportDriverStopFeedback,
- PlTransportSiteLink,
- PlTransportSiteStopFeedback,
- )
- def _parse_image_urls(raw: Optional[str]) -> list[str]:
- if not raw:
- return []
- text = str(raw).strip()
- if not text:
- return []
- try:
- parsed = json.loads(text)
- if isinstance(parsed, list):
- return [str(item).strip() for item in parsed if str(item).strip()]
- except json.JSONDecodeError:
- pass
- return [item.strip() for item in text.split(",") if item.strip()]
- def _short_label(text: str, max_len: int = 8) -> str:
- value = (text or "").strip()
- if not value:
- return "现场"
- if len(value) <= max_len:
- return value
- return f"{value[: max_len - 1]}…"
- def _stop_source_label(
- stop_type: str,
- stop_id: str,
- source: str,
- delivery_seq_by_id: dict[str, int],
- ) -> str:
- normalized = (stop_type or "").strip()
- if normalized == "load":
- return f"装货·{source}"
- seq = delivery_seq_by_id.get((stop_id or "").strip())
- if seq:
- return f"送货#{seq}·{source}"
- return f"送货·{source}"
- def _stop_sort_key(
- stop_type: str,
- stop_id: str,
- source: str,
- delivery_seq_by_id: dict[str, int],
- ) -> tuple[int, int, int, str]:
- normalized = (stop_type or "").strip()
- stop_rank = 0 if normalized == "load" else 1
- seq = delivery_seq_by_id.get((stop_id or "").strip(), 999) if normalized != "load" else 0
- source_rank = 0 if source == "司机" else 1
- return (stop_rank, seq, source_rank, stop_id or "")
- def load_plan_document_attachments_by_plan_ids(
- db: Session,
- *,
- tenant_no: str,
- plan_ids: list[str],
- ) -> dict[str, list[dict[str, str]]]:
- if not plan_ids:
- return {}
- result: dict[str, list[dict[str, str]]] = {plan_id: [] for plan_id in plan_ids}
- seen: dict[str, set[str]] = {plan_id: set() for plan_id in plan_ids}
- pending: dict[str, list[tuple[tuple[int, int, int, str], str, list[str]]]] = {
- plan_id: [] for plan_id in plan_ids
- }
- def add(plan_id: str, label: str, urls: list[str], sort_key: tuple[int, int, int, str]) -> None:
- if plan_id not in pending:
- return
- cleaned = [url for url in urls if url]
- if not cleaned:
- return
- pending[plan_id].append((sort_key, label, cleaned))
- def flush(plan_id: str) -> None:
- bucket = result.get(plan_id)
- if bucket is None:
- return
- for _, label, urls in sorted(pending.get(plan_id, []), key=lambda item: item[0]):
- for url in urls:
- if url in seen[plan_id]:
- continue
- seen[plan_id].add(url)
- bucket.append({"url": url, "label": label})
- delivery_seq_by_id: dict[str, int] = {}
- delivery_rows = (
- db.query(PlPlanDelivery.id, PlPlanDelivery.plan_id, PlPlanDelivery.seq)
- .filter(
- PlPlanDelivery.plan_id.in_(plan_ids),
- PlPlanDelivery.tenant_no == tenant_no,
- PlPlanDelivery.del_flag == 0,
- )
- .all()
- )
- for delivery_id, _plan_id, seq in delivery_rows:
- delivery_seq_by_id[str(delivery_id)] = int(seq or 0)
- plan_rows = (
- db.query(PlPlan.id, PlPlan.transport_id)
- .filter(
- PlPlan.id.in_(plan_ids),
- PlPlan.tenant_no == tenant_no,
- PlPlan.del_flag == 0,
- )
- .all()
- )
- transport_ids = [transport_id for _, transport_id in plan_rows if transport_id]
- plan_by_transport = {
- transport_id: plan_id for plan_id, transport_id in plan_rows if transport_id
- }
- if transport_ids:
- transports = (
- db.query(PlTransport)
- .filter(
- PlTransport.id.in_(transport_ids),
- PlTransport.tenant_no == tenant_no,
- PlTransport.del_flag == 0,
- )
- .all()
- )
- for transport in transports:
- plan_id = plan_by_transport.get(transport.id)
- if not plan_id:
- continue
- add(
- plan_id,
- "司机",
- _parse_image_urls(transport.feedback_images),
- (0, 0, 0, "transport"),
- )
- driver_rows = (
- db.query(PlTransportDriverStopFeedback)
- .filter(
- PlTransportDriverStopFeedback.plan_id.in_(plan_ids),
- PlTransportDriverStopFeedback.tenant_no == tenant_no,
- PlTransportDriverStopFeedback.del_flag == 0,
- )
- .all()
- )
- for row in driver_rows:
- label = _stop_source_label(row.stop_type, row.stop_id, "司机", delivery_seq_by_id)
- add(
- row.plan_id,
- label,
- _parse_image_urls(row.attachment_urls),
- _stop_sort_key(row.stop_type, row.stop_id, "司机", delivery_seq_by_id),
- )
- site_stop_rows = (
- db.query(PlTransportSiteStopFeedback)
- .filter(
- PlTransportSiteStopFeedback.plan_id.in_(plan_ids),
- PlTransportSiteStopFeedback.tenant_no == tenant_no,
- PlTransportSiteStopFeedback.del_flag == 0,
- )
- .all()
- )
- for row in site_stop_rows:
- label = _stop_source_label(row.stop_type, row.stop_id, "现场", delivery_seq_by_id)
- add(
- row.plan_id,
- label,
- _parse_image_urls(row.attachment_urls),
- _stop_sort_key(row.stop_type, row.stop_id, "现场", delivery_seq_by_id),
- )
- site_rows = (
- db.query(PlTransportSiteLink)
- .filter(
- PlTransportSiteLink.plan_id.in_(plan_ids),
- PlTransportSiteLink.tenant_no == tenant_no,
- PlTransportSiteLink.del_flag == 0,
- )
- .order_by(PlTransportSiteLink.order_num, PlTransportSiteLink.create_time)
- .all()
- )
- for row in site_rows:
- product = (row.product or "").strip()
- label = f"现场·{_short_label(product)}" if product else "现场"
- add(row.plan_id, label, _parse_image_urls(row.site_feedback_images), (2, 0, 1, row.id or ""))
- inbound_rows = (
- db.query(PlInboundOrder)
- .filter(
- PlInboundOrder.plan_id.in_(plan_ids),
- PlInboundOrder.tenant_no == tenant_no,
- PlInboundOrder.del_flag == 0,
- )
- .all()
- )
- for row in inbound_rows:
- add(row.plan_id, "入库现场", _parse_image_urls(row.site_feedback_images), (3, 0, 1, row.id or ""))
- outbound_rows = (
- db.query(PlOutboundOrder)
- .filter(
- PlOutboundOrder.plan_id.in_(plan_ids),
- PlOutboundOrder.tenant_no == tenant_no,
- PlOutboundOrder.del_flag == 0,
- )
- .all()
- )
- for row in outbound_rows:
- add(row.plan_id, "出库现场", _parse_image_urls(row.site_feedback_images), (3, 0, 2, row.id or ""))
- for plan_id in plan_ids:
- flush(plan_id)
- return result
|