The admin customer page collected an address (door no, street, suburb, city, state, postcode, landmark, lat/lng) that the backend had nowhere to store, so it was silently dropped on save. Add those fields flat onto appcustomers, matching the reference console's shape, plus an applocationid for zone scoping. - GET /admin/customers: add ?applocationid= filter; emit firstname/lastname split and the address fields alongside the existing joined name. - GET /admin/customers/summary (new): stat-tile counts (total/active/blocked) scoped like the list, so the client stops deriving them from the full page. - PATCH /admin/customers/🆔 accept firstname/lastname directly (single name still splits as a fallback) and persist every address field; pointer fields so an omitted field is not confused with one cleared to empty. Pagination and keyword search were already present. Additive, nullable columns — AutoMigrate handles it, no data rewrite. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
261 lines
15 KiB
Go
261 lines
15 KiB
Go
package models
|
|
|
|
import (
|
|
"time"
|
|
)
|
|
|
|
type PartnerInfo struct {
|
|
Partnerid int `json:"partnerid" gorm:"primaryKey;column:partnerid"`
|
|
Partnername string `json:"partnername" gorm:"column:partnername;not null"`
|
|
Partnertypeid int `json:"partnertypeid" gorm:"column:partnertypeid"`
|
|
Contactno string `json:"contactno" gorm:"column:contactno"`
|
|
Status string `json:"status" gorm:"column:status;default:Active"`
|
|
Createdat time.Time `json:"createdat" gorm:"column:createdat;default:CURRENT_TIMESTAMP"`
|
|
Updatedat time.Time `json:"updatedat" gorm:"column:updatedat;default:CURRENT_TIMESTAMP"`
|
|
}
|
|
|
|
func (PartnerInfo) TableName() string {
|
|
return "partnerinfo"
|
|
}
|
|
|
|
type Hub struct {
|
|
Hubid int `json:"hubid" gorm:"primaryKey;column:hubid"`
|
|
Hubname string `json:"hubname" gorm:"column:hubname;not null"`
|
|
Hubtype string `json:"hubtype" gorm:"column:hubtype;not null"` // sorting_center, delivery_hub
|
|
Applocationid int `json:"applocationid" gorm:"column:applocationid"`
|
|
Contactno string `json:"contactno" gorm:"column:contactno"`
|
|
Address string `json:"address" gorm:"column:address"`
|
|
Latitude float64 `json:"latitude" gorm:"column:latitude"`
|
|
Longitude float64 `json:"longitude" gorm:"column:longitude"`
|
|
Pincode string `json:"pincode" gorm:"column:pincode"`
|
|
Capacity int `json:"capacity" gorm:"column:capacity;default:50"`
|
|
Status string `json:"status" gorm:"column:status;default:Active"` // Active, InActive
|
|
Createdat time.Time `json:"createdat" gorm:"column:createdat;default:CURRENT_TIMESTAMP"`
|
|
Updatedat time.Time `json:"updatedat" gorm:"column:updatedat;default:CURRENT_TIMESTAMP"`
|
|
Createdby int `json:"createdby" gorm:"column:createdby"`
|
|
Updatedby int `json:"updatedby" gorm:"column:updatedby"`
|
|
Deletedat *time.Time `json:"deletedat,omitempty" gorm:"column:deletedat"`
|
|
}
|
|
|
|
func (Hub) TableName() string {
|
|
return "hubs"
|
|
}
|
|
|
|
type Vehicle struct {
|
|
Vehicleid int `json:"vehicleid" gorm:"primaryKey;column:vehicleid"`
|
|
Vehicleno string `json:"vehicleno" gorm:"primaryKey;column:vehicleno;unique;not null"`
|
|
Vehicletype string `json:"vehicletype" gorm:"column:vehicletype;not null"`
|
|
Maxweight float64 `json:"maxweight" gorm:"column:maxweight;not null"`
|
|
Maxvolume float64 `json:"maxvolume" gorm:"column:maxvolume;not null"`
|
|
Partnerid *int `json:"partnerid" gorm:"column:partnerid"`
|
|
Batterypercentage int `json:"batterypercentage" gorm:"column:batterypercentage"`
|
|
Status string `json:"status" gorm:"column:status;default:Available"` // Available, In_Transit, Maintenance, InActive
|
|
Createdat time.Time `json:"createdat" gorm:"column:createdat;default:CURRENT_TIMESTAMP"`
|
|
Updatedat time.Time `json:"updatedat" gorm:"column:updatedat;default:CURRENT_TIMESTAMP"`
|
|
Createdby int `json:"createdby" gorm:"column:createdby"`
|
|
Updatedby int `json:"updatedby" gorm:"column:updatedby"`
|
|
Deletedat *time.Time `json:"deletedat,omitempty" gorm:"column:deletedat"`
|
|
}
|
|
|
|
func (Vehicle) TableName() string {
|
|
return "vehicles"
|
|
}
|
|
|
|
type AppUser struct {
|
|
Userid int `json:"userid" gorm:"primaryKey;column:userid"`
|
|
Authname string `json:"authname" gorm:"column:authname;not null"`
|
|
Email string `json:"email" gorm:"column:email;unique;not null"`
|
|
Contactno string `json:"contactno" gorm:"column:contactno;not null"`
|
|
Password string `json:"-" gorm:"column:password;not null"`
|
|
Roleid int `json:"roleid" gorm:"column:roleid;not null"`
|
|
Hubid *int `json:"hubid" gorm:"column:hubid"`
|
|
Applocationid int `json:"applocationid" gorm:"column:applocationid"`
|
|
Partnerid *int `json:"partnerid" gorm:"column:partnerid"`
|
|
Tenantid int `json:"tenantid" gorm:"column:tenantid"`
|
|
Configid int `json:"configid" gorm:"column:configid;default:1"`
|
|
Onduty int `json:"onduty" gorm:"column:onduty;default:0"`
|
|
Status string `json:"status" gorm:"column:status;default:Active"`
|
|
Createdat time.Time `json:"createdat" gorm:"column:createdat;default:CURRENT_TIMESTAMP"`
|
|
Updatedat time.Time `json:"updatedat" gorm:"column:updatedat;default:CURRENT_TIMESTAMP"`
|
|
}
|
|
|
|
func (AppUser) TableName() string {
|
|
return "appusers"
|
|
}
|
|
|
|
type MilerProfile struct {
|
|
Milerprofileid int `json:"milerprofileid" gorm:"primaryKey;column:milerprofileid"`
|
|
Userid int `json:"userid" gorm:"column:userid;unique;not null"`
|
|
Applocationid int `json:"applocationid" gorm:"column:applocationid;default:1"`
|
|
Displayname string `json:"displayname" gorm:"column:displayname;not null"`
|
|
Phone string `json:"phone" gorm:"column:phone;not null"`
|
|
Profilephotourl string `json:"profilephotourl" gorm:"column:profilephotourl"`
|
|
Vehicleid *int `json:"vehicleid" gorm:"column:vehicleid"`
|
|
Hubid *int `json:"hubid" gorm:"column:hubid"`
|
|
// Legacyuserid holds this rider's userid in the old jupiter system for the
|
|
// six riders migrated from it. Nothing reads it any more — the jupiter
|
|
// telemetry bridge it existed for was removed — but it is kept as a record
|
|
// of where each migrated rider came from, which is worth having during the
|
|
// cutover. Nil for riders created natively in Doormile.
|
|
Legacyuserid *int `json:"legacyuserid,omitempty" gorm:"column:legacyuserid;index"`
|
|
Defaultvehicletype string `json:"defaultvehicletype" gorm:"column:defaultvehicletype"`
|
|
Currentlatitude float64 `json:"currentlatitude" gorm:"column:currentlatitude"`
|
|
Currentlongitude float64 `json:"currentlongitude" gorm:"column:currentlongitude"`
|
|
Currentpincode string `json:"currentpincode" gorm:"column:currentpincode"`
|
|
Availabilitystatus string `json:"availabilitystatus" gorm:"column:availabilitystatus;default:Offline"` // Offline, Available, Assigned, On_Pickup, At_Customer, Picked_Up, On_Delivery, Break, Blocked
|
|
Rating float64 `json:"rating" gorm:"column:rating;default:5.00"`
|
|
Totalcompletedpickups int `json:"totalcompletedpickups" gorm:"column:totalcompletedpickups;default:0"`
|
|
Totalcancelledpickups int `json:"totalcancelledpickups" gorm:"column:totalcancelledpickups;default:0"`
|
|
Devicetoken string `json:"device_token,omitempty" gorm:"column:device_token"`
|
|
Lastlocationupdatedat *time.Time `json:"lastlocationupdatedat" gorm:"column:lastlocationupdatedat"`
|
|
Createdat time.Time `json:"createdat" gorm:"column:createdat;default:CURRENT_TIMESTAMP"`
|
|
Updatedat time.Time `json:"updatedat" gorm:"column:updatedat;default:CURRENT_TIMESTAMP"`
|
|
}
|
|
|
|
func (MilerProfile) TableName() string {
|
|
return "milerprofiles"
|
|
}
|
|
|
|
type AppCustomer struct {
|
|
Appcustomerid int `json:"appcustomerid" gorm:"primaryKey;column:appcustomerid"`
|
|
Firstname string `json:"firstname" gorm:"column:firstname;not null"`
|
|
Lastname string `json:"lastname" gorm:"column:lastname"`
|
|
Phone string `json:"phone" gorm:"column:phone;unique;not null"`
|
|
Email string `json:"email" gorm:"column:email"`
|
|
Loginpinhash string `json:"-" gorm:"column:loginpinhash"`
|
|
Defaultlatitude float64 `json:"defaultlatitude" gorm:"column:defaultlatitude"`
|
|
Defaultlongitude float64 `json:"defaultlongitude" gorm:"column:defaultlongitude"`
|
|
Defaultpincode string `json:"defaultpincode" gorm:"column:defaultpincode"`
|
|
// Flat address on the customer record, kept for parity with the console's
|
|
// customer page (the reference stored the address this way). Separate from
|
|
// the normalized appcustomerlocations table, which holds a customer's many
|
|
// saved delivery addresses; this is the single profile address the console
|
|
// edits.
|
|
Doorno string `json:"doorno" gorm:"column:doorno"`
|
|
Address string `json:"address" gorm:"column:address"`
|
|
Suburb string `json:"suburb" gorm:"column:suburb"`
|
|
City string `json:"city" gorm:"column:city"`
|
|
State string `json:"state" gorm:"column:state"`
|
|
Postcode string `json:"postcode" gorm:"column:postcode"`
|
|
Landmark string `json:"landmark" gorm:"column:landmark"`
|
|
Latitude float64 `json:"latitude" gorm:"column:latitude"`
|
|
Longitude float64 `json:"longitude" gorm:"column:longitude"`
|
|
Applocationid int `json:"applocationid" gorm:"column:applocationid"` // city/zone, for console scoping
|
|
Devicetoken string `json:"device_token,omitempty" gorm:"column:device_token"`
|
|
Status string `json:"status" gorm:"column:status;default:Active"` // Active, Blocked, Deleted
|
|
Configid int `json:"configid" gorm:"column:configid;default:1"`
|
|
Lastloginat *time.Time `json:"lastloginat" gorm:"column:lastloginat"`
|
|
Createdat time.Time `json:"createdat" gorm:"column:createdat;default:CURRENT_TIMESTAMP"`
|
|
Updatedat time.Time `json:"updatedat" gorm:"column:updatedat;default:CURRENT_TIMESTAMP"`
|
|
}
|
|
|
|
func (AppCustomer) TableName() string {
|
|
return "appcustomers"
|
|
}
|
|
|
|
type AppCustomerLocation struct {
|
|
Appcustomerlocationid int `json:"appcustomerlocationid" gorm:"primaryKey;column:appcustomerlocationid"`
|
|
Appcustomerid int `json:"appcustomerid" gorm:"column:appcustomerid"`
|
|
Label string `json:"label" gorm:"column:label;default:Home"`
|
|
Receivername string `json:"receivername" gorm:"column:receivername"`
|
|
Receiverphone string `json:"receiverphone" gorm:"column:receiverphone"`
|
|
Address string `json:"address" gorm:"column:address;not null"`
|
|
Landmark string `json:"landmark" gorm:"column:landmark"`
|
|
City string `json:"city" gorm:"column:city"`
|
|
State string `json:"state" gorm:"column:state"`
|
|
Pincode string `json:"pincode" gorm:"column:pincode;not null"`
|
|
Latitude float64 `json:"latitude" gorm:"column:latitude;not null"`
|
|
Longitude float64 `json:"longitude" gorm:"column:longitude;not null"`
|
|
Isdefault bool `json:"isdefault" gorm:"column:isdefault;default:false"`
|
|
Status string `json:"status" gorm:"column:status;default:Active"`
|
|
Createdat time.Time `json:"createdat" gorm:"column:createdat;default:CURRENT_TIMESTAMP"`
|
|
Updatedat time.Time `json:"updatedat" gorm:"column:updatedat;default:CURRENT_TIMESTAMP"`
|
|
}
|
|
|
|
func (AppCustomerLocation) TableName() string {
|
|
return "appcustomerlocations"
|
|
}
|
|
|
|
type TenantLocation struct {
|
|
Tenantlocationid int `json:"tenantlocationid" gorm:"primaryKey;column:tenantlocationid"`
|
|
Tenantid int `json:"tenantid" gorm:"column:tenantid;not null"`
|
|
Locationname string `json:"locationname" gorm:"column:locationname"`
|
|
Address string `json:"address" gorm:"column:address;not null"`
|
|
City string `json:"city" gorm:"column:city;not null"`
|
|
State string `json:"state" gorm:"column:state;not null"`
|
|
Pincode string `json:"pincode" gorm:"column:pincode;not null"`
|
|
Latitude float64 `json:"latitude" gorm:"column:latitude;not null"`
|
|
Longitude float64 `json:"longitude" gorm:"column:longitude;not null"`
|
|
Isprimary bool `json:"isprimary" gorm:"column:isprimary;default:false"`
|
|
Status string `json:"status" gorm:"column:status;default:Active"`
|
|
Createdat time.Time `json:"createdat" gorm:"column:createdat;default:CURRENT_TIMESTAMP"`
|
|
Updatedat time.Time `json:"updatedat" gorm:"column:updatedat;default:CURRENT_TIMESTAMP"`
|
|
}
|
|
|
|
func (TenantLocation) TableName() string {
|
|
return "tenantlocations"
|
|
}
|
|
|
|
type HubStaffAccount struct {
|
|
Hubstaffaccountid int `json:"hubstaffaccountid" gorm:"primaryKey;column:hubstaffaccountid"`
|
|
Hubid int `json:"hubid" gorm:"column:hubid;index;not null"`
|
|
Email string `json:"email" gorm:"column:email;unique;not null"`
|
|
Passwordhash string `json:"-" gorm:"column:passwordhash;not null"`
|
|
Displayname string `json:"displayname" gorm:"column:displayname"`
|
|
Roleid int `json:"roleid" gorm:"column:roleid;default:6"`
|
|
Isactive bool `json:"isactive" gorm:"column:isactive;default:true"`
|
|
Tenantid *int `json:"tenantid" gorm:"column:tenantid;index"` // null = Doormile staff (can manage any hub in their city); set = partner staff scoped to their own hub
|
|
Createdat time.Time `json:"createdat" gorm:"column:createdat;default:CURRENT_TIMESTAMP"`
|
|
Updatedat time.Time `json:"updatedat" gorm:"column:updatedat;default:CURRENT_TIMESTAMP"`
|
|
}
|
|
|
|
func (HubStaffAccount) TableName() string {
|
|
return "hubstaffaccounts"
|
|
}
|
|
|
|
type MilerDutyLog struct {
|
|
Dutylogid int `json:"dutylogid" gorm:"primaryKey;column:dutylogid"`
|
|
Userid int `json:"userid" gorm:"column:userid;index;not null"`
|
|
Loginat time.Time `json:"loginat" gorm:"column:loginat;not null"`
|
|
Logoutat *time.Time `json:"logoutat" gorm:"column:logoutat"`
|
|
Onduty bool `json:"onduty" gorm:"column:onduty;default:true"`
|
|
Startlat float64 `json:"startlat" gorm:"column:startlat"`
|
|
Startlon float64 `json:"startlon" gorm:"column:startlon"`
|
|
Lastlat float64 `json:"lastlat" gorm:"column:lastlat"`
|
|
Lastlon float64 `json:"lastlon" gorm:"column:lastlon"`
|
|
Totalkms float64 `json:"totalkms" gorm:"column:totalkms;default:0"`
|
|
Createdat time.Time `json:"createdat" gorm:"column:createdat;default:CURRENT_TIMESTAMP"`
|
|
}
|
|
|
|
func (MilerDutyLog) TableName() string {
|
|
return "milerdutylogs"
|
|
}
|
|
|
|
type MilerBreakLog struct {
|
|
Breaklogid int `json:"breaklogid" gorm:"primaryKey;column:breaklogid"`
|
|
Userid int `json:"userid" gorm:"column:userid;index;not null"`
|
|
Dutylogid int `json:"dutylogid" gorm:"column:dutylogid;not null"`
|
|
Breaktype string `json:"breaktype" gorm:"column:breaktype;default:Personal"`
|
|
Startat time.Time `json:"startat" gorm:"column:startat;not null"`
|
|
Endat *time.Time `json:"endat" gorm:"column:endat"`
|
|
Createdat time.Time `json:"createdat" gorm:"column:createdat;default:CURRENT_TIMESTAMP"`
|
|
}
|
|
|
|
func (MilerBreakLog) TableName() string {
|
|
return "milerbreaklogs"
|
|
}
|
|
|
|
type MilerSupportTicket struct {
|
|
Ticketid int `json:"ticketid" gorm:"primaryKey;column:ticketid"`
|
|
Userid int `json:"userid" gorm:"column:userid;index;not null"`
|
|
Subject string `json:"subject" gorm:"column:subject;size:200;not null"`
|
|
Description string `json:"description" gorm:"column:description;type:text;not null"`
|
|
Status string `json:"status" gorm:"column:status;default:Open"`
|
|
Createdat time.Time `json:"createdat" gorm:"column:createdat;default:CURRENT_TIMESTAMP"`
|
|
Updatedat time.Time `json:"updatedat" gorm:"column:updatedat;default:CURRENT_TIMESTAMP"`
|
|
}
|
|
|
|
func (MilerSupportTicket) TableName() string {
|
|
return "milersupporttickets"
|
|
}
|