store based coustmers
This commit is contained in:
@@ -188,10 +188,21 @@ func (r *customerRepository) GetTenantCustomers(tid, lid, pageno, pagesize int,
|
|||||||
var args []interface{}
|
var args []interface{}
|
||||||
searchLike := "%" + keyword + "%"
|
searchLike := "%" + keyword + "%"
|
||||||
|
|
||||||
|
// DISTINCT ON collapses to one row per customer BEFORE the LIMIT is applied.
|
||||||
|
// Without it the store-scoped branch below paginated the joined
|
||||||
|
// customerlocations rows — one per saved address — so `pagesize` bought a
|
||||||
|
// page of addresses, not of customers. Live example: locationid 1185 returned
|
||||||
|
// 12 rows that were only 2 people, 11 of them one customer's addresses. A
|
||||||
|
// store with a page size of 20 therefore listed roughly three customers and
|
||||||
|
// gave no hint that the rest existed.
|
||||||
|
//
|
||||||
|
// The ORDER BY must lead with the DISTINCT ON expression, so customerid sorts
|
||||||
|
// first; the trailing keys only decide WHICH address represents a customer,
|
||||||
|
// preferring the one flagged primary.
|
||||||
if lid != 0 {
|
if lid != 0 {
|
||||||
q1 = `SELECT a.customerid,a.firstname,a.lastname,a.contactno,a.email,
|
q1 = `SELECT DISTINCT ON (a.customerid) a.customerid,a.firstname,a.lastname,a.contactno,a.email,
|
||||||
b.locationid as deliverylocationid,b.address,b.suburb,b.city,b.state,b.landmark,b.doorno,b.postcode,
|
b.locationid as deliverylocationid,b.address,b.suburb,b.city,b.state,b.landmark,b.doorno,b.postcode,
|
||||||
b.latitude,b.longitude,a.applocationid,c.locationid as tenantlocationid,a.status
|
b.latitude,b.longitude,a.applocationid,c.locationid as tenantlocationid,a.status
|
||||||
FROM customers a
|
FROM customers a
|
||||||
LEFT JOIN customerlocations b ON a.customerid=b.customerid
|
LEFT JOIN customerlocations b ON a.customerid=b.customerid
|
||||||
INNER JOIN tenantcustomers c ON a.customerid=c.customerid
|
INNER JOIN tenantcustomers c ON a.customerid=c.customerid
|
||||||
@@ -204,13 +215,17 @@ func (r *customerRepository) GetTenantCustomers(tid, lid, pageno, pagesize int,
|
|||||||
args = append(args, searchLike, searchLike, searchLike)
|
args = append(args, searchLike, searchLike, searchLike)
|
||||||
}
|
}
|
||||||
|
|
||||||
q1 += ` ORDER BY a.customerid DESC LIMIT ? OFFSET ?`
|
q1 += ` ORDER BY a.customerid DESC, b.primaryaddress DESC NULLS LAST, b.locationid ASC
|
||||||
|
LIMIT ? OFFSET ?`
|
||||||
args = append(args, pagesize, offset)
|
args = append(args, pagesize, offset)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
q1 = `SELECT a.customerid,a.firstname,a.lastname,a.contactno,a.email,
|
// A customer linked to several outlets of the same tenant has one
|
||||||
|
// tenantcustomers row per outlet, so this branch double-counted them
|
||||||
|
// against the LIMIT too.
|
||||||
|
q1 = `SELECT DISTINCT ON (a.customerid) a.customerid,a.firstname,a.lastname,a.contactno,a.email,
|
||||||
a.address,a.suburb,a.city,a.state,a.landmark,a.doorno,a.postcode,
|
a.address,a.suburb,a.city,a.state,a.landmark,a.doorno,a.postcode,
|
||||||
a.latitude,a.longitude,a.applocationid,c.locationid as tenantlocationid,a.status
|
a.latitude,a.longitude,a.applocationid,c.locationid as tenantlocationid,a.status
|
||||||
FROM customers a
|
FROM customers a
|
||||||
INNER JOIN tenantcustomers c ON a.customerid=c.customerid
|
INNER JOIN tenantcustomers c ON a.customerid=c.customerid
|
||||||
WHERE c.tenantid = ?`
|
WHERE c.tenantid = ?`
|
||||||
@@ -223,12 +238,10 @@ func (r *customerRepository) GetTenantCustomers(tid, lid, pageno, pagesize int,
|
|||||||
args = append(args, searchLike, searchLike, searchLike)
|
args = append(args, searchLike, searchLike, searchLike)
|
||||||
}
|
}
|
||||||
|
|
||||||
q1 += ` ORDER BY a.customerid DESC LIMIT ? OFFSET ?`
|
q1 += ` ORDER BY a.customerid DESC, c.locationid ASC LIMIT ? OFFSET ?`
|
||||||
args = append(args, pagesize, offset)
|
args = append(args, pagesize, offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
print(q1)
|
|
||||||
|
|
||||||
r.db.Raw(q1, args...).Find(&data)
|
r.db.Raw(q1, args...).Find(&data)
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
package repositories
|
package repositories
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"nearle/models"
|
"nearle/models"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/jinzhu/copier"
|
"github.com/jinzhu/copier"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
@@ -147,18 +149,75 @@ func (r *deliveriesRepository) UpdateDelivery(data models.UpdateDeliveryStatus)
|
|||||||
var ord models.Updateorderstatus
|
var ord models.Updateorderstatus
|
||||||
var cloc models.Customerlocations
|
var cloc models.Customerlocations
|
||||||
|
|
||||||
|
if data.Deliveryid == 0 {
|
||||||
|
return errors.New("deliveryid is required")
|
||||||
|
}
|
||||||
|
|
||||||
tx := r.db.Begin()
|
tx := r.db.Begin()
|
||||||
|
if tx.Error != nil {
|
||||||
|
return tx.Error
|
||||||
|
}
|
||||||
|
|
||||||
if err := tx.Table("deliveries").Where("deliveryid = ?", data.Deliveryid).Updates(&data).Error; err != nil {
|
if err := tx.Table("deliveries").Where("deliveryid = ?", data.Deliveryid).Updates(&data).Error; err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The parent order is resolved from the delivery row rather than taken from
|
||||||
|
// the request. Every status branch below writes the order with
|
||||||
|
// "WHERE orderheaderid = ?", and a client that omits orderheaderid made that
|
||||||
|
// "WHERE orderheaderid = 0", matching nothing. GORM reports no error for an
|
||||||
|
// update that affects no rows, so the handler still answered 201 Success
|
||||||
|
// while the order silently kept its old status — 635 deliveries are marked
|
||||||
|
// delivered against an order still reading pending because of this.
|
||||||
|
//
|
||||||
|
// deliveryid is the one field every caller must send (it is how the row
|
||||||
|
// above is found), so deriving the link from it makes the sync independent
|
||||||
|
// of how complete the client's payload is.
|
||||||
|
orderHeaderID := data.Orderheaderid
|
||||||
|
if orderHeaderID == 0 {
|
||||||
|
if err := tx.Table("deliveries").
|
||||||
|
Select("orderheaderid").
|
||||||
|
Where("deliveryid = ?", data.Deliveryid).
|
||||||
|
Scan(&orderHeaderID).Error; err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if orderHeaderID == 0 {
|
||||||
|
tx.Rollback()
|
||||||
|
return fmt.Errorf("delivery %d has no order attached", data.Deliveryid)
|
||||||
|
}
|
||||||
|
|
||||||
|
// syncOrder applies the status to the parent order and fails loudly if the
|
||||||
|
// row is not there, instead of reporting success for a write that landed
|
||||||
|
// nowhere.
|
||||||
|
syncOrder := func() error {
|
||||||
|
res := tx.Table("orders").Where("orderheaderid = ?", orderHeaderID).Updates(&ord)
|
||||||
|
if res.Error != nil {
|
||||||
|
return res.Error
|
||||||
|
}
|
||||||
|
if res.RowsAffected == 0 {
|
||||||
|
return fmt.Errorf("order %d not found for delivery %d", orderHeaderID, data.Deliveryid)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// The lifecycle timestamp mirrored onto the order. Clients frequently send
|
||||||
|
// the status without one, and because Updates() skips zero-valued struct
|
||||||
|
// fields the order's own column was left blank while its status moved on.
|
||||||
|
stamp := func(supplied string) string {
|
||||||
|
if strings.TrimSpace(supplied) != "" {
|
||||||
|
return supplied
|
||||||
|
}
|
||||||
|
return time.Now().Format("2006-01-02 15:04:05")
|
||||||
|
}
|
||||||
|
|
||||||
switch data.Orderstatus {
|
switch data.Orderstatus {
|
||||||
case "pending":
|
case "pending":
|
||||||
ord.Orderstatus = data.Orderstatus
|
ord.Orderstatus = data.Orderstatus
|
||||||
ord.Pending = data.Assigntime
|
ord.Pending = stamp(data.Assigntime)
|
||||||
if err := tx.Table("orders").Where("orderheaderid = ?", data.Orderheaderid).Updates(&ord).Error; err != nil {
|
if err := syncOrder(); err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -181,8 +240,8 @@ func (r *deliveriesRepository) UpdateDelivery(data models.UpdateDeliveryStatus)
|
|||||||
|
|
||||||
case "delivered":
|
case "delivered":
|
||||||
ord.Orderstatus = data.Orderstatus
|
ord.Orderstatus = data.Orderstatus
|
||||||
ord.Delivered = data.Deliverytime
|
ord.Delivered = stamp(data.Deliverytime)
|
||||||
if err := tx.Table("orders").Where("orderheaderid = ?", data.Orderheaderid).Updates(&ord).Error; err != nil {
|
if err := syncOrder(); err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -204,8 +263,8 @@ func (r *deliveriesRepository) UpdateDelivery(data models.UpdateDeliveryStatus)
|
|||||||
|
|
||||||
case "cancelled":
|
case "cancelled":
|
||||||
ord.Orderstatus = data.Orderstatus
|
ord.Orderstatus = data.Orderstatus
|
||||||
ord.Cancelled = data.Canceltime
|
ord.Cancelled = stamp(data.Canceltime)
|
||||||
if err := tx.Table("orders").Where("orderheaderid = ?", data.Orderheaderid).Updates(&ord).Error; err != nil {
|
if err := syncOrder(); err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user