miler map

This commit is contained in:
2026-09-09 12:55:23 +05:30
parent 074cc0eccf
commit 127fa062ed
143 changed files with 4315 additions and 2291 deletions

View File

@@ -719,6 +719,77 @@ class MilerApi {
),
);
// ═══════════════════════════════════════════════════════════════════════
// THE HANDOVER — the rider gives a hub-routed parcel to a base
// ═══════════════════════════════════════════════════════════════════════
/// Hands a `Created` consignment in at a base, ending this rider's part.
///
/// ── The leg that had no route ──
///
/// A parcel bound for another district is collected at a customer's door and
/// carried to a base; the network takes it from there. The rider could do the
/// first half and had no way to record the second, so an intercity parcel sat
/// in his queue until somebody inwarded it in the console — and every one of
/// those jobs reported zero distance and zero value on `/miler/earnings`,
/// because the assignment was never closed against him.
///
/// ── The body is optional, all of it ──
///
/// Sent with nothing, the parcel is handed into the base it was already
/// routed to. [hubId] is worth sending when the app has one — it is what the
/// server reconciles against — and the coordinates are stamped onto the
/// history row as evidence of where the hand-over happened.
///
/// ── Idempotent twice over ──
///
/// The shared `Idempotency-Key` middleware covers a retry after a dropped
/// response, and a parcel already inwarded answers **200 with
/// `already_inwarded: true`** rather than a 4xx — so a rider on bad signal at
/// a loading bay who presses again is confirmed, not refused. Read the result
/// through [MilerLifecycle.inwardAtHub], which treats that reply as the
/// success it is.
///
/// Refusals carry their own reason: `CONSIGNMENT_NOT_FOUND`,
/// `CONSIGNMENT_NOT_ASSIGNED`, `HUB_REQUIRED`, `HUB_NOT_FOUND`,
/// `INVALID_STATE` for a parcel already past this leg.
static Future<ApiResult> inwardAtHub(
Object consignmentId, {
Object? hubId,
double? lat,
double? lon,
}) => _guarded(
'inward-at-hub:$consignmentId',
() => _send(
'POST',
'/miler/consignments/$consignmentId/inward-at-hub',
idempotencyKey: _idempotencyKey('inward-at-hub', consignmentId),
body: {
if (hubId != null) 'hub_id': hubId,
if (lat != null) 'latitude': lat,
if (lon != null) 'longitude': lon,
},
),
);
/// The bases this rider may hand a parcel in at.
///
/// ── Why this is not the tenant locations route ──
///
/// `GET /admin/tenants/:id/locations` is a **different dataset** — a client's
/// own sites, not bases — and `/admin/*` requires roles 1/3/4 while a rider is
/// role 5. The 401 this app has been logging as a gap on that route was by
/// design, not an oversight. This is the rider-readable one.
///
/// Returns `{id, name, address, pincode, latitude, longitude}` per base, plus
/// `distance_km` and nearest-first ordering once the rider has reported a
/// position.
static Future<ApiResult> bases({String status = 'Active'}) => _send(
'GET',
'/miler/bases',
query: {if (status.isNotEmpty) 'status': status},
);
/// The consignment's current state and what may be done to it.
///
/// Returns `status` plus the backend's own derived flags — `collected`,