Files
backend_fiesta/models/order.go
2026-07-30 17:25:09 +05:30

553 lines
22 KiB
Go

package models
import (
"database/sql/driver"
"encoding/json"
"fmt"
"strconv"
"gorm.io/gorm"
)
// FlexibleString handles JSON that could be either a number or a string,
// and ensures it can be saved/read from the database as a string.
type FlexibleString string
func (fs *FlexibleString) UnmarshalJSON(b []byte) error {
if len(b) == 0 {
return nil
}
// If it's a string in JSON
if b[0] == '"' {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}
*fs = FlexibleString(s)
return nil
}
// If it's a number in JSON
var f float64
if err := json.Unmarshal(b, &f); err != nil {
return err
}
*fs = FlexibleString(strconv.FormatFloat(f, 'f', -1, 64))
return nil
}
func (fs FlexibleString) MarshalJSON() ([]byte, error) {
return json.Marshal(string(fs))
}
// 🔥 Database Logic: Handle reading from DB
func (fs *FlexibleString) Scan(value interface{}) error {
if value == nil {
*fs = ""
return nil
}
switch v := value.(type) {
case []byte:
*fs = FlexibleString(v)
case string:
*fs = FlexibleString(v)
case float64:
*fs = FlexibleString(strconv.FormatFloat(v, 'f', -1, 64))
case int64:
*fs = FlexibleString(strconv.FormatInt(v, 10))
default:
*fs = FlexibleString(fmt.Sprintf("%v", v))
}
return nil
}
// 🔥 Database Logic: Handle writing to DB
func (fs FlexibleString) Value() (driver.Value, error) {
return string(fs), nil
}
func (fs FlexibleString) String() string {
return string(fs)
}
type OrderInfo struct {
Orderheaderid int `json:"orderheaderid"`
Applocationid int `json:"applocationid"`
Applocation string `json:"applocation"`
Tenantid int `json:"tenantid"`
Partnerid int `json:"partnerid"`
Locationid int `json:"locationid"`
Categoryid int `json:"categoryid"`
Subcategoryid int `json:"subcategoryid"`
Moduleid int `json:"moduleid"`
Configid int `json:"configid"`
Orderid string `json:"orderid"`
Orderdate string `json:"orderdate"`
Deliverydate string `json:"deliverydate"`
Orderstatus string `json:"orderstatus"`
Deliverystatus string `json:"deliverystatus"`
Deliveryamt float64 `json:"deliveryamt"`
Itemcount int `json:"itemcount"`
Ordernotes string `json:"ordernotes"`
Kms FlexibleString `json:"kms"`
Actualkms FlexibleString `json:"actualkms"`
Pending string `json:"Pending"`
Processing string `json:"processing"`
Ready string `json:"ready"`
Cancelled string `json:"cancelled"`
Delivered string `json:"delivered"`
Assigntime string `json:"assigntime"`
Starttime string `json:"starttime"`
Arrivaltime string `json:"arrivaltime"`
Pickuptime string `json:"pickuptime"`
Deliverytime string `json:"deliverytime"`
Canceltime string `json:"canceltime"`
Deliverycharge float32 `json:"deliverycharge"`
Orderamount float32 `json:"orderamount"`
Customerid int `json:"customerid"`
Pickupcustomer string `json:"pickupcustomer"`
Pickupcontactno string `json:"pickupcontactno"`
Pickuplocationid int `json:"pickuplocationid"`
Pickupaddress string `json:"pickupaddress"`
Pickupsuburb string `json:"pickupsuburb"`
Pickupcity string `json:"pickupcity"`
Pickuplat FlexibleString `json:"pickuplat"`
Pickuplong FlexibleString `json:"pickuplong"`
Deliveryid int `json:"deliveryid"`
Deliverycustomerid int `json:"deliverycustomerid"`
Deliverycustomer string `json:"deliverycustomer"`
Deliverycontactno string `json:"deliverycontactno"`
Deliverylocationid int `json:"deliverylocationid"`
Deliveryaddress string `json:"deliveryaddress"`
Deliverysuburb string `json:"deliverysuburb"`
Droplat FlexibleString `json:"droplat"`
Droplon FlexibleString `json:"droplon"`
Deliverylat FlexibleString `json:"deliverylat"`
Deliverylong FlexibleString `json:"deliverylong"`
Deliverytype string `json:"deliverytype"`
Paymenttype int `json:"paymenttype"`
Tenantname string `json:"tenantname"`
Tenanttoken string `json:"tenanttoken"`
Tenantsuburb string `json:"tenantsuburb"`
Tenantcity string `json:"tenantcity"`
Tenantcontactno string `json:"tenantcontactno"`
Tenantpostcode string `json:"tenantpostcode"`
Locationname string `json:"locationname"`
Locationsuburb string `json:"locationsuburb"`
Locationcity string `json:"locationcity"`
Locationcontactno string `json:"locationcontactno"`
Rider string `json:"rider"`
Ridercontactno string `json:"ridercontactno"`
Riderkms FlexibleString `json:"riderkms"`
Smsdelivery int `json:"smsdelivery"`
Customertoken string `json:"customertoken"`
Ridertoken string `json:"ridertoken"`
}
type DeliveryQuery struct {
Tenantid int
Customerid int
Partnerid int
UserID int
Appuserid int
Applocationid int
Moduleid int
Locationid int
Configid int
Fromdate string
ToDate string
Status string
Pageno int
Pagesize int
Conn *gorm.DB
Keyword string `json:"keyword"`
}
type Ordersummary struct {
Total int `json:"total"`
Created int `json:"created"`
Pending int `json:"pending"`
Processing int `json:"processing"`
Delivered int `json:"delivered"`
Cancelled int `json:"cancelled"`
// Locationid int `json:"locationid"`
Locationname string `json:"locationname"`
Applocationid string `json:"applocationid"`
}
type Ordersummarylocation struct {
Total int `json:"total"`
Created int `json:"created"`
Pending int `json:"pending"`
Processing int `json:"processing"`
Delivered int `json:"delivered"`
Cancelled int `json:"cancelled"`
Locationid int `json:"locationid"`
Locationname string `json:"locationname"`
}
type Ordersummarydaily struct {
Total int `json:"total"`
Created int `json:"created"`
Pending int `json:"pending"`
Processing int `json:"processing"`
Delivered int `json:"delivered"`
Cancelled int `json:"cancelled"`
Tenantid int `json:"tenantid"`
Tenantname string `json:"tenantname"`
Locationid int `json:"locationid"`
Locationname string `json:"locationname"`
}
type OrderInsight struct {
Applocationid int `json:"applocationid" gorm:"Primary_Key"`
Locationname string `json:"locationname"`
Ordermonths *Ordermonths `json:"ordermonths" gorm:"-"`
}
type OrderInsightv1 struct {
Locationid int `json:"locationid" gorm:"Primary_Key"`
Locationname string `json:"locationname"`
Ordermonths *Ordermonths `json:"ordermonths" gorm:"-"`
}
type Ordermonths struct {
Jan int `json:"jan"`
Feb int `json:"feb"`
Mar int `json:"mar"`
Apr int `json:"apr"`
May int `json:"may"`
Jun int `json:"jun"`
Jul int `json:"jul"`
Aug int `Json:"aug"`
Sep int `Json:"sep"`
Oct int `Json:"oct"`
Nov int `Json:"nov"`
Dece int `Json:"dece"`
// Applocationid int `json:"applocationid"`
}
type Orders struct {
Orderheaderid int `json:"orderheaderid" gorm:"Primary_Key"`
Tenantid int `json:"tenantid"`
Locationid int `json:"locationid"`
Applocationid int `json:"applocationid"`
Moduleid int `json:"moduleid"`
Partnerid int `json:"partnerid"`
Configid int `json:"configid"`
Categoryid int `json:"categoryid"`
Subcategoryid int `json:"subcategoryid"`
Orderid string `json:"orderid"`
Orderdate string `json:"orderdate,omitempty"`
Deliverytime string `json:"deliverytime"`
Deliverytype string `json:"deliverytype"`
Orderstatus string `json:"orderstatus"`
Pending string `json:"pending"`
Processing string `json:"processing"`
Ready string `json:"ready"`
Delivered string `json:"delivered"`
Cancelled string `json:"cancelled"`
Customerid int `json:"customerid"`
Pickupaddress string `json:"pickupaddress"`
Pickuplat FlexibleString `json:"pickuplat"`
Pickuplong FlexibleString `json:"pickuplong"`
Pickupcustomer string `json:"pickupcustomer"`
Pickupcontactno string `json:"pickupcontactno"`
Pickuplocation string `json:"pickupsuburb"` // alias
Pickupcity string `json:"pickupcity"`
Deliveryid int `json:"deliverycustomerid"` // alias
Deliverycustomer string `json:"deliverycustomer"`
Deliverycontactno string `json:"deliverycontactno"`
Deliveryaddress string `json:"deliveryaddress"`
Deliverylocation string `json:"deliverylocation"`
Deliverycity string `json:"deliverycity"`
Deliverylocationid int `json:"deliverylocationid"`
Deliverylat FlexibleString `json:"deliverylat"`
Deliverylong FlexibleString `json:"deliverylong"`
Promotionid int `json:"promotionid"`
Promoname string `json:"promoname"`
Promoterms string `json:"promoterms"`
Promovalue int `json:"promovalue"`
Promoamount float32 `json:"promoamount"`
Orderamount float32 `json:"orderamount"`
Taxamount float32 `json:"taxamount"`
Ordercharges float32 `json:"ordercharges"`
Ordervalue float32 `json:"ordervalue"`
Itemcount int `json:"itemcount"`
Paymenttype int `json:"paymenttype"`
Paymentstatus int `json:"paymentstatus"`
Deliverycharge float32 `json:"deliverycharge"`
Ordernotes string `json:"ordernotes"`
Kms FlexibleString `json:"kms"`
Remarks string `json:"remarks"`
Tenantuserid int `json:"tenantuserid"`
Partneruserid int `json:"partneruserid"`
Smsdelivery int `json:"smsdelivery" gorm:"default:0"`
Items []OrderDetail `json:"items" gorm:"-"`
}
type OrderDetails struct {
Orderdetailid int `json:"orderdetailid" gorm:"primaryKey;autoIncrement"`
Orderheaderid int `json:"orderheaderid"`
Tenantid int `json:"tenantid"`
Locationid int `json:"locationid"`
Productid int `json:"productid"`
Productname string `json:"productname"`
Productdescription string `json:"productdescription"`
Supplyqty float64 `json:"supplyqty"`
Balanceqty float64 `json:"balanceqty"`
Orderqty float64 `json:"orderqty"`
Price float64 `json:"price"`
Unitid int `json:"unitid"`
Unitname string `json:"unitname"`
Productaddonid int `json:"productaddonid"`
Addontypeid int `json:"addontypeid"`
Productmapid int `json:"productmapid"`
Productvariantid int `json:"productvariantid"`
Productaddondescription string `json:"productaddondescription"`
Discountid int `json:"discountid"`
Discountname string `json:"discountname"`
Discountcode string `json:"discountcode"`
Discountterms string `json:"discountterms"`
Discountpercentage float64 `json:"discountpercentage"`
Discountamount float64 `json:"discountamount"`
Landingamount float64 `json:"landingamount"`
Taxpercentage float64 `json:"taxpercentage"`
Taxamount float64 `json:"taxamount"`
Totaltaxamount float64 `json:"totaltaxamount"`
Productsumprice float64 `json:"productsumprice"`
Itemstatus string `json:"itemstatus"`
Delivered string `json:"delivered"`
Orderamount float64 `json:"Orderamount"`
Productimage string `json:"productimage"`
}
type OrderDetail struct {
Orderdetailid int `json:"orderdetailid" gorm:"primaryKey;autoIncrement"`
Orderheaderid int `json:"orderheaderid"`
Tenantid int `json:"tenantid"`
Locationid int `json:"locationid"`
Productid int `json:"productid"`
Productname string `json:"productname"`
Productdescription string `json:"productdescription"`
Supplyqty float64 `json:"supplyqty"`
Balanceqty float64 `json:"balanceqty"`
Orderqty float64 `json:"orderqty"`
Price float64 `json:"price"`
Unitid int `json:"unitid"`
Unitname string `json:"unitname"`
Productaddonid int `json:"productaddonid"`
Addontypeid int `json:"addontypeid"`
Productmapid int `json:"productmapid"`
Productvariantid int `json:"productvariantid"`
Productaddondescription string `json:"productaddondescription"`
Discountid int `json:"discountid"`
Discountname string `json:"discountname"`
Discountcode string `json:"discountcode"`
Discountterms string `json:"discountterms"`
Discountpercentage float64 `json:"discountpercentage"`
Discountamount float64 `json:"discountamount"`
Landingamount float64 `json:"landingamount"`
Taxpercentage float64 `json:"taxpercentage"`
Taxamount float64 `json:"taxamount"`
Productsumprice float64 `json:"productsumprice"`
Itemstatus string `json:"itemstatus"`
Delivered string `json:"delivered"`
Orderamount float64 `json:"-" gorm:"-"`
Productimage string `json:"productimage" gorm:"-"` // only for JSON
}
type CustomerOrder struct {
Orderheaderid int `json:"orderheaderid" gorm:"Primary_Key"`
Applocationid int `json:"applocationid"`
Tenantid int `json:"tenantid"`
Locationid int `json:"locationid"`
Partnerid int `json:"partnerid"`
Configid int `json:"configid"`
Categoryid int `json:"categoryid"`
Subcategoryid int `json:"subcategoryid"`
Moduleid int `json:"moduleid"`
Orderid string `json:"orderid"`
Orderstatus string `json:"orderstatus"`
Orderdate string `json:"orderdate,omitempty"`
Ordernotes string `json:"ordernotes"`
Itemcount int `json:"itemcount"`
Deliverytime string `json:"deliverytime"` // alias for delivered
Pending string `json:"pending"`
Processing string `json:"processing"`
Ready string `json:"ready"`
Delivered string `json:"delivered"` // original delivered column
Cancelled string `json:"cancelled"`
Deliverycharge float32 `json:"deliverycharge"`
Kms FlexibleString `json:"kms"`
Smsdelivery int `json:"smsdelivery"`
// Tenant Info
Tenantname string `json:"tenantname"`
Tenanttoken string `json:"tenanttoken"`
Tenantcontactno string `json:"tenantcontactno"`
Tenantpostcode string `json:"tenantpostcode"`
Tenantsuburb string `json:"tenantsuburb"`
Tenantcity string `json:"tenantcity"`
Registrationno string `json:"registrationno"`
// Location Info
Locationname string `json:"locationname"`
Locationcontactno string `json:"locationcontactno"`
Locationpostcode string `json:"locationpostcode"`
Locationsuburb string `json:"locationsuburb"`
Locationcity string `json:"locationcity"`
// App Location
Applocation string `json:"applocation"`
// Delivery Info (from `deliveries` table)
Deliverystatus string `json:"deliverystatus"`
DeliveryUserID int `json:"deliveryid"` // alias
Assigntime string `json:"assigntime"`
Starttime string `json:"starttime"`
Arrivaltime string `json:"arrivaltime"`
Pickuptime string `json:"pickuptime"`
Finaldeliverytime string `json:"finaldeliverytime"` // alias for f.deliverytime
Canceltime string `json:"canceltime"`
Riderkms FlexibleString `json:"riderkms"`
// Actualkms sql.NullFloat64 `json:"actualkms"`
// Actualkms sql.NullFloat64 `json:"actualkms"`
// Riderkms sql.NullFloat64 `json:"riderkms"`
// Deliveryamt sql.NullFloat64 `json:"deliveryamt"`
Droplat FlexibleString `json:"droplat"`
Droplon FlexibleString `json:"droplon"`
// Rider
Rider string `json:"rider"`
Orderamount float64 `json:"orderamount"`
Taxamount float64 `json:"taxamount"`
Totaltaxamount float64 `json:"totaltaxamount"`
Riderkms_v2 FlexibleString `json:"-" gorm:"column:riderkms"` // Extra safety
// Items if applicable
OrderDetails []OrderDetails `json:"orderdetails" gorm:"-"`
}
type Ordersequences struct {
Sequenceid int `json:"sequenceid" gorm:"Primary_Key"`
Tenantid int `json:"tenantid"`
Orderprefix string `json:"orderprefix" gorm:"default:ORD"`
Customerprefix string `json:"customerprefix" gorm:"default:CUS"`
Appointmentprefix string `json:"appointmentprefix" gorm:"default:ORD"`
Receiptprefix string `json:"receiptprefix" gorm:"default:REC"`
Paymentprefix string `json:"paymentprefix" gorm:"default:PAY"`
}
// ── Offline (in-store) sales import ───────────────────────────────────────────
//
// A sale rung up at the counter never passes through the app, so nothing
// deducts its stock. These types carry a spreadsheet of such sales into the
// same order path online orders use, so one ledger remains the single source
// of truth for stock and one revenue figure covers both channels.
// OfflineSaleItem is one spreadsheet row. Only Productid and Qtysold are
// required; the rest fall back to the product's own pricing when left blank.
// Productname is carried for verification against Productid, not for matching
// (see SaleTemplateRow for why a name can't be a key).
type OfflineSaleItem struct {
Productid int `json:"productid"`
Productname string `json:"productname"`
Qtysold float64 `json:"qtysold"`
Unitprice float64 `json:"unitprice"`
Discountamount float64 `json:"discountamount"`
Taxpercent float64 `json:"taxpercent"`
}
// OfflineSaleBill is one counter bill — the rows of a spreadsheet grouped by
// their billno. Billno is what makes a re-upload of the same file safe: it is
// recorded on the order and refused if it is already present for this outlet.
type OfflineSaleBill struct {
Billno string `json:"billno"`
Saledate string `json:"saledate"`
Paymentmode string `json:"paymentmode"`
Customername string `json:"customername"`
Customermobile string `json:"customermobile"`
Remarks string `json:"remarks"`
Items []OfflineSaleItem `json:"items"`
}
// OfflineSalesUpload is the request body. Locationid is the outlet the sales
// belong to and is authorised server-side against Tenantid — a store user
// editing the spreadsheet cannot post sales into another branch.
type OfflineSalesUpload struct {
Tenantid int `json:"tenantid"`
Locationid int `json:"locationid"`
Userid int `json:"userid"`
Bills []OfflineSaleBill `json:"bills"`
}
// Outcomes a single bill can have. A bill is all-or-nothing: it either commits
// with its stock movement or it leaves nothing behind.
const (
OfflineSaleImported = "imported"
OfflineSaleDuplicate = "duplicate"
OfflineSaleFailed = "failed"
)
// OfflineSaleResult reports one bill's fate. Bills are independent, so a file
// with one bad bill still imports the rest and names exactly what it skipped.
type OfflineSaleResult struct {
Billno string `json:"billno"`
Status string `json:"status"`
Orderid string `json:"orderid"`
Orderheaderid int `json:"orderheaderid"`
Itemcount int `json:"itemcount"`
Amount float64 `json:"amount"`
Message string `json:"message"`
}
type OfflineSalesUploadResponse struct {
Imported int `json:"imported"`
Duplicate int `json:"duplicate"`
Failed int `json:"failed"`
Totalamount float64 `json:"totalamount"`
Results []OfflineSaleResult `json:"results"`
}
type TenantRevenueSummary struct {
Tenantid int `json:"tenantid"`
Tenantname string `json:"tenantname"`
OverallRevenue float64 `json:"overallrevenue"`
LocationRevenue []LocationRevenueDetails `json:"locationrevenue"`
}
type LocationRevenueDetails struct {
Locationid int `json:"locationid"`
Locationname string `json:"locationname"`
Revenue float64 `json:"revenue"`
}
type SalesSummaryChartData struct {
Date string `json:"date"`
Revenue float64 `json:"revenue"`
Orders int `json:"orders"`
}
type SalesSummaryTopLocation struct {
Locationname string `json:"locationname"`
Revenue float64 `json:"revenue"`
}
type SalesSummaryResponse struct {
TotalRevenue float64 `json:"totalRevenue"`
TotalOrders int `json:"totalOrders"`
AverageOrderValue float64 `json:"averageOrderValue"`
ChartData []SalesSummaryChartData `json:"chartData"`
TopLocations []SalesSummaryTopLocation `json:"topLocations"`
}
type TimeSeriesData struct {
Label string `json:"label"`
Orders int `json:"orders"`
Revenue float64 `json:"revenue"`
Cancelled int `json:"cancelled"`
Delivered int `json:"delivered"`
Activeskus int `json:"activeskus"`
}