device infos
This commit is contained in:
@@ -102,7 +102,60 @@ class MilkRun {
|
||||
// fabricated kitchen.
|
||||
|
||||
/// The stable key a stop groups under for pickup.
|
||||
static String sourceKeyOf(Map<String, dynamic> stop) {
|
||||
///
|
||||
/// ── The address is the last witness, and it was not being asked ──
|
||||
///
|
||||
/// Id, then name, then `'none'` — and `'none'` is its own bucket per the note
|
||||
/// above, on the sound principle that the app must not fabricate a kitchen.
|
||||
///
|
||||
/// What that missed is that a stop with no source id and no source name is
|
||||
/// not a stop with no *place*. It still says where it is collected from: the
|
||||
/// pickup address, which is on every row, and which two orders off the same
|
||||
/// counter share exactly because it is the same counter.
|
||||
///
|
||||
/// The cost of not asking was visible on a real morning. Eight orders came
|
||||
/// from one kitchen, seven carrying its id and one not, and the eighth could
|
||||
/// not be grouped with its siblings — so it fell out of the dropdown into a
|
||||
/// flat header of its own, titled with the customer's name, reading as a
|
||||
/// second place the rider had to ride to. Seven bags in a list and one
|
||||
/// stranded above it, off the same shelf.
|
||||
///
|
||||
/// Grouping by address is not a fabricated kitchen: it is the weakest true
|
||||
/// statement available — *these are collected from the same address* — and it
|
||||
/// is only reached when the two stronger ones are absent. A row with no
|
||||
/// address at all still gets `'none'`, and still stands alone.
|
||||
/// [within] is the rest of the day, when the caller has it. A stop that
|
||||
/// names no counter **adopts the one its neighbours name at the same
|
||||
/// address** — which is the half of this that the reported case actually
|
||||
/// needed: seven of the eight carried the kitchen's id and the eighth carried
|
||||
/// nothing, so keying the odd one out by its address alone still left it in a
|
||||
/// bucket of its own, correctly grouped with nobody.
|
||||
///
|
||||
/// Only ever *adopts*, never overrides: a stop with its own identity is
|
||||
/// keyed by it and does not consult the day at all. So two counters that
|
||||
/// share a street cannot merge, and a row cannot be pulled away from the id
|
||||
/// the hub gave it.
|
||||
static String sourceKeyOf(
|
||||
Map<String, dynamic> stop, {
|
||||
List<Map<String, dynamic>> within = const [],
|
||||
}) {
|
||||
final own = _identityKeyOf(stop);
|
||||
if (own.isNotEmpty) return own;
|
||||
|
||||
final place = _addressKey(stop);
|
||||
if (place.isEmpty) return 'none';
|
||||
|
||||
for (final other in within) {
|
||||
if (_addressKey(other) != place) continue;
|
||||
final identified = _identityKeyOf(other);
|
||||
if (identified.isNotEmpty) return identified;
|
||||
}
|
||||
return 'at:$place';
|
||||
}
|
||||
|
||||
/// The counter this stop names for itself — `id:…`, `name:…`, or `''` when
|
||||
/// the payload names none.
|
||||
static String _identityKeyOf(Map<String, dynamic> stop) {
|
||||
final id =
|
||||
(stop['sourceid'] ??
|
||||
stop['kitchenid'] ??
|
||||
@@ -113,7 +166,25 @@ class MilkRun {
|
||||
if (id.isNotEmpty && id != '0') return 'id:$id';
|
||||
final name = sourceNameOf(stop).toLowerCase();
|
||||
if (name.isNotEmpty) return 'name:$name';
|
||||
return 'none';
|
||||
return '';
|
||||
}
|
||||
|
||||
/// A pickup address reduced to something two rows can be compared on.
|
||||
///
|
||||
/// Case, spacing and punctuation all vary between rows the same hub wrote —
|
||||
/// `12, SNS Colony` and `12 SNS COLONY ` are one place — so everything but
|
||||
/// the letters and digits is dropped before comparing. Deliberately not
|
||||
/// `compactAddress`: that is written to be *read*, and a key should not
|
||||
/// change because a display rule was tuned.
|
||||
static String _addressKey(Map<String, dynamic> stop) {
|
||||
final raw =
|
||||
(stop['pickupaddress'] ??
|
||||
stop['PickupAddress'] ??
|
||||
stop['pickup_address'] ??
|
||||
'')
|
||||
.toString()
|
||||
.toLowerCase();
|
||||
return raw.replaceAll(RegExp(r'[^a-z0-9]'), '');
|
||||
}
|
||||
|
||||
/// The kitchen's name as the rider reads it, or '' when the payload has none.
|
||||
@@ -177,10 +248,14 @@ class MilkRun {
|
||||
Map<String, dynamic> stop,
|
||||
List<Map<String, dynamic>> stops,
|
||||
) {
|
||||
final key = sourceKeyOf(stop);
|
||||
// The day is passed on both sides so a row that names no counter is
|
||||
// gathered with the ones that do — see [sourceKeyOf]. Without it the bulk
|
||||
// collect would leave behind exactly the order the route card had just
|
||||
// learned to group in, which is the two-readers failure in a new place.
|
||||
final key = sourceKeyOf(stop, within: stops);
|
||||
return [
|
||||
for (final s in stops)
|
||||
if (sourceKeyOf(s) == key) s,
|
||||
if (sourceKeyOf(s, within: stops) == key) s,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user