Files
backend_fiesta/repositories/orderRepository.go
2026-05-25 11:52:26 +05:30

1134 lines
35 KiB
Go

package repositories
import (
"fmt"
"log"
"nearle/models"
"strconv"
"time"
"gorm.io/gorm"
)
type OrderRepository interface {
GetTenantOrders(q models.DeliveryQuery) ([]models.OrderInfo, error)
GetTenantLocationOrders(input models.DeliveryQuery) ([]models.OrderInfo, error)
GetPartnerOrders(stat, fdate, tdate string, pid, pageno, pagesize int, keyword string) ([]models.OrderInfo, error)
GetCustomerOrders(stat, fdate, tdate string, cid, mid, pageno, pagesize int, keyword string) ([]models.OrderInfo, error)
GetAdminOrders(stat, fdate, tdate string, aid, pageno, pagesize int, keyword string) ([]models.OrderInfo, error)
GetUserOrders(stat, fdate, tdate string, uid, pageno, pagesize int, keyword string) ([]models.OrderInfo, error)
GetAllOrders(stat, fdate, tdate string, pageno, pagesize int, keyword string) ([]models.OrderInfo, error)
GetOrderSummary(tid, pid, cid, aid int, fdate, tdate string) ([]models.Ordersummarydaily, error)
GetLocationOrderSummary(tenantID int) ([]models.Ordersummarylocation, error)
GetOrderInsights(tenantID int) ([]models.OrderInsightv1, error)
GetOrderDetails(orderHeaderID int) ([]models.OrderDetails, error)
UpdateOrder(order *models.Orders) error
CreateOrder(order models.Orders) (models.Orders, error)
GetCustomerOrdersv3(customerID, tenantID, moduleID, fromDate, toDate, orderStatus, keyword string, pageSize, offset int) ([]models.CustomerOrder, error)
}
type orderRepository struct {
db *gorm.DB
}
func NewOrderRepository(db *gorm.DB) OrderRepository {
return &orderRepository{db: db}
}
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,
a.pending, a.processing, a.ready, a.delivered AS completed, a.cancelled,
a.deliverycharge, a.kms,
a.customerid, a.pickuplocationid, a.pickupaddress, a.pickuplat, a.pickuplong,
a.pickupcustomer, a.pickupcontactno, a.pickuplocation as pickupsuburb, 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, b.customertoken,
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
INNER JOIN app_location h ON a.applocationid = h.applocationid
INNER 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,
a.orderid, a.orderstatus, a.orderdate, a.ordernotes, a.itemcount, a.deliverytime AS deliverydate,
a.pending, a.processing, a.ready, a.delivered AS completed, a.cancelled,
a.deliverycharge, a.kms,
a.customerid, a.pickupaddress, a.pickuplat, a.pickuplong,
a.pickupcustomer, a.pickupcontactno, a.pickuplocation as pickupsuburb, 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.orderamount,
b.tenantname, b.tenanttoken, b.primarycontact AS tenantcontactno, b.postcode AS tenantpostcode, b.suburb AS tenantsuburb,b.city AS tenantcity,
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`
)
func (r *orderRepository) GetTenantOrders(input models.DeliveryQuery) ([]models.OrderInfo, error) {
var data []models.OrderInfo
var query string
var params []interface{}
offset := (input.Pageno - 1) * input.Pagesize
baseQuery := base + ` WHERE a.tenantid = ?`
params = append(params, input.Tenantid)
if input.Status == "ongoing" {
query = baseQuery + ` AND a.orderstatus IN ('pending','processing','ready')`
} else {
query = baseQuery + ` AND a.orderstatus = ?`
params = append(params, input.Status)
}
query += ` AND a.deliverytime::date BETWEEN ? AND ?`
params = append(params, input.Fromdate, input.ToDate)
if input.Keyword != "" {
query += ` AND (
a.pickupcustomer LIKE ? OR
c.tenantname LIKE ? OR
a.deliverycustomer LIKE ? OR
a.pickupcontactno LIKE ? OR
a.deliverycontactno LIKE ? OR
a.orderid LIKE ?
)`
like := "%" + input.Keyword + "%"
params = append(params, like, like, like, like, like, like)
}
if input.Configid != 0 {
query += ` AND a.configid = ?`
params = append(params, input.Configid)
}
query += ` ORDER BY a.orderheaderid DESC LIMIT ? OFFSET ?`
params = append(params, input.Pagesize, offset)
fmt.Println("Executing:", query)
res := r.db.Raw(query, params...).Find(&data)
return data, res.Error
}
func (r *orderRepository) GetPartnerOrders(stat, fdate, tdate string, pid, pageno, pagesize int, keyword string) ([]models.OrderInfo, error) {
var data []models.OrderInfo
if pageno <= 0 {
pageno = 1
}
if pagesize <= 0 {
pagesize = 10
}
offset := (pageno - 1) * pagesize
fmt.Println("Getting partner order details")
query := orderdetails + ` WHERE a.partnerid = ?`
params := []interface{}{pid}
if fdate != "" && tdate != "" {
query += ` AND a.deliverytime::date BETWEEN ? AND ?`
params = append(params, fdate, tdate)
}
if stat != "" {
query += ` AND a.orderstatus = ?`
params = append(params, stat)
}
if keyword != "" {
query += ` AND (
a.pickupcustomer LIKE ? OR
b.tenantname LIKE ? OR
a.deliverycustomer LIKE ? OR
a.pickupcontactno LIKE ? OR
a.deliverycontactno LIKE ? OR
a.orderid LIKE ?
)`
like := "%" + keyword + "%"
params = append(params, like, like, like, like, like, like)
}
var total int64
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 deliveries f ON a.orderheaderid = f.orderheaderid
LEFT JOIN app_users g ON f.userid = g.userid
WHERE a.partnerid = ?`
countParams := []interface{}{pid}
if fdate != "" && tdate != "" {
countQuery += ` AND a.deliverytime::date BETWEEN ? AND ?`
countParams = append(countParams, fdate, tdate)
}
if stat != "" {
countQuery += ` AND a.orderstatus = ?`
countParams = append(countParams, stat)
}
if keyword != "" {
countQuery += ` AND (
a.pickupcustomer LIKE ? OR
b.tenantname LIKE ? OR
a.deliverycustomer LIKE ? OR
a.pickupcontactno LIKE ? OR
a.deliverycontactno LIKE ? OR
a.orderid LIKE ?
)`
like := "%" + keyword + "%"
countParams = append(countParams, like, like, like, like, like, like)
}
r.db.Raw(countQuery, countParams...).Scan(&total)
if int64(offset) >= total {
offset = 0
pageno = 1
}
query += ` ORDER BY a.orderheaderid DESC LIMIT ? OFFSET ?`
params = append(params, pagesize, offset)
fmt.Println("QUERY:", query)
fmt.Println("PARAMS:", params)
r.db.Raw(query, params...).Find(&data)
fmt.Println("RESULT COUNT:", len(data))
return data, nil
}
func (r *orderRepository) GetCustomerOrders(stat, fdate, tdate string, cid, mid, pageno, pagesize int, keyword string) ([]models.OrderInfo, error) {
var data []models.OrderInfo
if pageno <= 0 {
pageno = 1
}
if pagesize <= 0 {
pagesize = 10
}
offset := (pageno - 1) * pagesize
fmt.Println("Getting customer order details")
query := orderdetails + ` WHERE a.customerid = ?`
params := []interface{}{cid}
if mid != 0 {
query += ` AND a.moduleid = ?`
params = append(params, mid)
}
if fdate != "" && tdate != "" {
query += ` AND a.orderdate::date BETWEEN ? AND ?`
params = append(params, fdate, tdate)
}
if stat != "" {
query += ` AND a.orderstatus = ?`
params = append(params, stat)
}
if keyword != "" {
query += ` AND (
a.pickupcustomer LIKE ? OR
b.tenantname LIKE ? OR
a.deliverycustomer LIKE ? OR
a.pickupcontactno LIKE ? OR
a.deliverycontactno LIKE ? OR
a.orderid LIKE ?
)`
like := "%" + keyword + "%"
params = append(params, like, like, like, like, like, like)
}
var total int64
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
WHERE a.customerid = ?`
countParams := []interface{}{cid}
if mid != 0 {
countQuery += ` AND a.moduleid = ?`
countParams = append(countParams, mid)
}
if fdate != "" && tdate != "" {
countQuery += ` AND a.orderdate::date BETWEEN ? AND ?`
countParams = append(countParams, fdate, tdate)
}
if stat != "" {
countQuery += ` AND a.orderstatus = ?`
countParams = append(countParams, stat)
}
if keyword != "" {
countQuery += ` AND (
a.pickupcustomer LIKE ? OR
b.tenantname LIKE ? OR
a.deliverycustomer LIKE ? OR
a.pickupcontactno LIKE ? OR
a.deliverycontactno LIKE ? OR
a.orderid LIKE ?
)`
like := "%" + keyword + "%"
countParams = append(countParams, like, like, like, like, like, like)
}
r.db.Raw(countQuery, countParams...).Scan(&total)
if int64(offset) >= total {
offset = 0
pageno = 1
}
query += ` ORDER BY a.orderheaderid DESC LIMIT ? OFFSET ?`
params = append(params, pagesize, offset)
fmt.Println("QUERY:", query)
fmt.Println("PARAMS:", params)
res := r.db.Raw(query, params...).Find(&data)
if res.Error != nil {
fmt.Println("ERROR:", res.Error)
}
fmt.Println("RESULT COUNT:", len(data))
return data, nil
}
func (r *orderRepository) GetAdminOrders(stat, fdate, tdate string, aid, pageno, pagesize int, keyword string) ([]models.OrderInfo, error) {
var data []models.OrderInfo
if pageno <= 0 {
pageno = 1
}
if pagesize <= 0 {
pagesize = 10
}
offset := (pageno - 1) * pagesize
fmt.Println("Getting admin order details")
query := orderdetails + ` WHERE 1=1`
params := []interface{}{}
if aid != 0 {
query += ` AND a.applocationid = ?`
params = append(params, aid)
}
if fdate != "" && tdate != "" {
query += ` AND a.deliverytime::date BETWEEN ? AND ?`
params = append(params, fdate, tdate)
}
if stat != "" {
query += ` AND a.orderstatus = ?`
params = append(params, stat)
}
if keyword != "" {
query += ` AND (
a.pickupcustomer LIKE ? OR
b.tenantname LIKE ? OR
a.deliverycustomer LIKE ? OR
a.pickupcontactno LIKE ? OR
a.deliverycontactno LIKE ? OR
a.orderid LIKE ?
)`
like := "%" + keyword + "%"
params = append(params, like, like, like, like, like, like)
}
var total int64
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 deliveries f ON a.orderheaderid = f.orderheaderid
LEFT JOIN app_users g ON f.userid = g.userid
WHERE 1=1
`
countParams := []interface{}{}
if aid != 0 {
countQuery += ` AND a.applocationid = ?`
countParams = append(countParams, aid)
}
if fdate != "" && tdate != "" {
countQuery += ` AND a.deliverytime::date BETWEEN ? AND ?`
countParams = append(countParams, fdate, tdate)
}
if stat != "" {
countQuery += ` AND a.orderstatus = ?`
countParams = append(countParams, stat)
}
if keyword != "" {
countQuery += ` AND (
a.pickupcustomer LIKE ? OR
b.tenantname LIKE ? OR
a.deliverycustomer LIKE ? OR
a.pickupcontactno LIKE ? OR
a.deliverycontactno LIKE ? OR
a.orderid LIKE ?
)`
like := "%" + keyword + "%"
countParams = append(countParams, like, like, like, like, like, like)
}
r.db.Raw(countQuery, countParams...).Scan(&total)
if int64(offset) >= total {
offset = 0
pageno = 1
}
query += ` ORDER BY a.orderheaderid DESC LIMIT ? OFFSET ?`
params = append(params, pagesize, offset)
fmt.Println("QUERY:", query)
fmt.Println("PARAMS:", params)
r.db.Raw(query, params...).Find(&data)
fmt.Println("RESULT COUNT:", len(data))
return data, nil
}
func (r *orderRepository) GetUserOrders(stat, fdate, tdate string, uid, pageno, pagesize int, keyword string) ([]models.OrderInfo, error) {
var data []models.OrderInfo
if pageno <= 0 {
pageno = 1
}
if pagesize <= 0 {
pagesize = 10
}
offset := (pageno - 1) * pagesize
fmt.Println("Getting user order details")
query := orderdetails + ` WHERE e.status = 'Active' AND e.userid = ?`
params := []interface{}{uid}
if fdate != "" && tdate != "" {
query += ` AND a.deliverytime::date BETWEEN ? AND ?`
params = append(params, fdate, tdate)
}
if stat != "" {
query += ` AND a.orderstatus = ?`
params = append(params, stat)
}
if keyword != "" {
query += ` AND (
a.pickupcustomer LIKE ? OR
b.tenantname LIKE ? OR
a.deliverycustomer LIKE ? OR
a.pickupcontactno LIKE ? OR
a.deliverycontactno LIKE ? OR
a.orderid LIKE ?
)`
like := "%" + keyword + "%"
params = append(params, like, like, like, like, like, like)
}
var total int64
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 deliveries f ON a.orderheaderid = f.orderheaderid
LEFT JOIN app_users g ON f.userid = g.userid
WHERE e.status = 'Active' AND e.userid = ?
`
countParams := []interface{}{uid}
if fdate != "" && tdate != "" {
countQuery += ` AND a.deliverytime::date BETWEEN ? AND ?`
countParams = append(countParams, fdate, tdate)
}
if stat != "" {
countQuery += ` AND a.orderstatus = ?`
countParams = append(countParams, stat)
}
if keyword != "" {
countQuery += ` AND (
a.pickupcustomer LIKE ? OR
b.tenantname LIKE ? OR
a.deliverycustomer LIKE ? OR
a.pickupcontactno LIKE ? OR
a.deliverycontactno LIKE ? OR
a.orderid LIKE ?
)`
like := "%" + keyword + "%"
countParams = append(countParams, like, like, like, like, like, like)
}
r.db.Raw(countQuery, countParams...).Scan(&total)
if int64(offset) >= total {
offset = 0
pageno = 1
}
query += ` ORDER BY a.orderheaderid DESC LIMIT ? OFFSET ?`
params = append(params, pagesize, offset)
fmt.Println("QUERY:", query)
fmt.Println("PARAMS:", params)
r.db.Raw(query, params...).Find(&data)
fmt.Println("RESULT COUNT:", len(data))
return data, nil
}
func (r *orderRepository) GetAllOrders(stat, fdate, tdate string, pageno, pagesize int, keyword string) ([]models.OrderInfo, error) {
var data []models.OrderInfo
if pageno <= 0 {
pageno = 1
}
if pagesize <= 0 {
pagesize = 10
}
offset := (pageno - 1) * pagesize
fmt.Println("Getting all orders")
query := orderdetails + ` WHERE 1=1`
params := []interface{}{}
if fdate != "" && tdate != "" {
query += ` AND a.deliverytime::date BETWEEN ? AND ?`
params = append(params, fdate, tdate)
}
if stat != "" {
query += ` AND a.orderstatus = ?`
params = append(params, stat)
}
if keyword != "" {
query += ` AND (
a.pickupcustomer LIKE ? OR
b.tenantname LIKE ? OR
a.deliverycustomer LIKE ? OR
a.pickupcontactno LIKE ? OR
a.deliverycontactno LIKE ? OR
a.orderid LIKE ?
)`
like := "%" + keyword + "%"
params = append(params, like, like, like, like, like, like)
}
var total int64
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 deliveries f ON a.orderheaderid = f.orderheaderid
LEFT JOIN app_users g ON f.userid = g.userid
WHERE 1=1
`
countParams := []interface{}{}
if fdate != "" && tdate != "" {
countQuery += ` AND a.deliverytime::date BETWEEN ? AND ?`
countParams = append(countParams, fdate, tdate)
}
if stat != "" {
countQuery += ` AND a.orderstatus = ?`
countParams = append(countParams, stat)
}
if keyword != "" {
countQuery += ` AND (
a.pickupcustomer LIKE ? OR
b.tenantname LIKE ? OR
a.deliverycustomer LIKE ? OR
a.pickupcontactno LIKE ? OR
a.deliverycontactno LIKE ? OR
a.orderid LIKE ?
)`
like := "%" + keyword + "%"
countParams = append(countParams, like, like, like, like, like, like)
}
r.db.Raw(countQuery, countParams...).Scan(&total)
if int64(offset) >= total {
offset = 0
pageno = 1
}
query += ` ORDER BY a.orderheaderid DESC LIMIT ? OFFSET ?`
params = append(params, pagesize, offset)
fmt.Println("QUERY:", query)
fmt.Println("PARAMS:", params)
r.db.Raw(query, params...).Find(&data)
fmt.Println("RESULT COUNT:", len(data))
return data, nil
}
func (r *orderRepository) GetOrderSummary(tid, pid, cid, lid int, fdate, tdate string) ([]models.Ordersummarydaily, error) {
var data []models.Ordersummarydaily
var q1 string
// Base SELECT
const base = `
SELECT
COUNT(*) AS total,
SUM(CASE WHEN o.orderstatus = 'created' THEN 1 ELSE 0 END) AS created,
SUM(CASE WHEN o.orderstatus = 'pending' THEN 1 ELSE 0 END) AS pending,
SUM(CASE WHEN o.orderstatus = 'processing' THEN 1 ELSE 0 END) AS processing,
SUM(CASE WHEN o.orderstatus = 'delivered' THEN 1 ELSE 0 END) AS delivered,
SUM(CASE WHEN o.orderstatus = 'cancelled' THEN 1 ELSE 0 END) AS cancelled,
t.tenantid,
t.tenantname
FROM orders o
INNER JOIN tenants t ON o.tenantid = t.tenantid
`
// Apply filters
if tid != 0 {
q1 = base + " WHERE o.configid = 1 AND o.tenantid = " + strconv.Itoa(tid)
} else if pid != 0 {
q1 = base + " WHERE o.configid = 1 AND o.partnerid = " + strconv.Itoa(pid)
} else if cid != 0 {
q1 = base + " WHERE o.configid = 1 AND o.customerid = " + strconv.Itoa(cid)
} else if lid != 0 {
q1 = base + " WHERE o.configid = 1 AND o.locationid = " + strconv.Itoa(lid)
} else {
q1 = base + " WHERE o.configid = 1"
}
// Date filter
if fdate != "" && tdate != "" {
q1 += " AND o.orderdate::date BETWEEN '" + fdate + "' AND '" + tdate + "'"
}
// Group by tenant
q1 += " GROUP BY t.tenantid, t.tenantname"
// Debug
fmt.Println("Executing GetOrderSummary query:", q1)
if err := r.db.Raw(q1).Scan(&data).Error; err != nil {
return nil, err
}
return data, nil
}
func (r *orderRepository) GetLocationOrderSummary(tenantID int) ([]models.Ordersummarylocation, error) {
var data []models.Ordersummarylocation
var params []interface{}
q1 := `
SELECT
l.locationid,
l.locationname,
COALESCE(COUNT(o.orderid), 0) AS total,
COALESCE(SUM(CASE WHEN o.orderstatus = 'created' THEN 1 ELSE 0 END), 0) AS created,
COALESCE(SUM(CASE WHEN o.orderstatus = 'pending' THEN 1 ELSE 0 END), 0) AS pending,
COALESCE(SUM(CASE WHEN o.orderstatus = 'processing' THEN 1 ELSE 0 END), 0) AS processing,
COALESCE(SUM(CASE WHEN o.orderstatus = 'delivered' THEN 1 ELSE 0 END), 0) AS delivered,
COALESCE(SUM(CASE WHEN o.orderstatus = 'cancelled' THEN 1 ELSE 0 END), 0) AS cancelled
FROM tenantlocations l
LEFT JOIN orders o
ON l.locationid = o.locationid
AND l.tenantid = o.tenantid
AND o.configid = 1
`
if tenantID != 0 {
q1 += " WHERE l.tenantid = ?"
params = append(params, tenantID)
}
q1 += " GROUP BY l.locationid, l.locationname ORDER BY l.locationid"
fmt.Println("Executing query:", q1)
if err := r.db.Raw(q1, params...).Scan(&data).Error; err != nil {
return nil, err
}
return data, nil
}
func (r *orderRepository) GetDistinctLocations() ([]models.OrderInsight, error) {
var locations []models.OrderInsight
q1 := `
SELECT DISTINCT a.applocationid, b.locationname
FROM orders a
INNER JOIN app_location b ON a.applocationid = b.applocationid
WHERE b.status = 'Active'`
if err := r.db.Raw(q1).Scan(&locations).Error; err != nil {
return nil, err
}
return locations, nil
}
func (r *orderRepository) GetMonthlyOrders(applocationid string) (*models.Ordermonths, error) {
var orderMonths models.Ordermonths
q2 := `
SELECT
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 1 THEN 1 ELSE 0 END), 0) AS jan,
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 2 THEN 1 ELSE 0 END), 0) AS feb,
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 3 THEN 1 ELSE 0 END), 0) AS mar,
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 4 THEN 1 ELSE 0 END), 0) AS apr,
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 5 THEN 1 ELSE 0 END), 0) AS may,
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 6 THEN 1 ELSE 0 END), 0) AS jun,
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 7 THEN 1 ELSE 0 END), 0) AS jul,
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 8 THEN 1 ELSE 0 END), 0) AS aug,
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 9 THEN 1 ELSE 0 END), 0) AS sep,
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 10 THEN 1 ELSE 0 END), 0) AS oct,
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 11 THEN 1 ELSE 0 END), 0) AS nov,
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 12 THEN 1 ELSE 0 END), 0) AS dece
FROM orders a
WHERE a.applocationid = ?
AND EXTRACT(YEAR FROM a.orderdate) = EXTRACT(YEAR FROM CURRENT_DATE)`
if err := r.db.Raw(q2, applocationid).Scan(&orderMonths).Error; err != nil {
return nil, err
}
return &orderMonths, nil
}
func (r *orderRepository) GetOrderInsights(tenantID int) ([]models.OrderInsightv1, error) {
var locations []models.OrderInsightv1
var params []interface{}
// ✅ Query 1: Get all locations (even without orders)
q1 := `SELECT b.locationid, b.locationname
FROM tenantlocations b
WHERE b.status = 'Active'`
if tenantID != 0 {
q1 += " AND b.tenantid = ?"
params = append(params, tenantID)
}
if err := r.db.Raw(q1, params...).Scan(&locations).Error; err != nil {
return nil, err
}
// ✅ Query 2: Monthly order counts per location
q2 := `SELECT
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 1 THEN 1 ELSE 0 END), 0) AS jan,
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 2 THEN 1 ELSE 0 END), 0) AS feb,
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 3 THEN 1 ELSE 0 END), 0) AS mar,
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 4 THEN 1 ELSE 0 END), 0) AS apr,
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 5 THEN 1 ELSE 0 END), 0) AS may,
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 6 THEN 1 ELSE 0 END), 0) AS jun,
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 7 THEN 1 ELSE 0 END), 0) AS jul,
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 8 THEN 1 ELSE 0 END), 0) AS aug,
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 9 THEN 1 ELSE 0 END), 0) AS sep,
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 10 THEN 1 ELSE 0 END), 0) AS oct,
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 11 THEN 1 ELSE 0 END), 0) AS nov,
COALESCE(SUM(CASE WHEN EXTRACT(MONTH FROM a.orderdate) = 12 THEN 1 ELSE 0 END), 0) AS dece
FROM orders a
WHERE a.locationid = ? AND EXTRACT(YEAR FROM a.orderdate) = EXTRACT(YEAR FROM CURRENT_DATE)`
if tenantID != 0 {
q2 += " AND a.tenantid = ?"
}
// ✅ Attach monthly order counts for each location
for i := range locations {
var orderMonths models.Ordermonths
if tenantID != 0 {
if err := r.db.Raw(q2, locations[i].Locationid, tenantID).Scan(&orderMonths).Error; err != nil {
return nil, err
}
} else {
if err := r.db.Raw(q2, locations[i].Locationid).Scan(&orderMonths).Error; err != nil {
return nil, err
}
}
locations[i].Ordermonths = &orderMonths
}
return locations, nil
}
func (r *orderRepository) GetOrderDetails(orderHeaderID int) ([]models.OrderDetails, error) {
var details []models.OrderDetails
query := `
SELECT a.orderdetailid, a.orderheaderid, a.tenantid, a.locationid, a.productid, a.productname, a.productdescription, a.supplyqty, a.balanceqty,
a.orderqty, a.price, a.unitid, a.unitname, a.productaddonid, a.addontypeid, a.productmapid, a.productvariantid, a.productaddondescription,
a.discountid, a.discountname, a.discountcode, a.discountterms, a.discountpercentage, a.discountamount, a.landingamount, a.taxpercentage,
a.taxamount, a.productsumprice, a.itemstatus, a.delivered, COALESCE(b.orderamount, 0) as orderamount, COALESCE(b.taxamount, 0) as totaltaxamount,
c.productimage
FROM orderdetails a
LEFT JOIN orders b ON b.orderheaderid = a.orderheaderid
LEFT JOIN products c ON a.productid = c.productid
WHERE a.orderheaderid = ?
`
if err := r.db.Raw(query, orderHeaderID).Scan(&details).Error; err != nil {
return nil, err
}
return details, nil
}
func (r *orderRepository) UpdateOrder(order *models.Orders) error {
tx := r.db.Begin()
if err := tx.Where("orderheaderid = ?", order.Orderheaderid).Updates(order).Error; err != nil {
tx.Rollback()
return err
}
return tx.Commit().Error
}
func (r *orderRepository) getSequenceno(tid int, prefix string) string {
type SeqResult struct {
Orderseqno string
}
var q1 string
// Formats the ID as tenantid-subprefix+seqno (e.g., 908-20245189)
if prefix == "ORD" {
q1 = `SELECT CONCAT(tenantid, '-',
CASE WHEN subprefix IS NULL OR CAST(subprefix AS TEXT) IN ('0', '0.0', '') THEN '' ELSE CAST(subprefix AS TEXT) END,
COALESCE(MAX(orderseqno) + 1, 1)) AS orderseqno
FROM ordersequences WHERE tenantid = ?
GROUP BY tenantid, subprefix`
} else if prefix == "INV" {
q1 = `SELECT CONCAT(tenantid, '-',
CASE WHEN subprefix IS NULL OR CAST(subprefix AS TEXT) IN ('0', '0.0', '') THEN '' ELSE CAST(subprefix AS TEXT) END,
COALESCE(MAX(invoiceseqno) + 1, 1)) AS orderseqno
FROM ordersequences WHERE tenantid = ?
GROUP BY tenantid, subprefix`
}
var result SeqResult
r.db.Raw(q1, tid).Scan(&result)
// Fallback if no row exists in the database
if result.Orderseqno == "" {
return fmt.Sprintf("%d-1", tid)
}
return result.Orderseqno
}
func (r *orderRepository) updateSeqno(tid int, prefix string) error {
var field string
if prefix == "ORD" {
field = "orderseqno"
} else if prefix == "INV" {
field = "invoiceseqno"
} else {
return fmt.Errorf("invalid prefix: %s", prefix)
}
// 🛠️ Improved: Check if row exists, if not, create it
var count int64
r.db.Table("ordersequences").Where("tenantid = ?", tid).Count(&count)
if count == 0 {
newSeq := map[string]interface{}{
"tenantid": tid,
field: 1,
"subprefix": nil, // Use NULL so CONCAT ignores it or set default here
}
return r.db.Table("ordersequences").Create(&newSeq).Error
}
// If it exists, perform the update
return r.db.Table("ordersequences").
Where("tenantid = ?", tid).
Update(field, gorm.Expr(fmt.Sprintf("%s + 1", field))).Error
}
func (r *orderRepository) CreateOrder(data models.Orders) (models.Orders, error) {
tx := r.db.Begin()
data.Orderid = r.getSequenceno(data.Tenantid, "ORD")
if err := tx.Create(&data).Error; err != nil {
tx.Rollback()
return models.Orders{}, err
}
for _, item := range data.Items {
item.Orderheaderid = data.Orderheaderid
item.Tenantid = data.Tenantid
item.Locationid = data.Locationid
if err := tx.Table("orderdetails").Create(&item).Error; err != nil {
tx.Rollback()
return models.Orders{}, err
}
stock := models.Productstock{
Tenantid: data.Tenantid,
Stockdate: time.Now(),
Locationid: data.Locationid,
Productid: item.Productid,
Quantity: int(item.Orderqty),
Stocktype: "out",
Status: "Active",
}
if err := tx.Table("productstocks").Create(&stock).Error; err != nil {
tx.Rollback()
return models.Orders{}, err
}
}
if err := r.updateSeqno(data.Tenantid, "ORD"); err != nil {
log.Println("updateSeqno error:", err)
}
if err := tx.Commit().Error; err != nil {
return models.Orders{}, err
}
var order models.Orders
if err := r.db.Where("orderheaderid = ?", data.Orderheaderid).First(&order).Error; err != nil {
return models.Orders{}, err
}
var items []models.OrderDetail
if err := r.db.Table("orderdetails").Where("orderheaderid = ?", data.Orderheaderid).Find(&items).Error; err == nil {
order.Items = items
}
return order, nil
}
func (r *orderRepository) getOrderDetailsByHeaderID(orderHeaderID int) ([]models.OrderDetails, float64, float64, error) {
var details []models.OrderDetails
var orderAmount float64
var totalTaxAmount float64
query := `
SELECT a.orderdetailid,a.orderheaderid,a.tenantid,a.locationid,a.productid,a.productname,a.productdescription,a.supplyqty,a.balanceqty,a.orderqty,a.price,a.unitid,
a.unitname,a.productaddonid,a.addontypeid,a.productmapid,a.productvariantid,a.productaddondescription,a.discountid,a.discountname,a.discountcode,a.discountterms,
a.discountpercentage,a.discountamount,a.landingamount,a.taxpercentage,a.taxamount,a.productsumprice,a.itemstatus,a.delivered,COALESCE(b.orderamount, 0) as orderamount,
COALESCE(b.taxamount, 0) as totaltaxamount,c.productimage
FROM orderdetails a
LEFT JOIN orders b ON b.orderheaderid = a.orderheaderid
LEFT JOIN products c ON a.productid = c.productid
WHERE a.orderheaderid = ?`
err := r.db.Raw(query, orderHeaderID).Scan(&details).Error
if err != nil {
return nil, 0, 0, err
}
if len(details) > 0 {
orderAmount = details[0].Orderamount
totalTaxAmount = details[0].Totaltaxamount
}
return details, orderAmount, totalTaxAmount, nil
}
func (r *orderRepository) GetCustomerOrdersv3(customerID, tenantID, moduleID, fromDate, toDate, orderStatus, keyword string, pageSize, offset int) ([]models.CustomerOrder, error) {
orders := make([]models.CustomerOrder, 0)
baseQuery := `
SELECT a.orderheaderid, a.applocationid, 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, a.pending, a.processing, a.ready,
a.delivered, a.cancelled, a.deliverycharge, a.kms, a.customerid, a.pickupaddress,
a.pickuplat, a.pickuplong, a.pickupcustomer, a.pickupcontactno, a.pickuplocation AS pickupsuburb,
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,
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
WHERE 1=1
`
params := []interface{}{}
if customerID != "" {
baseQuery += " AND a.customerid = ?"
params = append(params, customerID)
}
if tenantID != "" && tenantID != "0" {
baseQuery += " AND a.tenantid = ?"
params = append(params, tenantID)
}
if moduleID != "" {
baseQuery += " AND a.moduleid = ?"
params = append(params, moduleID)
}
if fromDate != "" && toDate != "" {
baseQuery += " AND DATE(a.orderdate) BETWEEN ? AND ?"
params = append(params, fromDate, toDate)
}
if orderStatus != "" {
baseQuery += " AND a.orderstatus = ?"
params = append(params, orderStatus)
}
if keyword != "" {
baseQuery += " AND EXISTS (SELECT 1 FROM orderdetails od WHERE od.orderheaderid = a.orderheaderid AND od.productname LIKE ?)"
params = append(params, "%"+keyword+"%")
}
baseQuery += " ORDER BY a.orderheaderid DESC LIMIT ? OFFSET ?"
params = append(params, pageSize, offset)
if err := r.db.Raw(baseQuery, params...).Scan(&orders).Error; err != nil {
return nil, err
}
// 🚀 NO LOOPING YET — Now fetch all details in one query
return r.attachOrderDetails(orders)
}
func (r *orderRepository) attachOrderDetails(orders []models.CustomerOrder) ([]models.CustomerOrder, error) {
if len(orders) == 0 {
return orders, nil
}
orderIDs := make([]int, 0, len(orders))
for _, o := range orders {
orderIDs = append(orderIDs, o.Orderheaderid)
}
var details []models.OrderDetails
query := `
SELECT a.*, p.productimage
FROM orderdetails a
LEFT JOIN products p ON a.productid = p.productid
WHERE a.orderheaderid IN ?
`
if err := r.db.Raw(query, orderIDs).Scan(&details).Error; err != nil {
return nil, err
}
// map orderheaderid → []details
detailMap := map[int][]models.OrderDetails{}
for _, d := range details {
detailMap[d.Orderheaderid] = append(detailMap[d.Orderheaderid], d)
}
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
}
}
return orders, nil
}
func (r *orderRepository) GetTenantLocationOrders(input models.DeliveryQuery) ([]models.OrderInfo, error) {
var data []models.OrderInfo
var params []interface{}
offset := (input.Pageno - 1) * input.Pagesize
// Start building SQL
query := base + `
WHERE a.tenantid = ?
AND a.locationid = ?
`
params = append(params, input.Tenantid, input.Locationid)
// Status filter
if input.Status == "ongoing" {
query += ` AND a.orderstatus IN ('pending','processing','ready')`
} else if input.Status != "" {
query += ` AND a.orderstatus = ?`
params = append(params, input.Status)
}
// Applocation filter
if input.Applocationid != 0 {
query += ` AND a.applocationid = ?`
params = append(params, input.Applocationid)
}
// Config filter
if input.Configid != 0 {
query += ` AND a.configid = ?`
params = append(params, input.Configid)
}
// Date filter
query += ` AND DATE(a.deliverytime) BETWEEN ? AND ?`
params = append(params, input.Fromdate, input.ToDate)
// Keyword filter
if input.Keyword != "" {
like := "%" + input.Keyword + "%"
query += ` AND (
a.pickupcustomer LIKE ? OR
c.tenantname LIKE ? OR
a.deliverycustomer LIKE ? OR
a.pickupcontactno LIKE ? OR
a.deliverycontactno LIKE ? OR
a.orderid LIKE ?
)`
params = append(params, like, like, like, like, like, like)
}
// Sorting + pagination
query += ` ORDER BY a.orderheaderid DESC LIMIT ? OFFSET ?`
params = append(params, input.Pagesize, offset)
fmt.Println("Executing Tenant+Location SQL:", query)
result := r.db.Raw(query, params...).Find(&data)
return data, result.Error
}