feat: miler delivery-leg fixes — consignmentid, auto route sequencing, admin consignment status
Miler app P0 + contract gaps found in the live audit: - GET /miler/bookings now returns consignmentid + consignmentstatus on every row (nullable), so the app can call deliver/skip/start-delivery straight from the list. /miler/assignments is the active-only queue, so this is the authoritative fix for stops that have moved onto the delivery leg. - GET /miler/bookings now returns sequencedat per row: non-null means the console/optimizer fixed this stop's order and the app follows step exactly; null means no route assigned and the app may fall back to nearest-first. - Route sequencing (internal/routing) now runs automatically after every assignment — customer auto-assign, express auto-assign, manual assign, and accept — via SequenceMilerStopsAsync (fire-and-forget, no-op below two active stops). Previously only hub batch-assign sequenced, so most riders saw step=0. - GET /admin/bookings now surfaces the live consignmentstatus alongside the frozen booking status, so a Converted_To_Consignment booking can still show Out_for_Delivery / Delivered instead of a generic "Active". Two-step hyperlocal flow (Arrived_At_Pickup, Collected_By_Miler, start-delivery) stays gated behind MILER_COLLECTED_STATE_ENABLED (default off) until the app ships; consignmentid/status, GET /miler/consignments/:id, stable error codes and Idempotency-Key handling are unconditional and safe on the current app. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WRaFH5hMRqmUQvVPQsyjZD
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"doormile/constants"
|
||||
"doormile/db"
|
||||
"doormile/internal/routing"
|
||||
"doormile/models"
|
||||
"doormile/utils"
|
||||
|
||||
@@ -240,6 +241,10 @@ func commitAssignment(booking *models.PickupBooking, candidate *milerCandidate,
|
||||
notifyMilerNewAssignment(candidate.profile, booking.Bookingid)
|
||||
notifyCustomerMilerAssigned(booking, candidate.profile.Displayname)
|
||||
|
||||
// Order the rider's stops now this one is added. No-op below two active stops;
|
||||
// best-effort and off this goroutine's critical path.
|
||||
routing.SequenceMilerStopsAsync(milerUserID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"doormile/constants"
|
||||
"doormile/db"
|
||||
"doormile/internal/routing"
|
||||
"doormile/models"
|
||||
"doormile/utils"
|
||||
)
|
||||
@@ -240,6 +241,10 @@ func commitCustomerAssignment(
|
||||
notifyMilerNewAssignment(miler.profile, booking.Bookingid)
|
||||
notifyCustomerMilerAssigned(booking, miler.profile.Displayname)
|
||||
|
||||
// Order the rider's stops now this one is added. No-op below two active stops;
|
||||
// best-effort and off this goroutine's critical path.
|
||||
routing.SequenceMilerStopsAsync(milerUserID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -151,6 +151,27 @@ func SequenceMilerStops(milerUserID int) ([]Result, error) {
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// SequenceMilerStopsAsync re-sequences a rider's active stops in the background.
|
||||
// Fire-and-forget: the assignment paths call this after they commit, so a rider
|
||||
// who now holds two or more stops gets an ordered route — without the optimizer's
|
||||
// network call ever sitting inside, or being able to fail, the assignment request
|
||||
// itself. Below two active stops SequenceMilerStops is a no-op, so calling it
|
||||
// after every single assignment is safe and cheap.
|
||||
func SequenceMilerStopsAsync(milerUserID int) {
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
utils.Error("routing: async sequencing panicked",
|
||||
"miler_userid", milerUserID, "error", r)
|
||||
}
|
||||
}()
|
||||
if _, err := SequenceMilerStops(milerUserID); err != nil {
|
||||
utils.Warn("routing: async sequencing failed",
|
||||
"miler_userid", milerUserID, "error", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// loadActiveStops returns the rider's assignments that still have to be run,
|
||||
// with the coordinates needed to order them.
|
||||
func loadActiveStops(milerUserID int) ([]stop, error) {
|
||||
|
||||
Reference in New Issue
Block a user