115 lines
5.4 KiB
Dart
115 lines
5.4 KiB
Dart
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<ManifestLine> forGroup(List<Map<String, dynamic>> 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<String, dynamic> 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<String, dynamic> stop) =>
|
|
(stop['pickupcustomer'] ??
|
|
stop['customername'] ??
|
|
stop['tenantname'] ??
|
|
'')
|
|
.toString()
|
|
.trim();
|
|
}
|
|
|
|
/// One row of a pickup manifest. See [OrderManifest.forGroup].
|
|
class ManifestLine {
|
|
final Map<String, dynamic> 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 = '',
|
|
});
|
|
}
|