device infos

This commit is contained in:
2026-08-28 15:07:30 +05:30
parent 5723d373b2
commit 69f4f3e909
84 changed files with 4337 additions and 2339 deletions

View File

@@ -524,9 +524,92 @@ class ApiConfig {
'parcels': booking['parcels'] ?? const [],
'starttime': s(booking['createdat']),
'eta': s(booking['eta']),
// ── The row's own clocks, carried verbatim ──
//
// This adapter builds a **fixed map**, so a field it does not name is a
// field the app can never see — the same trap `step` and `stoptype` were
// in. Every timestamp on the booking was in that trap, and the cost was
// not cosmetic: [ServiceDay] dates a row by exactly these key names, so
// an adapted row carried nothing to date it by and *every* screen that
// asks "does this belong to today" had to answer "cannot tell".
//
// That is how yesterday's assignments stayed on Home. The filter was
// never missing so much as starved: it was asking a question of fields
// this method had already thrown away.
//
// Copied under the names the wire uses, with no reshaping and no
// parsing. [ServiceDay] and [parseStamp] own the reading of them —
// Doormile sends IST wall-clock in naive columns, sometimes with a
// trailing `Z` it never had, and the one place that knows that should
// stay the one place that knows it.
for (final k in timestampFieldNames)
if (booking[k] != null && booking[k].toString().trim().isNotEmpty)
k: booking[k],
// ── And the row's distances, for the same reason ──
//
// `cumulativekms` was named above and the rest were not, so the whole
// distance vocabulary was dropped here: `kms` (what the hub planned),
// `riderkms` (what the rider actually covered) and the `compliance` block
// the contract carries them in.
//
// [StopCompliance] reads exactly those names, so it answered `null` for
// every adapted row — and Activity's `km ridden` totalled zero all day
// and printed an em dash. Same failure as the timestamps, on a different
// set of fields: a fixed map cannot pass on what it does not name.
for (final k in distanceFieldNames)
if (booking[k] != null && booking[k].toString().trim().isNotEmpty)
k: booking[k],
};
}
/// Every distance key a booking row is known to carry, copied through
/// [pickupFromBooking] untouched.
///
/// Kept in step with [StopCompliance], which is what reads them. `compliance`
/// is a nested object rather than a number and is passed on whole — this
/// adapter's job is to stop losing fields, not to reshape them.
static const List<String> distanceFieldNames = [
// What the hub planned for this stop.
'kms',
'km',
// What the rider actually covered. `riderkms` is the backend's name;
// `actualkms` is the name this app posts on its own pickup write.
'riderkms',
'actualkms',
// The contract's block, carrying both plus the on-time verdict.
'compliance',
];
/// Every timestamp key a booking row is known to carry, copied through
/// [pickupFromBooking] untouched.
///
/// Deliberately a superset of what any one endpoint sends: a name that is
/// absent costs one map lookup, and a name that is missing costs a screen
/// its ability to tell today from yesterday. Kept in step with
/// `ServiceDay.timeKeys`, which is what reads them.
static const List<String> timestampFieldNames = [
'createdat',
'createdon',
'updatedat',
'updatedon',
'modifiedon',
'pickedtime',
'picked_time',
'deliverytime',
'deliveredat',
'completedat',
'expected_pickup_time',
'expectedpickuptime',
'slotstarttime',
'slotendtime',
'slotfrom',
'slotto',
'assignedat',
'assignedon',
];
static List<Map<String, dynamic>> pickupsFromBookings(dynamic data) {
if (data is List) {
return data.whereType<Map>().map((b) => pickupFromBooking(b)).toList();