orders
This commit is contained in:
@@ -54,6 +54,34 @@ func NewOrderRepository(db *gorm.DB) OrderRepository {
|
||||
// It made a real revenue figure indistinguishable from an order that genuinely
|
||||
// booked nothing, which is why the historic orders on several tenants all look
|
||||
// worthless.
|
||||
// ── Why every join below is a LEFT JOIN ──────────────────────────────────────
|
||||
//
|
||||
// These queries list orders. An order that exists is an order that must be
|
||||
// listable, so a lookup that cannot be resolved may blank a column — it must
|
||||
// never remove the row.
|
||||
//
|
||||
// They were INNER JOINs against customers, tenants, tenantlocations,
|
||||
// app_location and app_locationconfig, which made each one a silent filter on a
|
||||
// column the caller never asked to filter by. An order written with
|
||||
// applocationid 0 or customerid 0 was created successfully, deducted stock, and
|
||||
// then appeared in no screen that lists orders — not the shopper’s own history,
|
||||
// not the shop’s. Measured 2026-09-02: two identical orders one field apart,
|
||||
// both in the database, one of them visible.
|
||||
//
|
||||
// Some of these joins contributed no columns at all to the query they sat in,
|
||||
// so they were pure filters by accident.
|
||||
//
|
||||
// The workaround is still in the tree and shows what this cost: the offline
|
||||
// sales importer builds "header scaffolding" and invents a walk-in customer
|
||||
// solely so its orders would not vanish (offlineLocationContext,
|
||||
// resolveOfflineCustomer). Populating those fields stays good practice, but it
|
||||
// is no longer what keeps an order visible.
|
||||
//
|
||||
// Deliberate filtering is unaffected. A query with a WHERE on a joined table —
|
||||
// GetUserOrders filters e.status and e.userid — still excludes rows the join
|
||||
// could not resolve, because WHERE runs after the join. GetDistinctLocations
|
||||
// keeps its INNER JOIN on purpose: it asks which app locations have orders, so
|
||||
// one that cannot be resolved is genuinely not an answer.
|
||||
const (
|
||||
base = `SELECT DISTINCT a.orderheaderid, a.applocationid, h.locationname AS applocation, a.tenantid, a.locationid, a.partnerid, a.configid, a.categoryid, a.subcategoryid, a.moduleid,
|
||||
a.orderid, a.orderstatus, a.orderdate, a.ordernotes, a.itemcount, a.deliverytime AS deliverydate,
|
||||
@@ -67,12 +95,12 @@ const (
|
||||
c.tenantname, c.tenanttoken, c.primarycontact AS tenantcontactno, c.postcode AS tenantpostcode, c.suburb AS tenantsuburb, c.city AS tenantcity,
|
||||
d.locationname, d.contactno AS locationcontactno, d.postcode AS locationpostcode, d.suburb AS locationsuburb, d.city AS locationcity
|
||||
FROM orders a
|
||||
INNER JOIN customers b ON a.customerid = b.customerid
|
||||
INNER JOIN tenants c ON a.tenantid = c.tenantid
|
||||
INNER JOIN tenantlocations d ON a.locationid = d.locationid
|
||||
LEFT JOIN customers b ON a.customerid = b.customerid
|
||||
LEFT JOIN tenants c ON a.tenantid = c.tenantid
|
||||
LEFT JOIN tenantlocations d ON a.locationid = d.locationid
|
||||
|
||||
INNER JOIN app_location h ON a.applocationid = h.applocationid
|
||||
INNER JOIN app_locationconfig i ON a.applocationid = i.applocationid`
|
||||
LEFT JOIN app_location h ON a.applocationid = h.applocationid
|
||||
LEFT JOIN app_locationconfig i ON a.applocationid = i.applocationid`
|
||||
|
||||
orderdetails = `SELECT DISTINCT a.orderheaderid, a.applocationid,
|
||||
a.tenantid, a.locationid, a.partnerid, a.configid, a.categoryid, a.subcategoryid, a.moduleid,
|
||||
@@ -87,10 +115,10 @@ const (
|
||||
c.locationname, c.contactno AS locationcontactno, c.postcode AS locationpostcode, c.suburb AS locationsuburb, c.city AS locationcity,
|
||||
d.locationname AS applocation
|
||||
FROM orders a
|
||||
INNER JOIN tenants b ON a.tenantid = b.tenantid
|
||||
INNER JOIN tenantlocations c ON a.locationid = c.locationid
|
||||
INNER JOIN app_location d ON a.applocationid = d.applocationid
|
||||
INNER JOIN app_locationconfig e ON d.applocationid = e.applocationid`
|
||||
LEFT JOIN tenants b ON a.tenantid = b.tenantid
|
||||
LEFT JOIN tenantlocations c ON a.locationid = c.locationid
|
||||
LEFT JOIN app_location d ON a.applocationid = d.applocationid
|
||||
LEFT JOIN app_locationconfig e ON d.applocationid = e.applocationid`
|
||||
)
|
||||
|
||||
func (r *orderRepository) GetTenantOrders(input models.DeliveryQuery) ([]models.OrderInfo, error) {
|
||||
@@ -102,15 +130,33 @@ func (r *orderRepository) GetTenantOrders(input models.DeliveryQuery) ([]models.
|
||||
baseQuery := base + ` WHERE a.tenantid = ?`
|
||||
params = append(params, input.Tenantid)
|
||||
|
||||
// Status filters only when one was asked for.
|
||||
//
|
||||
// The else branch ran unconditionally, so a request naming no status became
|
||||
// `orderstatus = ''` — which matches nothing. That is precisely the
|
||||
// console’s default view: All branches, no status chosen. It listed no
|
||||
// orders at all, however many the shop had taken.
|
||||
//
|
||||
// Compared case-insensitively because the ladder is stored capitalised
|
||||
// ("Pending") while every literal here is lower case. Postgres agrees:
|
||||
// `SELECT 'Pending' IN ('pending','processing','ready')` is false, so
|
||||
// "ongoing" matched nothing either.
|
||||
query = baseQuery
|
||||
if input.Status == "ongoing" {
|
||||
query = baseQuery + ` AND a.orderstatus IN ('pending','processing','ready')`
|
||||
} else {
|
||||
query = baseQuery + ` AND a.orderstatus = ?`
|
||||
query += ` AND LOWER(a.orderstatus) IN ('pending','processing','ready')`
|
||||
} else if input.Status != "" {
|
||||
query += ` AND LOWER(a.orderstatus) = LOWER(?)`
|
||||
params = append(params, input.Status)
|
||||
}
|
||||
|
||||
query += ` AND a.deliverytime::date BETWEEN ? AND ?`
|
||||
params = append(params, input.Fromdate, input.ToDate)
|
||||
// A date range narrows the list; it is not a precondition for having one.
|
||||
// Applied unconditionally it cast the empty string to a date and answered
|
||||
// 500, so the console’s order list failed outright until somebody picked a
|
||||
// range.
|
||||
if input.Fromdate != "" && input.ToDate != "" {
|
||||
query += ` AND a.deliverytime::date BETWEEN ? AND ?`
|
||||
params = append(params, input.Fromdate, input.ToDate)
|
||||
}
|
||||
|
||||
if input.Keyword != "" {
|
||||
query += ` AND (
|
||||
@@ -160,7 +206,7 @@ func (r *orderRepository) GetPartnerOrders(stat, fdate, tdate string, pid, pagen
|
||||
params = append(params, fdate, tdate)
|
||||
}
|
||||
if stat != "" {
|
||||
query += ` AND a.orderstatus = ?`
|
||||
query += ` AND LOWER(a.orderstatus) = LOWER(?)`
|
||||
params = append(params, stat)
|
||||
}
|
||||
if keyword != "" {
|
||||
@@ -180,10 +226,10 @@ func (r *orderRepository) GetPartnerOrders(stat, fdate, tdate string, pid, pagen
|
||||
countQuery := `
|
||||
SELECT COUNT(DISTINCT a.orderheaderid)
|
||||
FROM orders a
|
||||
INNER JOIN tenants b ON a.tenantid = b.tenantid
|
||||
INNER JOIN tenantlocations c ON a.locationid = c.locationid
|
||||
INNER JOIN app_location d ON a.applocationid = d.applocationid
|
||||
INNER JOIN app_locationconfig e ON d.applocationid = e.applocationid
|
||||
LEFT JOIN tenants b ON a.tenantid = b.tenantid
|
||||
LEFT JOIN tenantlocations c ON a.locationid = c.locationid
|
||||
LEFT JOIN app_location d ON a.applocationid = d.applocationid
|
||||
LEFT JOIN app_locationconfig e ON d.applocationid = e.applocationid
|
||||
LEFT JOIN deliveries f ON a.orderheaderid = f.orderheaderid
|
||||
LEFT JOIN app_users g ON f.userid = g.userid
|
||||
WHERE a.partnerid = ?`
|
||||
@@ -274,10 +320,10 @@ func (r *orderRepository) GetCustomerOrders(stat, fdate, tdate string, cid, mid,
|
||||
countQuery := `
|
||||
SELECT COUNT(DISTINCT a.orderheaderid)
|
||||
FROM orders a
|
||||
INNER JOIN tenants b ON a.tenantid = b.tenantid
|
||||
INNER JOIN tenantlocations c ON a.locationid = c.locationid
|
||||
INNER JOIN app_location d ON a.applocationid = d.applocationid
|
||||
INNER JOIN app_locationconfig e ON d.applocationid = e.applocationid
|
||||
LEFT JOIN tenants b ON a.tenantid = b.tenantid
|
||||
LEFT JOIN tenantlocations c ON a.locationid = c.locationid
|
||||
LEFT JOIN app_location d ON a.applocationid = d.applocationid
|
||||
LEFT JOIN app_locationconfig e ON d.applocationid = e.applocationid
|
||||
WHERE a.customerid = ?`
|
||||
countParams := []interface{}{cid}
|
||||
|
||||
@@ -376,10 +422,10 @@ func (r *orderRepository) GetAdminOrders(stat, fdate, tdate string, aid, pageno,
|
||||
countQuery := `
|
||||
SELECT COUNT(DISTINCT a.orderheaderid)
|
||||
FROM orders a
|
||||
INNER JOIN tenants b ON a.tenantid = b.tenantid
|
||||
INNER JOIN tenantlocations c ON a.locationid = c.locationid
|
||||
INNER JOIN app_location d ON a.applocationid = d.applocationid
|
||||
INNER JOIN app_locationconfig e ON d.applocationid = e.applocationid
|
||||
LEFT JOIN tenants b ON a.tenantid = b.tenantid
|
||||
LEFT JOIN tenantlocations c ON a.locationid = c.locationid
|
||||
LEFT JOIN app_location d ON a.applocationid = d.applocationid
|
||||
LEFT JOIN app_locationconfig e ON d.applocationid = e.applocationid
|
||||
LEFT JOIN deliveries f ON a.orderheaderid = f.orderheaderid
|
||||
LEFT JOIN app_users g ON f.userid = g.userid
|
||||
WHERE 1=1
|
||||
@@ -471,10 +517,10 @@ func (r *orderRepository) GetUserOrders(stat, fdate, tdate string, uid, pageno,
|
||||
countQuery := `
|
||||
SELECT COUNT(DISTINCT a.orderheaderid)
|
||||
FROM orders a
|
||||
INNER JOIN tenants b ON a.tenantid = b.tenantid
|
||||
INNER JOIN tenantlocations c ON a.locationid = c.locationid
|
||||
INNER JOIN app_location d ON a.applocationid = d.applocationid
|
||||
INNER JOIN app_locationconfig e ON d.applocationid = e.applocationid
|
||||
LEFT JOIN tenants b ON a.tenantid = b.tenantid
|
||||
LEFT JOIN tenantlocations c ON a.locationid = c.locationid
|
||||
LEFT JOIN app_location d ON a.applocationid = d.applocationid
|
||||
LEFT JOIN app_locationconfig e ON d.applocationid = e.applocationid
|
||||
LEFT JOIN deliveries f ON a.orderheaderid = f.orderheaderid
|
||||
LEFT JOIN app_users g ON f.userid = g.userid
|
||||
WHERE e.status = 'Active' AND e.userid = ?
|
||||
@@ -564,10 +610,10 @@ func (r *orderRepository) GetAllOrders(stat, fdate, tdate string, pageno, pagesi
|
||||
countQuery := `
|
||||
SELECT COUNT(DISTINCT a.orderheaderid)
|
||||
FROM orders a
|
||||
INNER JOIN tenants b ON a.tenantid = b.tenantid
|
||||
INNER JOIN tenantlocations c ON a.locationid = c.locationid
|
||||
INNER JOIN app_location d ON a.applocationid = d.applocationid
|
||||
INNER JOIN app_locationconfig e ON d.applocationid = e.applocationid
|
||||
LEFT JOIN tenants b ON a.tenantid = b.tenantid
|
||||
LEFT JOIN tenantlocations c ON a.locationid = c.locationid
|
||||
LEFT JOIN app_location d ON a.applocationid = d.applocationid
|
||||
LEFT JOIN app_locationconfig e ON d.applocationid = e.applocationid
|
||||
LEFT JOIN deliveries f ON a.orderheaderid = f.orderheaderid
|
||||
LEFT JOIN app_users g ON f.userid = g.userid
|
||||
WHERE 1=1
|
||||
@@ -2314,16 +2360,16 @@ func (r *orderRepository) GetCustomerOrdersv3(customerID, tenantID, moduleID, fr
|
||||
a.pickupcity, a.deliveryid AS deliverycustomerid, a.deliveryaddress, a.deliverylat,
|
||||
a.deliverylong, a.deliverytype, a.deliverycustomer, a.deliverycontactno,
|
||||
a.deliverylocation AS deliverysuburb, a.deliverycity, a.paymenttype, a.smsdelivery,
|
||||
a.taxamount,
|
||||
a.orderamount, a.taxamount,
|
||||
b.tenantname, b.tenanttoken, b.primarycontact AS tenantcontactno,
|
||||
b.postcode AS tenantpostcode, b.suburb AS tenantsuburb, b.city AS tenantcity, b.registrationno,
|
||||
c.locationname, c.contactno AS locationcontactno, c.postcode AS locationpostcode,
|
||||
c.suburb AS locationsuburb, c.city AS locationcity,
|
||||
d.locationname AS applocation
|
||||
FROM orders a
|
||||
INNER JOIN tenants b ON a.tenantid = b.tenantid
|
||||
INNER JOIN tenantlocations c ON a.locationid = c.locationid
|
||||
INNER JOIN app_location d ON a.applocationid = d.applocationid
|
||||
LEFT JOIN tenants b ON a.tenantid = b.tenantid
|
||||
LEFT JOIN tenantlocations c ON a.locationid = c.locationid
|
||||
LEFT JOIN app_location d ON a.applocationid = d.applocationid
|
||||
WHERE 1=1
|
||||
`
|
||||
|
||||
@@ -2402,10 +2448,15 @@ func (r *orderRepository) attachOrderDetails(orders []models.CustomerOrder) ([]m
|
||||
for i := range orders {
|
||||
orders[i].OrderDetails = detailMap[orders[i].Orderheaderid]
|
||||
|
||||
if len(orders[i].OrderDetails) > 0 {
|
||||
orders[i].Orderamount = orders[i].OrderDetails[0].Orderamount
|
||||
orders[i].Totaltaxamount = orders[i].OrderDetails[0].Totaltaxamount
|
||||
}
|
||||
// The header already carries the order total, and it is the only place
|
||||
// that has one. This used to overwrite it with the first LINE’s
|
||||
// Orderamount and Totaltaxamount — columns that do not exist on the
|
||||
// orderdetails table, so both scanned as zero and clobbered a correct
|
||||
// value. Every order in a shopper’s history read ₹0 as a result, however
|
||||
// much they had actually spent.
|
||||
//
|
||||
// Taking the first line’s figure could not have been right even if the
|
||||
// columns existed: one line is not the order.
|
||||
}
|
||||
|
||||
return orders, nil
|
||||
@@ -2427,7 +2478,7 @@ func (r *orderRepository) GetTenantLocationOrders(input models.DeliveryQuery) ([
|
||||
|
||||
// Status filter
|
||||
if input.Status == "ongoing" {
|
||||
query += ` AND a.orderstatus IN ('pending','processing','ready')`
|
||||
query += ` AND LOWER(a.orderstatus) IN ('pending','processing','ready')`
|
||||
} else if input.Status != "" {
|
||||
query += ` AND a.orderstatus = ?`
|
||||
params = append(params, input.Status)
|
||||
@@ -2446,8 +2497,12 @@ func (r *orderRepository) GetTenantLocationOrders(input models.DeliveryQuery) ([
|
||||
}
|
||||
|
||||
// Date filter
|
||||
query += ` AND DATE(a.deliverytime) BETWEEN ? AND ?`
|
||||
params = append(params, input.Fromdate, input.ToDate)
|
||||
// Narrows the list rather than gating it — same reasoning as
|
||||
// GetTenantOrders above, where empty dates cast to a date and answered 500.
|
||||
if input.Fromdate != "" && input.ToDate != "" {
|
||||
query += ` AND DATE(a.deliverytime) BETWEEN ? AND ?`
|
||||
params = append(params, input.Fromdate, input.ToDate)
|
||||
}
|
||||
|
||||
// Keyword filter
|
||||
if input.Keyword != "" {
|
||||
|
||||
Reference in New Issue
Block a user