fix: per-site attribution needs its own column, not pickuplocationid
Caught by testing the previous commit against production: creating a booking with a resolved site failed with pickupbookings_pickuplocationid_fkey FOREIGN KEY (pickuplocationid) REFERENCES appcustomerlocations(...) pickuplocationid is the *customer's* saved address, a B2C concept. It never referred to the client company's own kitchens or branches. The pre-existing code that validated an incoming pickuplocationid against TenantLocation was wrong on the same point and would have 500'd for any caller that used it — it had simply never been called with a value. Adds tenantlocationid to pickupbookings and consignments (nullable, indexed, additive via AutoMigrate), carried across at pickup, and points the reporting filter, the by_location breakdown and the Unattributed bucket at it. The booking request accepts tenantlocationid, and still accepts pickuplocationid as an alias so anything written against the earlier docs starts working instead of failing. Also gofmt on the two model files touched; booking.go was already failing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,8 +5,8 @@ import (
|
||||
)
|
||||
|
||||
type PickupBooking struct {
|
||||
Bookingid int `json:"bookingid" gorm:"primaryKey;column:bookingid"`
|
||||
Bookingno string `json:"bookingno" gorm:"column:bookingno;unique;not null"`
|
||||
Bookingid int `json:"bookingid" gorm:"primaryKey;column:bookingid"`
|
||||
Bookingno string `json:"bookingno" gorm:"column:bookingno;unique;not null"`
|
||||
// Tenantid identifies which client company this booking is for. Nil for
|
||||
// direct B2C bookings (Bookingsource "Customer_App") that aren't attributed
|
||||
// to a tenant yet — see CreateCustomerBooking. Required for CRM bookings
|
||||
@@ -14,31 +14,39 @@ type PickupBooking struct {
|
||||
// a specific tenant. Propagated onto the resulting Consignment at pickup
|
||||
// time in BookingPickupComplete, instead of inferring it from whichever
|
||||
// miler happens to complete the pickup.
|
||||
Tenantid *int `json:"tenantid" gorm:"column:tenantid;index"`
|
||||
Appcustomerid int `json:"appcustomerid" gorm:"column:appcustomerid"`
|
||||
Pickuplocationid *int `json:"pickuplocationid" gorm:"column:pickuplocationid"`
|
||||
Pickupaddress string `json:"pickupaddress" gorm:"column:pickupaddress;not null"`
|
||||
Pickuppincode string `json:"pickuppincode" gorm:"column:pickuppincode;not null"`
|
||||
Pickuplatitude float64 `json:"pickuplatitude" gorm:"column:pickuplatitude;not null"`
|
||||
Pickuplongitude float64 `json:"pickuplongitude" gorm:"column:pickuplongitude;not null"`
|
||||
Deliveryaddress string `json:"deliveryaddress" gorm:"column:deliveryaddress;not null"`
|
||||
Deliverypincode string `json:"deliverypincode" gorm:"column:deliverypincode;not null"`
|
||||
Deliverylatitude float64 `json:"deliverylatitude" gorm:"column:deliverylatitude;not null"`
|
||||
Deliverylongitude float64 `json:"deliverylongitude" gorm:"column:deliverylongitude;not null"`
|
||||
Deliverycity string `json:"deliverycity" gorm:"column:deliverycity"`
|
||||
Nearesthubid *int `json:"nearesthubid" gorm:"column:nearesthubid"`
|
||||
Bookingsource string `json:"bookingsource" gorm:"column:bookingsource;default:Customer_App"`
|
||||
Providercompany string `json:"providercompany" gorm:"column:providercompany"`
|
||||
Providerlocation string `json:"providerlocation" gorm:"column:providerlocation"`
|
||||
Notes string `json:"notes" gorm:"column:notes"`
|
||||
Status string `json:"status" gorm:"column:status;default:Created"` // Created, Miler_Assigned, Pickup_Scheduled, Picked_Up, Converted_To_Consignment, Cancelled
|
||||
Preferredpickupfrom *time.Time `json:"preferredpickupfrom" gorm:"column:preferredpickupfrom"`
|
||||
Preferredpickupto *time.Time `json:"preferredpickupto" gorm:"column:preferredpickupto"`
|
||||
Assignedmileruserid *int `json:"assignedmileruserid" gorm:"column:assignedmileruserid"`
|
||||
Consignmentid *int `json:"consignmentid" gorm:"column:consignmentid"`
|
||||
Createdat time.Time `json:"createdat" gorm:"column:createdat;default:CURRENT_TIMESTAMP"`
|
||||
Updatedat time.Time `json:"updatedat" gorm:"column:updatedat;default:CURRENT_TIMESTAMP"`
|
||||
|
||||
Tenantid *int `json:"tenantid" gorm:"column:tenantid;index"`
|
||||
Appcustomerid int `json:"appcustomerid" gorm:"column:appcustomerid"`
|
||||
// Pickuplocationid is the *customer's* saved address the parcel was collected
|
||||
// from — it carries a foreign key to appcustomerlocations. It is a B2C
|
||||
// concept and has nothing to do with the client company's own sites.
|
||||
Pickuplocationid *int `json:"pickuplocationid" gorm:"column:pickuplocationid"`
|
||||
// Tenantlocationid is the *client's* site: the kitchen, branch or depot the
|
||||
// parcel came out of. Separate column because pickuplocationid points at a
|
||||
// different table entirely; writing a tenantlocations id into it violates
|
||||
// that foreign key. This is what per-site reporting groups by.
|
||||
Tenantlocationid *int `json:"tenantlocationid" gorm:"column:tenantlocationid;index"`
|
||||
Pickupaddress string `json:"pickupaddress" gorm:"column:pickupaddress;not null"`
|
||||
Pickuppincode string `json:"pickuppincode" gorm:"column:pickuppincode;not null"`
|
||||
Pickuplatitude float64 `json:"pickuplatitude" gorm:"column:pickuplatitude;not null"`
|
||||
Pickuplongitude float64 `json:"pickuplongitude" gorm:"column:pickuplongitude;not null"`
|
||||
Deliveryaddress string `json:"deliveryaddress" gorm:"column:deliveryaddress;not null"`
|
||||
Deliverypincode string `json:"deliverypincode" gorm:"column:deliverypincode;not null"`
|
||||
Deliverylatitude float64 `json:"deliverylatitude" gorm:"column:deliverylatitude;not null"`
|
||||
Deliverylongitude float64 `json:"deliverylongitude" gorm:"column:deliverylongitude;not null"`
|
||||
Deliverycity string `json:"deliverycity" gorm:"column:deliverycity"`
|
||||
Nearesthubid *int `json:"nearesthubid" gorm:"column:nearesthubid"`
|
||||
Bookingsource string `json:"bookingsource" gorm:"column:bookingsource;default:Customer_App"`
|
||||
Providercompany string `json:"providercompany" gorm:"column:providercompany"`
|
||||
Providerlocation string `json:"providerlocation" gorm:"column:providerlocation"`
|
||||
Notes string `json:"notes" gorm:"column:notes"`
|
||||
Status string `json:"status" gorm:"column:status;default:Created"` // Created, Miler_Assigned, Pickup_Scheduled, Picked_Up, Converted_To_Consignment, Cancelled
|
||||
Preferredpickupfrom *time.Time `json:"preferredpickupfrom" gorm:"column:preferredpickupfrom"`
|
||||
Preferredpickupto *time.Time `json:"preferredpickupto" gorm:"column:preferredpickupto"`
|
||||
Assignedmileruserid *int `json:"assignedmileruserid" gorm:"column:assignedmileruserid"`
|
||||
Consignmentid *int `json:"consignmentid" gorm:"column:consignmentid"`
|
||||
Createdat time.Time `json:"createdat" gorm:"column:createdat;default:CURRENT_TIMESTAMP"`
|
||||
Updatedat time.Time `json:"updatedat" gorm:"column:updatedat;default:CURRENT_TIMESTAMP"`
|
||||
|
||||
// Relations
|
||||
Parcels []BookingParcel `json:"parcels" gorm:"foreignKey:Bookingid"`
|
||||
ServiceOptions []BookingServiceOption `json:"serviceoptions" gorm:"foreignKey:Bookingid"`
|
||||
@@ -91,7 +99,7 @@ type BookingPayment struct {
|
||||
Bookingpaymentid int `json:"bookingpaymentid" gorm:"primaryKey;column:bookingpaymentid"`
|
||||
Bookingid int `json:"bookingid" gorm:"column:bookingid"`
|
||||
Amount float64 `json:"amount" gorm:"column:amount;not null"`
|
||||
Paymentmode string `json:"paymentmode" gorm:"column:paymentmode"` // Cash, UPI, Card, Wallet
|
||||
Paymentmode string `json:"paymentmode" gorm:"column:paymentmode"` // Cash, UPI, Card, Wallet
|
||||
Paymentstatus string `json:"paymentstatus" gorm:"column:paymentstatus;default:Pending"` // Pending, Paid, Failed, Refunded
|
||||
Collectedbyuserid *int `json:"collectedbyuserid" gorm:"column:collectedbyuserid"`
|
||||
Transactionref string `json:"transactionref" gorm:"column:transactionref"`
|
||||
@@ -129,8 +137,8 @@ type BookingVehicleRequirement struct {
|
||||
Requiredvehicletype string `json:"requiredvehicletype" gorm:"column:requiredvehicletype;not null"`
|
||||
Reason string `json:"reason" gorm:"column:reason"`
|
||||
Nearesthubid *int `json:"nearesthubid" gorm:"column:nearesthubid"`
|
||||
Scheduledpickupfrom *time.Time `json:"scheduledpickupfrom" gorm:"column:scheduledpickupfrom"`
|
||||
Scheduledpickupto *time.Time `json:"scheduledpickupto" gorm:"column:scheduledpickupto"`
|
||||
Scheduledpickupfrom *time.Time `json:"scheduledpickupfrom" gorm:"column:scheduledpickupfrom"`
|
||||
Scheduledpickupto *time.Time `json:"scheduledpickupto" gorm:"column:scheduledpickupto"`
|
||||
Assignedvehicleid *int `json:"assignedvehicleid" gorm:"column:assignedvehicleid"`
|
||||
Assigneddriveruserid *int `json:"assigneddriveruserid" gorm:"column:assigneddriveruserid"`
|
||||
Status string `json:"status" gorm:"column:status;default:Required"` // Required, Scheduled, Assigned, Arrived, Picked_Up, Cancelled
|
||||
|
||||
Reference in New Issue
Block a user