updates on the ai agents and time series prediction and updates on the api to
This commit is contained in:
@@ -14,7 +14,6 @@ import (
|
||||
"doormile/dto"
|
||||
"doormile/internal/assignment"
|
||||
"doormile/internal/legs"
|
||||
"doormile/internal/routing"
|
||||
"doormile/models"
|
||||
"doormile/utils"
|
||||
|
||||
@@ -1972,122 +1971,33 @@ func HubBatchAssign(c *fiber.Ctx) error {
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return utils.BadRequest(c, "invalid request body")
|
||||
}
|
||||
capPerRider := req.MaxPerRider
|
||||
if capPerRider <= 0 {
|
||||
capPerRider = defaultBatchAssignCapPerRider
|
||||
}
|
||||
|
||||
bookingQuery := db.DB.Where("assignedmileruserid IS NULL AND status = ?", constants.BookingPendingPickup)
|
||||
if len(req.Bookingids) > 0 {
|
||||
bookingQuery = bookingQuery.Where("bookingid IN ?", req.Bookingids)
|
||||
} else if prefix != "" {
|
||||
bookingQuery = bookingQuery.Where("pickuppincode LIKE ?", prefix+"%")
|
||||
}
|
||||
bookingQuery = scopeBookingsToOwnTenant(c, bookingQuery)
|
||||
|
||||
var bookings []models.PickupBooking
|
||||
if err := bookingQuery.Order("createdat ASC").Find(&bookings).Error; err != nil {
|
||||
return utils.Internal(c, "failed to fetch pending bookings")
|
||||
}
|
||||
if len(bookings) == 0 {
|
||||
return utils.OK(c, fiber.Map{"assigned": 0, "skipped": 0, "results": []fiber.Map{}})
|
||||
}
|
||||
|
||||
// Every rider on duty at this hub, not only the idle ones. capPerRider is
|
||||
// what limits a round; requiring Available made that limit unreachable,
|
||||
// because a rider stopped being Available the moment they took the first
|
||||
// booking of the very batch being built.
|
||||
var riderProfiles []models.MilerProfile
|
||||
if err := db.DB.Where("hubid = ? AND availabilitystatus IN ?", hubID, constants.MilerWorkingStatuses).
|
||||
Find(&riderProfiles).Error; err != nil {
|
||||
return utils.Internal(c, "failed to fetch available riders")
|
||||
}
|
||||
|
||||
candidates := make([]*batchRiderCandidate, 0, len(riderProfiles))
|
||||
for _, mp := range riderProfiles {
|
||||
// Seed the count with what the rider is ALREADY holding. capPerRider
|
||||
// has to mean "stops in hand", not "stops added by this call" — now
|
||||
// that busy riders are eligible, counting only this call's additions
|
||||
// would hand five more to someone already carrying five.
|
||||
var openStops int64
|
||||
db.DB.Model(&models.BookingAssignment{}).
|
||||
Where("mileruserid = ? AND assignmentstatus IN ?", mp.Userid, []string{
|
||||
constants.AssignmentAssigned,
|
||||
constants.AssignmentAccepted,
|
||||
}).
|
||||
Count(&openStops)
|
||||
candidates = append(candidates, &batchRiderCandidate{
|
||||
userid: mp.Userid, lat: mp.Currentlatitude, lon: mp.Currentlongitude,
|
||||
assigned: int(openStops),
|
||||
})
|
||||
}
|
||||
|
||||
results := make([]fiber.Map, 0, len(bookings))
|
||||
assignedCount, skippedCount := 0, 0
|
||||
|
||||
for _, b := range bookings {
|
||||
var nearest *batchRiderCandidate
|
||||
nearestDist := math.MaxFloat64
|
||||
|
||||
for _, cand := range candidates {
|
||||
if cand.assigned >= capPerRider {
|
||||
continue
|
||||
// The solver itself now lives in batchAssignService.go, shared with
|
||||
// AdminBatchAssign. Only the scope differs: this route's riders are the
|
||||
// ones on duty AT THIS HUB, and with no explicit bookingids it clears this
|
||||
// hub's own pincode-prefixed queue.
|
||||
result, err := RunBatchAssign(req.Bookingids, req.MaxPerRider, batchRiderScope{
|
||||
ActorID: staffID,
|
||||
Bookings: func(q *gorm.DB) *gorm.DB {
|
||||
if len(req.Bookingids) == 0 && prefix != "" {
|
||||
q = q.Where("pickuppincode LIKE ?", prefix+"%")
|
||||
}
|
||||
d := haversineKM(b.Pickuplatitude, b.Pickuplongitude, cand.lat, cand.lon)
|
||||
if d < nearestDist {
|
||||
nearestDist = d
|
||||
nearest = cand
|
||||
}
|
||||
}
|
||||
|
||||
if nearest == nil {
|
||||
results = append(results, fiber.Map{
|
||||
"bookingid": b.Bookingid, "bookingno": b.Bookingno,
|
||||
"assigned": false, "reason": "no available rider under capacity",
|
||||
})
|
||||
skippedCount++
|
||||
continue
|
||||
}
|
||||
|
||||
if _, err := AssignMilerToBooking(b.Bookingid, nearest.userid, &staffID); err != nil {
|
||||
results = append(results, fiber.Map{
|
||||
"bookingid": b.Bookingid, "bookingno": b.Bookingno,
|
||||
"assigned": false, "reason": err.Error(),
|
||||
})
|
||||
skippedCount++
|
||||
continue
|
||||
}
|
||||
|
||||
nearest.assigned++
|
||||
results = append(results, fiber.Map{
|
||||
"bookingid": b.Bookingid, "bookingno": b.Bookingno,
|
||||
"assigned": true, "mileruserid": nearest.userid, "distance_km": nearestDist,
|
||||
})
|
||||
assignedCount++
|
||||
}
|
||||
|
||||
// Batch assignment is exactly the case stop-ordering exists for: a rider
|
||||
// walks out of here with several bookings and, until now, no indication of
|
||||
// what order to run them in. Sequence each rider that actually got work.
|
||||
//
|
||||
// Best-effort and deliberately after the assignments are committed: the
|
||||
// optimizer is a separate service over the network, and it failing must
|
||||
// leave the bookings assigned rather than undoing the batch.
|
||||
sequenced := 0
|
||||
for _, r := range ridersAssigned(results) {
|
||||
if _, err := routing.SequenceMilerStops(r); err != nil {
|
||||
utils.Warn("HubBatchAssign: stop sequencing failed",
|
||||
"miler_userid", r, "error", err)
|
||||
continue
|
||||
}
|
||||
sequenced++
|
||||
return scopeBookingsToOwnTenant(c, q)
|
||||
},
|
||||
Riders: func(q *gorm.DB) *gorm.DB {
|
||||
return q.Where("hubid = ?", hubID)
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
utils.Error("HubBatchAssign: failed", "error", err)
|
||||
return utils.Internal(c, "failed to assign bookings")
|
||||
}
|
||||
|
||||
return utils.OK(c, fiber.Map{
|
||||
"assigned": assignedCount,
|
||||
"skipped": skippedCount,
|
||||
"riderssequenced": sequenced,
|
||||
"results": results,
|
||||
"assigned": result.Assigned,
|
||||
"skipped": result.Skipped,
|
||||
"riderssequenced": result.Riderssequenced,
|
||||
"results": result.Results,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user