production

This commit is contained in:
2026-08-28 11:13:15 +05:30
parent d7348e253f
commit 5723d373b2
162 changed files with 17924 additions and 7026 deletions

View File

@@ -67,7 +67,7 @@ extension RouteOrderSourceX on RouteOrderSource {
/// What the rider is told the list is ordered by. Short, because it sits
/// under a heading and not in a paragraph.
String get label => switch (this) {
RouteOrderSource.adminSequence => 'Hub route',
RouteOrderSource.adminSequence => 'Assigned route',
RouteOrderSource.bookedTime => 'By booked time',
RouteOrderSource.backendOrder => 'As assigned',
RouteOrderSource.proximity => 'Nearest first',
@@ -76,7 +76,8 @@ extension RouteOrderSourceX on RouteOrderSource {
/// The longer form, for a place with room to explain — and specifically to
/// keep the app from implying the hub planned an order it did not.
String get explanation => switch (this) {
RouteOrderSource.adminSequence => 'Ordered by the route your hub assigned.',
RouteOrderSource.adminSequence =>
'Ordered by the route your office assigned.',
RouteOrderSource.bookedTime =>
'No route assigned — ordered by booked time.',
RouteOrderSource.backendOrder =>
@@ -122,9 +123,43 @@ abstract final class RouteOrder {
return 0;
}
/// Field names that have carried the moment the route was solved.
static const List<String> sequencedAtKeys = [
'sequencedat',
'sequencedAt',
'sequenced_at',
'routesequencedat',
];
/// True when this stop carries a solve timestamp.
///
/// ── The authority signal, confirmed by the backend ──
///
/// `sequencedat` is what says a route exists: **non-null → follow `step`
/// exactly; null → no route was assigned, use a fallback.** Sequencing is
/// automatic on every assignment — there is no operator action to wait for —
/// so `step: 0` with a null stamp means one of exactly three things: the
/// rider has fewer than two active stops, a stop is missing coordinates, or
/// the row predates the fix. None of those is a route to follow.
static bool isSequenced(Map<String, dynamic> stop) {
for (final key in sequencedAtKeys) {
final raw = stop[key];
if (raw == null) continue;
if (raw.toString().trim().isEmpty) continue;
return true;
}
return false;
}
/// True when the hub has solved an order for at least one of these stops.
///
/// The stamp is the authority and a positive `step` is accepted alongside
/// it: a deployment that populates one without the other is still telling
/// the app it has a route, and refusing to follow a numbered sequence
/// because its timestamp is missing would be reading the contract against
/// the rider. Either is enough; neither means no route.
static bool hasAdminSequence(Iterable<Map<String, dynamic>> stops) =>
stops.any((s) => sequenceOf(s) > 0);
stops.any((s) => isSequenced(s) || sequenceOf(s) > 0);
/// Puts [stops] in the order they are to be worked, and says which rule it
/// used.