device infos
This commit is contained in:
@@ -227,7 +227,11 @@ Future<String> resolveConsignmentId(Map<String, dynamic> stop) async {
|
||||
/// rider can retry this until his battery dies.
|
||||
/// • **At a hub.** A cross-city parcel is `Inwarded_at_Hub` and will be
|
||||
/// delivered by somebody else. There is nothing here for him to start.
|
||||
/// • **Refused.** The server gave a reason and it was thrown away.
|
||||
/// • **Refused.** The server gave a reason and it was thrown away. It is
|
||||
/// read now — and *translated*, because the reason arrives as a state
|
||||
/// machine talking to itself (`consignment is Inwarded_At_Hub, not
|
||||
/// Collected_By_Miler`) and that is not a sentence for a rider. See
|
||||
/// [_refusalSentence].
|
||||
/// • **Unreachable.** The only one where "check your connection" is true.
|
||||
///
|
||||
/// Telling a rider to check a working connection, about a parcel that is not
|
||||
@@ -318,10 +322,10 @@ Future<bool> releaseForDelivery(Map<String, dynamic> stop) async {
|
||||
// account for, and one 400 carrying the backend's own sentence is worth more
|
||||
// than a client-side refusal that invents one. A hyperlocal consignment the
|
||||
// pivot has not finished releasing is let through; a hub-routed one is
|
||||
// refused by the server, and the rider is told what the server said.
|
||||
// refused by the server, and the rider is told what the server *meant* —
|
||||
// translated out of the state machine's vocabulary, see [_refusalSentence].
|
||||
// A hold that cannot exist on this line is a bad read, not a fact about the
|
||||
// stop. See [_handoffHoldIsPossible].
|
||||
final heldElsewhere = state.awaitsHub && _handoffHoldIsPossible;
|
||||
if (state.awaitsHub && !_handoffHoldIsPossible) {
|
||||
debugPrint(
|
||||
'[MILKRUN] $consignmentId read as ${state.name} on a line with no '
|
||||
@@ -333,11 +337,16 @@ Future<bool> releaseForDelivery(Map<String, dynamic> stop) async {
|
||||
!(state.awaitsHub && !_handoffHoldIsPossible) &&
|
||||
state != ConsignmentState.unknown) {
|
||||
debugPrint('[MILKRUN] $consignmentId is ${state.name} — not releasable');
|
||||
lastReleaseFailure = heldElsewhere
|
||||
// The honest answer for a cross-city parcel: it is not his round, and
|
||||
// saying so without naming a building he has never been to.
|
||||
? "This one has already been handed on — it's not yours to deliver."
|
||||
: 'This parcel cannot be started yet. Ask your office to check it.';
|
||||
// One sentence per state, written once — see
|
||||
// [ConsignmentStateX.startRefusalSentence]. This branch and the refusal
|
||||
// below are the same answer arrived at from two directions (a state the
|
||||
// app read, and a state the server named), and they used to word it
|
||||
// differently: a cross-city parcel blocked here said "it's not yours to
|
||||
// deliver" while the identical parcel blocked one request later read out
|
||||
// a database enum.
|
||||
lastReleaseFailure =
|
||||
state.startRefusalSentence ??
|
||||
'This parcel cannot be started yet. Ask your office to check it.';
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -361,16 +370,63 @@ Future<bool> releaseForDelivery(Map<String, dynamic> stop) async {
|
||||
final after = await ConsignmentGate.stateOf(consignmentId);
|
||||
if (after.isDeliverable || after.isDelivered) return true;
|
||||
|
||||
// `status: 0` is the request never leaving; anything else is the server
|
||||
// answering, and its own words beat a guess about the network.
|
||||
// `status: 0` is the request never leaving, and it is the one failure that
|
||||
// is really about the connection.
|
||||
lastReleaseFailure = res.status == 0
|
||||
? 'Could not reach your office. Check your connection and slide again.'
|
||||
: (res.message.trim().isNotEmpty
|
||||
? res.message.trim()
|
||||
: 'Your office would not start this delivery.');
|
||||
: _refusalSentence(res, after);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// The rider's version of a refused **Start ride**.
|
||||
///
|
||||
/// ── What the rider was actually reading ──
|
||||
///
|
||||
/// The server's own words were passed straight to the screen, on the argument
|
||||
/// that one refusal carrying the backend's reason beats a client-side guess
|
||||
/// that invents one. That argument holds for *whose* answer it is. It does not
|
||||
/// hold for what the answer turned out to be: `start-delivery` refuses with an
|
||||
/// assertion about its own model — **"consignment is Inwarded_At_Hub, not
|
||||
/// Collected_By_Miler"** — and that is what a rider saw on the slider, in
|
||||
/// database vocabulary, with no way to tell it from a crash.
|
||||
///
|
||||
/// The reason is worth keeping; the wording was never the server's to write.
|
||||
/// So the state is what travels, and [ConsignmentStateX.startRefusalSentence]
|
||||
/// says it once, in one place, in words that answer the only two questions he
|
||||
/// has: is this mine, and will sliding again help.
|
||||
///
|
||||
/// ── Three sources for that state, best first ──
|
||||
///
|
||||
/// 1. **A fresh read** — [after], asked immediately after the refusal, which
|
||||
/// is the newest thing anyone knows about the consignment.
|
||||
/// 2. **The refusal itself.** The read can fail — the row need not carry a
|
||||
/// status and the detail route 404s on older deployments — and when it
|
||||
/// does the refusal is the only thing left that knows. See
|
||||
/// [consignmentStateNamedInRefusal] for why reading it is safe.
|
||||
/// 3. **The failure code.** `INVALID_STATE` alone still says the one useful
|
||||
/// thing: the consignment has moved on from the rung this press acts at,
|
||||
/// so sliding again is not the answer.
|
||||
///
|
||||
/// Prose from the server is still preferred over a generic sentence — some
|
||||
/// routes really do answer in words meant for a person. What is filtered out
|
||||
/// is the wire vocabulary. See [namesWireState].
|
||||
String _refusalSentence(ApiResult res, ConsignmentState after) {
|
||||
final state = after != ConsignmentState.unknown
|
||||
? after
|
||||
: consignmentStateNamedInRefusal(res.message);
|
||||
|
||||
final fromState = state.startRefusalSentence;
|
||||
if (fromState != null) return fromState;
|
||||
|
||||
final said = res.message.trim();
|
||||
if (said.isNotEmpty && !namesWireState(said)) return said;
|
||||
|
||||
return res.isInvalidState
|
||||
? 'Your office has already moved this parcel on, so it cannot be '
|
||||
'started from here. Ask them to check it.'
|
||||
: 'Your office would not start this delivery.';
|
||||
}
|
||||
|
||||
/// Brings this device into line with a delivery the server already has.
|
||||
///
|
||||
/// The same local bookkeeping a successful `deliver` performs — the order
|
||||
|
||||
Reference in New Issue
Block a user