Files

105 lines
3.4 KiB
Python
Raw Permalink Normal View History

"""Which customer order a project or unit takes its customer, PO and dates from, when VISUAL has several.
The one rule, in order:
1. a Clerical pin that names one of the project's orders (`pin`);
2. the base's own linked order, the first of `by_base[base]` (`base`);
3. the project order whose top jobs name the unit, open orders first (`unit_top_job`);
4. the project's first open order, status F, H or R (`project_open`);
5. the project's first order, the newest (`project_newest`).
`derive` maps the chosen order to the fields a project or unit keeps: customer, po, order_date, ship_date.
"""
from __future__ import annotations
from collections.abc import Mapping
from dataclasses import dataclass
from datetime import date, datetime
from typing import Any
from .types import Order
OPEN_STATUSES = ("F", "H", "R")
VIA = ("pin", "base", "unit_top_job", "project_open", "project_newest")
FIELDS = ("customer", "po", "order_date", "ship_date")
@dataclass(frozen=True)
class Chosen:
order: Order
via: str # pin | base | unit_top_job | project_open | project_newest
def _is_open(o: Order) -> bool:
return (o.status or "").strip().upper() in OPEN_STATUSES
def choose(
*,
unit_number: str,
base: str,
by_base: Mapping[str, list[Order]],
by_project: Mapping[str, list[Order]],
project: str,
pin: str | None,
) -> Chosen | None:
proj = list(by_project.get(project) or [])
own = list(by_base.get(base) or []) if base else []
if pin:
p = pin.strip().upper()
for o in [*proj, *own]:
if o.cust_order_id.strip().upper() == p:
return Chosen(o, "pin")
if own:
return Chosen(own[0], "base")
if unit_number:
u = unit_number.upper()
hits = [o for o in proj if any(t.upper() == u for t in o.top_jobs)]
hits.sort(key=lambda o: not _is_open(o)) # stable: open first, the list's own order within
if hits:
return Chosen(hits[0], "unit_top_job")
for o in proj:
if _is_open(o):
return Chosen(o, "project_open")
if proj:
return Chosen(proj[0], "project_newest")
return None
def derive(order: Order) -> dict[str, Any]:
"""customer <- customer_name, po <- customer_po_ref, order_date, ship_date <- promise or desired ship date."""
return {
"customer": order.customer_name,
"po": order.customer_po_ref,
"order_date": order.order_date,
"ship_date": order.promise_date or order.desired_ship_date,
}
def _iso(v: date | None) -> str | None:
return v.isoformat() if v else None
def order_ref(chosen: Chosen, at: datetime) -> dict[str, Any]:
"""The jsonb kept on projects.order_ref and units.order_ref."""
o = chosen.order
return {
"cust_order_id": o.cust_order_id,
"via": chosen.via,
"status": o.status,
"customer_name": o.customer_name,
"customer_po_ref": o.customer_po_ref,
"order_date": _iso(o.order_date),
"desired_ship_date": _iso(o.desired_ship_date),
"promise_date": _iso(o.promise_date),
"chosen_at": at.isoformat(),
}
def same_ref(a: Mapping[str, Any] | None, b: Mapping[str, Any] | None) -> bool:
"""Two order_refs are the same when everything but chosen_at matches."""
if a is None or b is None:
return a is None and b is None
return {k: v for k, v in a.items() if k != "chosen_at"} == {k: v for k, v in b.items() if k != "chosen_at"}