package models import ( "time" ) type PickupBooking struct { 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 // (Bookingsource "CRM_Console"), since those are always made on behalf of // 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 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"` // Pickupsourcetype says what KIND of place this booking is collected from — // one of constants.PickupSource*. It is stored on the booking row, not looked // up from a location master, because a customer-door pickup has no location // id at all: only the row can tell "no location because it is a front door" // apart from "no location because nobody filled it in". Empty on rows written // before this column existed; derivePickupSourceType classifies those from // what they do carry, so the API never returns a blank type. Pickupsourcetype string `json:"pickup_source_type" gorm:"column:pickupsourcetype;size:20"` // Pickuphubid is set only when Pickupsourcetype is "hub" — the base the // parcel is collected FROM (Base → Customer). It is a separate column from // Nearesthubid, which is the base a parcel is routed TO. Conflating them // would make a base-origin booking look like a base-destination one. Pickuphubid *int `json:"pickuphubid" gorm:"column:pickuphubid;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"` // Arrival trace: written by the reached action when the rider is at the // pickup point. Nullable — a booking that was never reached has no arrival. // arrivallatitude/longitude are the rider's actual GPS at the moment they // tapped "arrived", kept as a durable record separate from live telemetry. // JSON name is reachedat (not arrivedat): the miler app, the /reached // response and the Admin Console all key off reachedat — the console derives // its "Arrived" display from Pickup_Scheduled + reachedat != null. The DB // column stays arrivedat. Arrivedat *time.Time `json:"reachedat" gorm:"column:arrivedat"` Arrivallatitude *float64 `json:"arrivallatitude" gorm:"column:arrivallatitude"` Arrivallongitude *float64 `json:"arrivallongitude" gorm:"column:arrivallongitude"` Consignmentid *int `json:"consignmentid" gorm:"column:consignmentid"` // Consignmentstatus is not a column — it is filled in by handlers that want // the live consignment status alongside the booking (e.g. the admin bookings // list, so a "Converted_To_Consignment" booking can still show // Out_for_Delivery / Delivered). omitempty keeps it out of every other // PickupBooking response that does not populate it. Consignmentstatus string `json:"consignmentstatus,omitempty" gorm:"-"` // Trackingno is not a column either — it lives on the consignment, which only // exists once the parcel is collected. It is filled in by handlers that serve // a customer, because without it the customer app has no way to reach // GET /customer/track/:trackingno at all: a booking is addressed by id, a // shipment by tracking number, and nothing joined the two. Trackingno string `json:"trackingno,omitempty" gorm:"-"` 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"` Payments []BookingPayment `json:"payments" gorm:"foreignKey:Bookingid"` } func (PickupBooking) TableName() string { return "pickupbookings" } type BookingParcel struct { Bookingparcelid int `json:"bookingparcelid" gorm:"primaryKey;column:bookingparcelid"` Bookingid int `json:"bookingid" gorm:"column:bookingid"` Itemcategory string `json:"itemcategory" gorm:"column:itemcategory"` Itemdescription string `json:"itemdescription" gorm:"column:itemdescription"` Declaredvalue float64 `json:"declaredvalue" gorm:"column:declaredvalue"` Weight float64 `json:"weight" gorm:"column:weight"` Length float64 `json:"length" gorm:"column:length"` Width float64 `json:"width" gorm:"column:width"` Height float64 `json:"height" gorm:"column:height"` Isfragile bool `json:"isfragile" gorm:"column:isfragile;default:false"` Needsinsurance bool `json:"needsinsurance" gorm:"column:needsinsurance;default:false"` Insuranceamount float64 `json:"insuranceamount" gorm:"column:insuranceamount;default:0.00"` Requireslargevehicle bool `json:"requireslargevehicle" gorm:"column:requireslargevehicle;default:false"` Suggestedvehicletype string `json:"suggestedvehicletype" gorm:"column:suggestedvehicletype"` Createdat time.Time `json:"createdat" gorm:"column:createdat;default:CURRENT_TIMESTAMP"` Updatedat time.Time `json:"updatedat" gorm:"column:updatedat;default:CURRENT_TIMESTAMP"` } func (BookingParcel) TableName() string { return "bookingparcels" } type BookingServiceOption struct { Bookingserviceid int `json:"bookingserviceid" gorm:"primaryKey;column:bookingserviceid"` Bookingid int `json:"bookingid" gorm:"column:bookingid"` Servicetype string `json:"servicetype" gorm:"column:servicetype"` // Normal, Fast, Superfast Estimatedprice float64 `json:"estimatedprice" gorm:"column:estimatedprice"` Estimateddeliveryat *time.Time `json:"estimateddeliveryat" gorm:"column:estimateddeliveryat"` Sladueat *time.Time `json:"sladueat" gorm:"column:sladueat"` Pricingid *int `json:"pricingid" gorm:"column:pricingid"` Createdat time.Time `json:"createdat" gorm:"column:createdat;default:CURRENT_TIMESTAMP"` } func (BookingServiceOption) TableName() string { return "bookingserviceoptions" } 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 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"` Paidat *time.Time `json:"paidat" gorm:"column:paidat"` Createdat time.Time `json:"createdat" gorm:"column:createdat;default:CURRENT_TIMESTAMP"` } func (BookingPayment) TableName() string { return "bookingpayments" } type BookingAssignment struct { Bookingassignmentid int `json:"bookingassignmentid" gorm:"primaryKey;column:bookingassignmentid"` Bookingid int `json:"bookingid" gorm:"column:bookingid"` Mileruserid int `json:"mileruserid" gorm:"column:mileruserid"` Assignedbyuserid *int `json:"assignedbyuserid" gorm:"column:assignedbyuserid"` Assignmentstatus string `json:"assignmentstatus" gorm:"column:assignmentstatus;default:Assigned"` // Assigned, Accepted, Rejected, Reassigned, Completed, Cancelled Assignedat time.Time `json:"assignedat" gorm:"column:assignedat;default:CURRENT_TIMESTAMP"` Acceptedat *time.Time `json:"acceptedat" gorm:"column:acceptedat"` Completedat *time.Time `json:"completedat" gorm:"column:completedat"` Remarks string `json:"remarks" gorm:"column:remarks"` AgentDecisionID *uint64 `json:"agent_decision_id,omitempty" gorm:"column:agent_decision_id"` Riderkms float64 `json:"riderkms" gorm:"column:riderkms;default:0"` Ridercharges float64 `json:"ridercharges" gorm:"column:ridercharges;default:0"` Bonuspoints int `json:"bonuspoints" gorm:"column:bonuspoints;default:0"` // Stop sequencing, written by internal/routing from the Route Optimization // API's road-network ordering. Step is 1..N across a rider's currently // active assignments — it says what order to run them in, which nothing in // Doormile decided before: assignment picked *who*, never *in what order*. // // Step 0 means "not sequenced yet", not "first". A rider with a single stop // is never sequenced, and sequencing is best-effort, so 0 is common and must // not be read as a position. Step int `json:"step" gorm:"column:step;default:0"` Previouskms float64 `json:"previouskms" gorm:"column:previouskms;default:0"` Cumulativekms float64 `json:"cumulativekms" gorm:"column:cumulativekms;default:0"` Etaminutes int `json:"etaminutes" gorm:"column:etaminutes;default:0"` Cumulativeeta int `json:"cumulativeeta" gorm:"column:cumulativeeta;default:0"` Sequencedat *time.Time `json:"sequencedat" gorm:"column:sequencedat"` } func (BookingAssignment) TableName() string { return "bookingassignments" } type BookingVehicleRequirement struct { Requirementid int `json:"requirementid" gorm:"primaryKey;column:requirementid"` Bookingid int `json:"bookingid" gorm:"column:bookingid"` 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"` 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 Createdat time.Time `json:"createdat" gorm:"column:createdat;default:CURRENT_TIMESTAMP"` Updatedat time.Time `json:"updatedat" gorm:"column:updatedat;default:CURRENT_TIMESTAMP"` } func (BookingVehicleRequirement) TableName() string { return "bookingvehiclerequirements" }