import 'package:miler/data/milk_run.dart'; import 'package:miler/views/Dashboard/pickups/stop_type.dart'; /// ───────────────────────────────────────────────────────────────────────── /// WHAT THE RIDER COLLECTS AT A COUNTER, AS A LIST HE CAN COUNT /// /// One pickup order is one handover. If a kitchen has five pickup orders the /// rider is handed five things and ends up with five deliveries, each carrying /// what it arrived in. That rule lives here so it cannot be stated two /// different ways on two screens. /// /// ── Why this is a file and not a `+ 1` at each call site ── /// /// Every screen in the pickup half of the app has to answer "how many?" and /// "which one is this?", and every screen that answered independently answered /// differently: one showed a backend `Quantity` (an order's item count, not a /// count of handovers), one showed a bare printed label when the payload /// happened to carry one and nothing at all when it did not, and the kitchen /// heading counted "meals". A rider standing at a counter comparing "5 meals" /// on his phone with four items on the shelf has no way to tell which of the /// two numbers is wrong. /// /// So the count is **derived from the orders**, always, and there is no second /// quantity anywhere that can disagree with it. /// /// ── The invented numbering is gone ── /// /// This used to name every line `Bag 1 … Bag n`, falling back to the order's /// position in its group whenever the payload printed no label of its own. Two /// things were wrong with that, and only the second is about the word. /// /// The number was **the app's own invention presented as a physical fact**. It /// counted positions in a list the app had built, and it was drawn as a tag in /// the corner of every row where it read like something stencilled on a /// container. A rider matching a shelf against it was matching against the /// app's arithmetic, not against anything the kitchen had written; and the rail /// beside it already numbers the same rows, so the tag mostly restated the node /// two columns to its left in louder type. /// /// A label the counter **actually printed** is a different thing entirely — it /// is a fact about an object in front of him — so it survives, verbatim, under /// whatever name the kitchen gave it. What is never done again is manufacturing /// one where none exists. /// /// Nothing here fabricates a crate, a tote or a quantity the backend has not /// sent. If a future contract ever puts more than one handover on an order, /// this is the one file that changes. /// ───────────────────────────────────────────────────────────────────────── class OrderManifest { OrderManifest._(); /// One line per order: the stop, who it is for, and the label the counter /// printed on it — empty when it printed none. /// /// Deliberately carries the stop itself: every caller that renders a manifest /// also needs to act on the orders behind it, and pairing them here is what /// stops a screen from rendering five lines and posting four ids. static List forGroup(List> stops) => [ for (var i = 0; i < stops.length; i++) ManifestLine( stop: stops[i], orderId: MilkRun.idOf(stops[i]), customer: customerOf(stops[i]), label: labelFor(stops[i]), ), ]; /// The label physically printed on one order's handover, or `''`. /// /// Read straight off the payload and never derived. A counter that prints /// nothing leaves this empty, and the row simply carries no tag — which is /// honest, where a manufactured `Bag 4` was a shelf reference the shelf had /// never heard of. static String labelFor(Map stop) => stopPrintedLabel(stop); /// `5 orders` — the load, in the unit everything else on the screen counts. /// /// It printed `5 orders · 5 bags` once: the two halves of one rule side by /// side, as a check the rider could eyeball. That cost the header the fact it /// exists for — a real kitchen name plus `13 orders · 13 bags` pushed /// `11 to accept` off the row — so it was cut to the physical half, `13 bags`. /// /// Now that the app no longer names anything a bag, the surviving half is the /// one the rest of the screen already speaks: the rows underneath are orders, /// the chip counts orders, the hub assigns orders. One word, everywhere. static String countLabel(int orders) => orders == 1 ? '1 order' : '$orders orders'; /// The name the order is going to, for a manifest line. static String customerOf(Map stop) => (stop['pickupcustomer'] ?? stop['customername'] ?? stop['tenantname'] ?? '') .toString() .trim(); } /// One row of a pickup manifest. See [OrderManifest.forGroup]. class ManifestLine { final Map stop; final String orderId; final String customer; /// What the counter printed on this order, or `''` when it printed nothing. final String label; const ManifestLine({ required this.stop, required this.orderId, required this.customer, this.label = '', }); }