device infos
This commit is contained in:
@@ -228,23 +228,19 @@ class WorkRepository {
|
||||
// it is the timeline contradicting itself in the rider's face. Anything the
|
||||
// backend already reports as past his hands is skipped, and stays skipped
|
||||
// forever because [stampOrderEvent] never overwrites.
|
||||
unawaited(
|
||||
stampOrderEvents(
|
||||
mapped
|
||||
.where((s) {
|
||||
final st = stopStatusOf(s);
|
||||
return !st.isWorkComplete &&
|
||||
!st.isCancelled &&
|
||||
!st.isRejected &&
|
||||
!st.isSkipped &&
|
||||
!st.isPicked &&
|
||||
!st.isDeliveryLeg;
|
||||
})
|
||||
.map((s) => (s['orderid'] ?? '').toString())
|
||||
.where((id) => id.isNotEmpty),
|
||||
OrderEvent.assigned,
|
||||
),
|
||||
);
|
||||
//
|
||||
// ── And it is read back onto the row ──
|
||||
//
|
||||
// It used to be fired into the dark with `unawaited`: written for one
|
||||
// screen's timeline, and joined by that screen alone. That left every other
|
||||
// screen with no clock at all on a row the backend dates with nothing, and
|
||||
// "does this belong to today" is a question three of them ask.
|
||||
//
|
||||
// So the stamp comes back as `assignedat` — a field on the stop, like any
|
||||
// other. Awaited rather than fired off, because a row that reaches Home
|
||||
// before its own clock does is a row Home cannot place, and the batch is
|
||||
// one read and one write of a small blob. See [stampOrderEventsAndRead].
|
||||
await _stampAssignment(mapped);
|
||||
|
||||
_loadedAt = DateTime.now();
|
||||
return _publish(
|
||||
@@ -286,6 +282,59 @@ class WorkRepository {
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes each stop's assignment clock onto it, in place, as `assignedat`.
|
||||
///
|
||||
/// ── Which rows are stamped, and which only read ──
|
||||
///
|
||||
/// Only work still in front of the rider is *stamped* — see the note at the
|
||||
/// call site: the ledger did not exist when a stop that is already delivered
|
||||
/// arrived, so its first sighting is whenever the app happened to be opened,
|
||||
/// and an `Assigned 3:34 PM` above a `Delivered 11:57 AM` is the timeline
|
||||
/// contradicting itself.
|
||||
///
|
||||
/// Every row is **read**, though, finished ones included. A stop the rider
|
||||
/// collected this morning was stamped this morning while it was still ahead
|
||||
/// of him, and that clock is exactly what keeps it inside today's trip — drop
|
||||
/// it and the progress ring loses its own denominator the moment the work is
|
||||
/// done.
|
||||
///
|
||||
/// A backend clock always wins: this only fills a gap, never overwrites.
|
||||
static Future<void> _stampAssignment(List<Map<String, dynamic>> day) async {
|
||||
if (day.isEmpty) return;
|
||||
try {
|
||||
final ledger = await stampOrderEventsAndRead(
|
||||
day
|
||||
.where((s) {
|
||||
final st = stopStatusOf(s);
|
||||
return !st.isWorkComplete &&
|
||||
!st.isCancelled &&
|
||||
!st.isRejected &&
|
||||
!st.isSkipped &&
|
||||
!st.isPicked &&
|
||||
!st.isDeliveryLeg;
|
||||
})
|
||||
.map((s) => (s['orderid'] ?? '').toString())
|
||||
.where((id) => id.isNotEmpty),
|
||||
OrderEvent.assigned,
|
||||
);
|
||||
if (ledger.isEmpty) return;
|
||||
|
||||
for (final stop in day) {
|
||||
final id = (stop['orderid'] ?? '').toString().trim();
|
||||
if (id.isEmpty) continue;
|
||||
final at = ledger[id]?[OrderEvent.assigned];
|
||||
if (at == null || at.isEmpty) continue;
|
||||
final existing = (stop['assignedat'] ?? '').toString().trim();
|
||||
if (existing.isNotEmpty) continue;
|
||||
stop['assignedat'] = at;
|
||||
}
|
||||
} catch (e) {
|
||||
// A day with no assignment clocks is a day the screens date by whatever
|
||||
// the backend sent. Never worth failing the fetch over.
|
||||
debugPrint('[WORK] could not read the assignment ledger: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Turns a refused call into the thing the rider does about it.
|
||||
static LoadFailureKind _classify(ApiResult res) => switch (res.status) {
|
||||
0 => LoadFailureKind.offline,
|
||||
|
||||
Reference in New Issue
Block a user