backend requirements onthe xustomer app
This commit is contained in:
100
controllers/cxConsignmentHooks.go
Normal file
100
controllers/cxConsignmentHooks.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"doormile/constants"
|
||||
"doormile/internal/cxstage"
|
||||
"doormile/utils"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Per-order stages — the second half of §8.3.
|
||||
//
|
||||
// Stages 6-8 belong to each order rather than to the booking, and may differ
|
||||
// between destinations of the same pickup: one parcel out for delivery in
|
||||
// Chennai while another is still at a hub in Kerala. Each of the operational
|
||||
// writes that moves a consignment records its customer stage against the
|
||||
// destination that consignment belongs to, and the booking's own stage falls
|
||||
// back to the least-advanced of them.
|
||||
|
||||
// cxStageForConsignmentStatus maps an operational consignment status onto the
|
||||
// customer stage it means. Not every status has one: a parcel sitting on a
|
||||
// tripsheet, or one flagged missing, is still "in transit" as far as the
|
||||
// customer's seven milestones go, and inventing a stage for it would put a key
|
||||
// on the wire the client silently falls back to `booked` for.
|
||||
func cxStageForConsignmentStatus(status string) (string, bool) {
|
||||
switch status {
|
||||
case constants.ConsignmentInwardedAtHub,
|
||||
constants.ConsignmentTripsheetLoaded,
|
||||
constants.ConsignmentInTransit:
|
||||
return constants.CxStageInTransit, true
|
||||
case constants.ConsignmentOutForDelivery:
|
||||
return constants.CxStageOutForDelivery, true
|
||||
case constants.ConsignmentDelivered:
|
||||
return constants.CxStageDelivered, true
|
||||
default:
|
||||
// Created and Collected_By_Miler both mean "the order exists and is in
|
||||
// the rider's hands", which is order_created — already recorded at
|
||||
// pickup-complete, so there is nothing new to say.
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
|
||||
// recordCxConsignmentStage records the customer stage for one consignment,
|
||||
// inside the caller's transaction, and returns the notification to fire once
|
||||
// that transaction commits.
|
||||
//
|
||||
// The consignment is resolved to its destination through bookingdestinations,
|
||||
// not through pickupbookings.consignmentid. That column names only the FIRST
|
||||
// order of a multi-destination pickup, so a lookup through it finds nothing for
|
||||
// destinations 2..N — which would mean no stage advance and no notification on
|
||||
// every order after the first.
|
||||
//
|
||||
// A consignment that belongs to no customer booking at all — a console-created
|
||||
// express shipment — is a no-op, not an error. Those have no customer app
|
||||
// watching them.
|
||||
func recordCxConsignmentStage(tx *gorm.DB, consignmentID int, status string, actorType string, actorID *int, source string) (afterCommit func(), err error) {
|
||||
noop := func() {}
|
||||
|
||||
stage, ok := cxStageForConsignmentStatus(status)
|
||||
if !ok {
|
||||
return noop, nil
|
||||
}
|
||||
|
||||
dest, booking, found := cxDestinationForConsignment(consignmentID)
|
||||
if !found || booking == nil {
|
||||
return noop, nil
|
||||
}
|
||||
if booking.Bookingsource != constants.BookingSourceCustomerApp {
|
||||
return noop, nil
|
||||
}
|
||||
|
||||
destinationID := cxDestinationIDFor(dest)
|
||||
if err := cxstage.Record(tx, cxstage.Event{
|
||||
BookingID: booking.Bookingid,
|
||||
DestinationID: destinationID,
|
||||
Stage: stage,
|
||||
ActorType: actorType,
|
||||
ActorID: actorID,
|
||||
Source: source,
|
||||
At: utils.DBNow(),
|
||||
}); err != nil {
|
||||
return noop, err
|
||||
}
|
||||
|
||||
bookingID := booking.Bookingid
|
||||
return func() { go cxstage.Notify(bookingID, destinationID, stage) }, nil
|
||||
}
|
||||
|
||||
// cancelCxBookingFromOps stands a pickup down on behalf of a rider or an ops
|
||||
// user, recording who did it and why.
|
||||
//
|
||||
// A customer whose pickup disappears with no explanation has no way to tell a
|
||||
// cancellation from a bug, and support has no way to answer them — so the
|
||||
// actor and the reason are part of the write, not an afterthought.
|
||||
func cancelCxBookingFromOps(tx *gorm.DB, bookingID int, reason, actorType string, actorID *int, source string) error {
|
||||
if reason == "" {
|
||||
reason = "Cancelled by Doormile"
|
||||
}
|
||||
return cxstage.Cancel(tx, bookingID, reason, actorType, actorID, source)
|
||||
}
|
||||
Reference in New Issue
Block a user