package domain import ( "context" "encoding/json" "errors" "nearle/db" "nearle/models" "nearle/utils" "strconv" "strings" "time" "github.com/jinzhu/copier" "github.com/redis/go-redis/v9" ) const ( deliveries = `SELECT distinct a.deliveryid,a.applocationid,f.locationname AS applocation,a.orderheaderid,a.configid,a.tenantid,a.partnerid,a.locationid,a.userid,a.categoryid,a.subcategoryid,a.moduleid, a.orderid,a.deliverydate,a.orderstatus,a.assigntime,a.starttime,a.arrivaltime,a.pickuptime,a.deliverytime,a.canceltime,a.acceptedtime, a.customerid,a.pickupcustomer,a.pickupcontactno,a.pickuplocationid,a.pickupaddress,a.pickuplocation,a.pickuplat,a.pickuplon, a.deliverycustomerid,a.deliverycustomer,a.deliverycontactno,a.deliverylocationid,a.deliveryaddress,a.deliverylocation, a.droplat,a.droplon,a.deliverylat,a.deliverylong, a.riderslat,a.riderslon,a.deliveryamt,a.kms,a.actualkms,a.riderkms,a.deliverycharges,a.deliverytype,a.paymenttype,a.smsdelivery,a.quantity,a.collectionamt,a.collectedamt,a.collectionstatus, a.notes,a.ordernotes,a.step,a.eta,a.previouskms,a.cumulativekms,a.ridertime,b.tenantname,b.primarycontact as tenantcontactno,b.tenanttoken,b.suburb as tenantsuburb,b.city as tenantcity, b.address AS tenantaddress, CONCAT(c.firstname, ' ', c.lastname) AS ridername,c.userfcmtoken,c.contactno as ridercontact,e.locationname,e.suburb AS locationsuburb,e.contactno AS locationcontactno,e.address AS locationaddress, h.slab, h.pricingdate, h.baseprice, h.minkm, h.priceperkm, h.maxkm, h.orders, h.othercharges, h.surgecharges, a.expecteddeliverytime, a.profit, a.transitminutes, a.calculationdistancekm FROM deliveries a INNER JOIN tenants b ON a.tenantid=b.tenantid INNER JOIN app_users c ON a.userid=c.userid INNER JOIN tenantlocations e ON a.locationid=e.locationid INNER JOIN app_location f ON a.applocationid = f.applocationid INNER JOIN app_locationconfig g ON f.applocationid = g.applocationid LEFT JOIN tenantpricing h ON a.tenantid = h.tenantid` ) func PublishLog(input []models.Deliverylogs) error { logInfo("PublishLog", "records", len(input)) tx := db.DB.Begin() for i := range input { t1 := tx.Create(&input[i]) if t1.Error != nil { logError("PublishLog failed", "error", tx.Error) tx.Rollback() return t1.Error } } err := tx.Commit().Error if err != nil { return err } return nil } func CreateDeliveries(data []models.Deliveries) error { logInfo("CreateDeliveries", "records", len(data)) var que []models.Deliveryqueues var ord models.Updateorderstatus tx := db.DB.Begin() for i := range data { t1 := tx.Create(&data[i]) if t1.Error != nil { logError("CreateDeliveries failed", "error", tx.Error) tx.Rollback() return t1.Error } if err := copier.Copy(&que, &data[i]); err != nil { return err } t2 := tx.Create(&que) if t2.Error != nil { logError("CreateDeliveries queue failed", "error", tx.Error) tx.Rollback() return t2.Error } ord.Orderstatus = data[i].Orderstatus ord.Pending = data[i].Deliverydate t3 := tx.Table("orders").Where("orderheaderid=?", data[i].Orderheaderid).Updates(&ord) if t3.Error != nil { logError("CreateDeliveries order update failed", "error", tx.Error) tx.Rollback() return t3.Error } } err := tx.Commit().Error if err != nil { return err } return nil } func CreateDeliveriesV2(data []models.Deliveries) ([]int64, error) { ctx := db.Ctx var deliveryIDs []int64 logInfo("πŸ”₯ CreateDeliveriesV2 DOMAIN CALLED") for _, d := range data { // πŸ”’ Rider guard key riderKey := "rider:" + strconv.Itoa(d.Userid) + ":active_delivery" // ⏱ delivery TTL (example: 2 hours) ttl := 2 * time.Hour // πŸ”’ PREVENT DOUBLE ASSIGN (CREATE ONLY IF NOT EXISTS) ok, err := db.Rdb.SetNX(ctx, riderKey, "LOCK", ttl).Result() if err != nil { return nil, err } if !ok { return nil, errors.New("rider " + strconv.Itoa(d.Userid) + " already has active delivery") } // πŸ”₯ Generate delivery ID deliveryID, err := db.Rdb.Incr(ctx, "counter:deliveryid").Result() if err != nil { db.Rdb.Del(ctx, riderKey) return nil, err } deliveryIDs = append(deliveryIDs, deliveryID) // πŸ”‘ Redis keys deliveryKey := "delivery:active:" + strconv.FormatInt(deliveryID, 10) cityKey := "city:" + strconv.Itoa(d.Tenantid) + ":active_deliveries" pipe := db.Rdb.TxPipeline() // πŸ”₯ ACTIVE DELIVERY HASH (AUTO-CREATES) pipe.HSet(ctx, deliveryKey, map[string]interface{}{ "delivery_id": deliveryID, "orderheaderid": d.Orderheaderid, "orderid": d.Orderid, "tenantid": d.Tenantid, // city "partnerid": d.Partnerid, "rider_id": d.Userid, "status": "ASSIGNED", "pickupaddress": d.Pickupaddress, "deliveryaddress": d.Deliveryaddress, "pickuplat": d.Pickuplat, "pickuplon": d.Pickuplon, "deliverylat": d.Deliverylat, "deliverylong": d.Deliverylong, "eta": d.Eta, "expecteddeliverytime": d.Expecteddeliverytime, "profit": d.Profit, "transitminutes": d.Transitminutes, "calculationdistancekm": d.Calculationdistancekm, "created_at": time.Now().Unix(), "last_updated": time.Now().Unix(), }) // πŸ”₯ CITY β†’ ACTIVE DELIVERIES INDEX (AUTO-CREATES) pipe.SAdd(ctx, cityKey, deliveryID) // πŸ”₯ SET RIDER VALUE (REPLACE LOCK) pipe.Set(ctx, riderKey, deliveryID, ttl) // πŸ”₯ TTL ONLY ON DELIVERY & RIDER (NEVER CITY) pipe.Expire(ctx, deliveryKey, ttl) cmds, err := pipe.Exec(ctx) if err != nil { db.Rdb.Del(ctx, riderKey) return nil, err } // πŸ” Per-command safety check for _, cmd := range cmds { if cmd.Err() != nil { db.Rdb.Del(ctx, riderKey) return nil, cmd.Err() } } logInfo("βœ… Delivery created", "deliveryID", deliveryID) } logInfo("βœ… CreateDeliveriesV2 COMPLETED") return deliveryIDs, nil } func CreateDelivery(data models.Deliveries) error { logInfo("CreateDelivery", "orderheaderid", data.Orderheaderid) var que models.Deliveryqueues var ord models.Updateorderstatus tx := db.DB.Begin() t1 := tx.Table("deliveries").Create(&data) if t1.Error != nil { tx.Rollback() return t1.Error } if err := copier.Copy(&que, &data); err != nil { return err } t2 := tx.Table("deliveryqueues").Create(&que) if t2.Error != nil { logError("CreateDelivery queue failed", "error", tx.Error) tx.Rollback() return t2.Error } ord.Orderstatus = data.Orderstatus ord.Pending = data.Assigntime t3 := tx.Table("orders").Where("orderheaderid=?", data.Orderheaderid).Updates(&ord) if t3.Error != nil { logError("CreateDelivery order update failed", "error", tx.Error) tx.Rollback() return t3.Error } err := tx.Commit().Error if err != nil { return err } return nil } func UpdateDelivery(data models.UpdateDeliveryStatus) error { logInfo("UpdateDelivery", "deliveryid", data.Deliveryid, "status", data.Orderstatus) var ord models.Updateorderstatus var cloc models.Customerlocations tx := db.DB.Begin() t1 := tx.Table("deliveries").Where("deliveryid=?", data.Deliveryid).Updates(&data) if t1.Error != nil { logError("UpdateDelivery failed", "error", tx.Error) tx.Rollback() } if data.Orderstatus == "pending" { ord.Orderstatus = data.Orderstatus ord.Pending = data.Assigntime t2 := tx.Table("orders").Where("orderheaderid=?", data.Orderheaderid).Updates(&ord) if t2.Error != nil { logError("UpdateDelivery pending update failed", "error", tx.Error) tx.Rollback() } } if data.Orderstatus == "picked" { if data.Pickuplocationid != 0 && data.Deliverytype != "B" { cloc.Latitude = data.Riderslat cloc.Longitude = data.Riderslon cloc.Address = data.Address cloc.Suburb = data.Suburb cloc.City = data.City cloc.State = data.State cloc.Postcode = data.Postcode t5 := tx.Table("customerlocations").Where("locationid=?", data.Pickuplocationid).Updates(&cloc) if t5.Error != nil { logError("UpdateDelivery customer location update failed", "error", tx.Error) tx.Rollback() } } } if data.Orderstatus == "delivered" { ord.Orderstatus = data.Orderstatus ord.Delivered = data.Deliverytime t2 := tx.Table("orders").Where("orderheaderid=?", data.Orderheaderid).Updates(&ord) if t2.Error != nil { logError("UpdateDelivery delivered update failed", "error", tx.Error) tx.Rollback() } if data.Deliverylocationid != 0 && data.Deliverytype != "B" { cloc.Latitude = data.Deliverylat cloc.Longitude = data.Deliverylong cloc.Address = data.Address cloc.Suburb = data.Suburb cloc.City = data.City cloc.State = data.State cloc.Postcode = data.Postcode t5 := tx.Table("customerlocations").Where("locationid=?", data.Deliverylocationid).Updates(&cloc) if t5.Error != nil { logError("UpdateDelivery delivery location update failed", "error", tx.Error) tx.Rollback() } } } if data.Orderstatus == "cancelled" { ord.Orderstatus = data.Orderstatus ord.Cancelled = data.Canceltime t2 := tx.Table("orders").Where("orderheaderid=?", data.Orderheaderid).Updates(&ord) if t2.Error != nil { logError("UpdateDelivery cancelled update failed", "error", tx.Error) tx.Rollback() } } err := tx.Commit().Error if err != nil { return err } return err } func GetDeliveryQueues(uid int, fdate, tdate string) []models.Deliveryinfo { logInfo("GetDeliveryQueues", "userid", uid) var data []models.Deliveryinfo var q1 string if fdate != "" && tdate != "" { q1 = deliveries + " where a.orderstatus='pending' and a.userid= ? and a.deliverydate::date between ? and ? order by a.deliveryid asc" db.DB.Raw(q1, uid, fdate, tdate).Find(&data) } else { q1 = deliveries + " where a.orderstatus='pending' and a.userid= ? and a.deliverydate::date = CURRENT_DATE order by a.deliveryid asc" db.DB.Raw(q1, uid).Find(&data) } logInfo("GetDeliveryQueues Query executed", "userid", uid) return data } func GetDeliveryQueuesV1(uid int, fdate, tdate string) []models.Deliveryinfo { logInfo("GetDeliveryQueuesV1", "userid", uid) var data []models.Deliveryinfo var q1 string statusFilter := `a.orderstatus IN ('pending', 'accepted', 'arrived')` if fdate != "" && tdate != "" { q1 = deliveries + " WHERE " + statusFilter + " AND a.userid = ? AND a.deliverydate::date BETWEEN ? AND ? ORDER BY a.deliveryid ASC" db.DB.Raw(q1, uid, fdate, tdate).Find(&data) } else { q1 = deliveries + " WHERE " + statusFilter + " AND a.userid = ? AND a.deliverydate::date = CURRENT_DATE ORDER BY a.deliveryid ASC" db.DB.Raw(q1, uid).Find(&data) } return data } func GetDeliveryQueuesPicked(uid int, fdate, tdate string) []models.Deliveryinfo { logInfo("GetDeliveryQueuesPicked", "userid", uid) var data []models.Deliveryinfo var q1 string if fdate != "" && tdate != "" { q1 = deliveries + " where a.orderstatus='picked' and a.userid=? and a.deliverydate::date between ? and ? order by a.deliveryid asc" db.DB.Raw(q1, uid, fdate, tdate).Find(&data) } else { q1 = deliveries + " where a.orderstatus='picked' and a.userid=? and a.deliverydate::date = CURRENT_DATE order by a.deliveryid asc" db.DB.Raw(q1, uid).Find(&data) } return data } func GetDeliverylogs(did int) []models.Deliverylogs { logInfo("GetDeliverylogs", "deliveryid", did) var data []models.Deliverylogs q1 := "select * from deliverylogs where deliveryid=? order by logid asc" db.DB.Raw(q1, did).Find(&data) return data } func GetTenantDeliveries(input models.DeliveryQuery) []models.Deliveryinfo { logInfo("πŸ” Fetching Tenant Deliveries", "tenantid", input.Tenantid) var data []models.Deliveryinfo var queryBuilder strings.Builder var params []interface{} offset := (input.Pageno - 1) * input.Pagesize baseQuery := ` SELECT a.*, b.tenantname, CONCAT(c.firstname, ' ', c.lastname) AS ridername, c.contactno AS ridercontact, c.userfcmtoken, d.locationname, d.contactno AS locationcontactno, d.suburb AS locationsuburb, d.address AS locationaddress, e.slab, e.pricingdate, e.baseprice, e.minkm, e.priceperkm, e.maxkm, e.orders, e.othercharges, e.surgecharges FROM deliveries a JOIN tenants b ON a.tenantid = b.tenantid JOIN app_users c ON a.userid = c.userid JOIN tenantlocations d ON a.locationid = d.locationid JOIN tenantpricing e ON a.tenantid = e.tenantid WHERE b.moduleid = 6 AND a.tenantid = ? ` queryBuilder.WriteString(baseQuery) params = append(params, input.Tenantid) // βœ… USERID FILTER (FIX) if input.UserID > 0 { queryBuilder.WriteString(" AND a.userid = ?") params = append(params, input.UserID) } // βœ… STATUS FILTER (ignore "all") if input.Status != "" && strings.ToLower(input.Status) != "all" { queryBuilder.WriteString(" AND LOWER(a.orderstatus) = LOWER(?)") params = append(params, input.Status) } // βœ… DATE FILTER if input.Fromdate != "" && input.ToDate != "" { queryBuilder.WriteString(" AND a.deliverydate::date BETWEEN ? AND ?") params = append(params, input.Fromdate, input.ToDate) } // βœ… KEYWORD FILTER if input.Keyword != "" { k := "%" + strings.ToLower(input.Keyword) + "%" queryBuilder.WriteString(` AND ( LOWER(a.pickupcustomer) LIKE ? OR LOWER(a.deliverycustomer) LIKE ? OR LOWER(a.pickupcontactno) LIKE ? OR LOWER(a.deliverycontactno) LIKE ? OR LOWER(CAST(a.orderid AS CHAR)) LIKE ? OR LOWER(c.firstname) LIKE ? OR LOWER(c.lastname) LIKE ? OR LOWER(c.contactno) LIKE ? ) `) for i := 0; i < 8; i++ { params = append(params, k) } } queryBuilder.WriteString(" ORDER BY a.deliveryid DESC") if input.Pagesize > 0 { queryBuilder.WriteString(" LIMIT ? OFFSET ?") params = append(params, input.Pagesize, offset) } query := queryBuilder.String() // print("Final Query:", query) db.DB.Raw(query, params...).Scan(&data) return data } func GetPartnerDeliveries(input models.DeliveryQuery) []models.Deliveryinfo { logInfo("Partner Deliveries", "partnerid", input.Partnerid) var data []models.Deliveryinfo var qb strings.Builder var params []interface{} offset := (input.Pageno - 1) * input.Pagesize // πŸ”Ή Base query qb.WriteString(deliveries) qb.WriteString(` WHERE b.moduleid = 6 AND a.partnerid = ?`) params = append(params, input.Partnerid) // πŸ”Ή STATUS FILTER (ignore "all") if input.Status != "" && strings.ToLower(input.Status) != "all" { qb.WriteString(` AND LOWER(a.orderstatus) = LOWER(?)`) params = append(params, input.Status) } // πŸ”Ή DATE FILTER if input.Fromdate != "" && input.ToDate != "" { qb.WriteString(` AND a.deliverydate::date BETWEEN ? AND ?`) params = append(params, input.Fromdate, input.ToDate) } // πŸ”Ή ORDER qb.WriteString(` ORDER BY a.deliveryid DESC`) // πŸ”Ή PAGINATION if input.Pagesize > 0 { qb.WriteString(` LIMIT ? OFFSET ?`) params = append(params, input.Pagesize, offset) } finalQuery := qb.String() logInfo("Final Query", "query", finalQuery) logInfo("Params", "params", params) db.DB.Raw(finalQuery, params...).Scan(&data) return data } func GetCustomerDeliveries(input models.DeliveryQuery) []models.Deliveryinfo { logInfo("Customer Deliveries", "partnerid", input.Partnerid) var q1 string offset := (input.Pageno - 1) * input.Pagesize var data []models.Deliveryinfo // βœ… Apply status filter ONLY if status != "" AND status != "all" if input.Status != "" && strings.ToLower(input.Status) != "all" { if input.Fromdate != "" && input.ToDate != "" { if input.Pagesize != 0 { q1 = deliveries + " where b.moduleid=6 and a.partnerid=? and a.orderstatus=? and a.deliverydate::date between ? and ? order by deliveryid desc LIMIT ? OFFSET ?" db.DB.Raw(q1, input.Partnerid, input.Status, input.Fromdate, input.ToDate, input.Pagesize, offset).Find(&data) } else { q1 = deliveries + " where b.moduleid=6 and a.partnerid=? and a.orderstatus=? and a.deliverydate::date between ? and ? order by deliveryid desc" db.DB.Raw(q1, input.Partnerid, input.Status, input.Fromdate, input.ToDate).Find(&data) } } else { if input.Pagesize != 0 { q1 = deliveries + " where b.moduleid=6 and a.partnerid=? and a.orderstatus=? order by deliveryid desc LIMIT ? OFFSET ?" db.DB.Raw(q1, input.Partnerid, input.Status, input.Pagesize, offset).Find(&data) } else { q1 = deliveries + " where b.moduleid=6 and a.partnerid=? and a.orderstatus=? order by deliveryid desc" db.DB.Raw(q1, input.Partnerid, input.Status).Find(&data) } } } else { // βœ… status = "" OR status = "all" β†’ NO STATUS FILTER if input.Pagesize != 0 { q1 = deliveries + " where b.moduleid=6 and a.partnerid=? and a.deliverydate::date between ? and ? order by deliveryid desc LIMIT ? OFFSET ?" db.DB.Raw(q1, input.Partnerid, input.Fromdate, input.ToDate, input.Pagesize, offset).Find(&data) } else { q1 = deliveries + " where b.moduleid=6 and a.partnerid=? and a.deliverydate::date between ? and ? order by deliveryid desc" db.DB.Raw(q1, input.Partnerid, input.Fromdate, input.ToDate).Find(&data) } } return data } func GetAdminDeliveries(input models.DeliveryQuery) []models.Deliveryinfo { logInfo("Admin Deliveries", "applocationid", input.Applocationid) var data []models.Deliveryinfo var qb strings.Builder var params []interface{} offset := (input.Pageno - 1) * input.Pagesize qb.WriteString(` SELECT a.*, b.tenantname,b.primarycontact as tenantcontactno,b.tenanttoken,b.suburb as tenantsuburb,b.city as tenantcity, b.address AS tenantaddress, CONCAT(c.firstname, ' ', c.lastname) AS ridername,c.userfcmtoken,c.contactno as ridercontact, d.locationname,d.suburb AS locationsuburb,d.contactno AS locationcontactno,d.address AS locationaddress, e.locationname AS applocation, f.slab, f.pricingdate, f.baseprice, f.minkm, f.priceperkm, f.maxkm, f.orders, f.othercharges, f.surgecharges FROM deliveries a JOIN tenants b ON a.tenantid = b.tenantid JOIN app_users c ON a.userid = c.userid JOIN tenantlocations d ON a.locationid = d.locationid JOIN app_location e ON a.applocationid = e.applocationid JOIN tenantpricing f ON a.tenantid = f.tenantid WHERE b.moduleid = 6 AND a.applocationid = ? `) params = append(params, input.Applocationid) // βœ… TENANT FILTER if input.Tenantid != 0 { qb.WriteString(" AND a.tenantid = ?") params = append(params, input.Tenantid) } // βœ… LOCATION FILTER if input.Locationid != 0 { qb.WriteString(" AND a.locationid = ?") params = append(params, input.Locationid) } // βœ… USER / RIDER FILTER if input.UserID != 0 { qb.WriteString(" AND a.userid = ?") params = append(params, input.UserID) } // βœ… STATUS FILTER if input.Status != "" && strings.ToLower(input.Status) != "all" { qb.WriteString(" AND LOWER(a.orderstatus) = LOWER(?)") params = append(params, input.Status) } // βœ… DATE RANGE FILTER if input.Fromdate != "" && input.ToDate != "" { qb.WriteString(` AND a.deliverydate >= (CONCAT(?::text, ' 00:00:00'))::timestamp AND a.deliverydate <= (CONCAT(?::text, ' 23:59:59'))::timestamp `) params = append(params, input.Fromdate, input.ToDate) } qb.WriteString(" ORDER BY a.deliveryid DESC") // βœ… PAGINATION if input.Pagesize > 0 { qb.WriteString(" LIMIT ? OFFSET ?") params = append(params, input.Pagesize, offset) } finalQuery := qb.String() db.DB.Raw(finalQuery, params...).Scan(&data) return data } func GetUserDeliveries(input models.DeliveryQuery) []models.Deliveryinfo { var q1 string logInfo("User Deliveries", "userid", input.UserID) offset := (input.Pageno - 1) * input.Pagesize var data []models.Deliveryinfo var params []interface{} q1 = deliveries + " where b.moduleid=6 and a.userid=?" params = append(params, input.UserID) // CASE 1: status = all β†’ show all statuses if input.Status == "all" { q1 += " and a.deliverydate::date between ? and ? order by deliveryid desc" params = append(params, input.Fromdate, input.ToDate) // CASE 2: Specific status (picked, active, delivered…) } else if input.Status != "" { q1 += " and a.orderstatus=? and a.deliverydate::date between ? and ? order by deliveryid desc" params = append(params, input.Status, input.Fromdate, input.ToDate) // CASE 3: No status passed β†’ default statuses } else { q1 += " and a.orderstatus in ('picked','active','skipped') and a.deliverydate::date between ? and ? order by deliveryid desc" params = append(params, input.Fromdate, input.ToDate) } if input.Pagesize != 0 { q1 += " LIMIT ? OFFSET ?" params = append(params, input.Pagesize, offset) } db.DB.Raw(q1, params...).Find(&data) return data } func GetUserDeliveriesv1(input models.DeliveryQuery) []models.Deliveryinfo { var q1 string logInfo("User Deliveriesv1", "userid", input.UserID) offset := (input.Pageno - 1) * input.Pagesize var data []models.Deliveryinfo if input.Status != "" { if input.Pagesize != 0 { logInfo("Rider Deliveriesv2") q1 = deliveries + " where a.userid=? and a.orderstatus=? and a.deliverydate::date between ? and ? order by deliveryid desc LIMIT ? OFFSET ?" db.DB.Raw(q1, input.UserID, input.Status, input.Fromdate, input.ToDate, input.Pagesize, offset).Find(&data) } else { logInfo("Rider Deliveriesv1") q1 = deliveries + " where a.userid=? and a.orderstatus=? and a.deliverydate::date between ? and ? order by deliveryid asc" db.DB.Raw(q1, input.UserID, input.Status, input.Fromdate, input.ToDate).Find(&data) } } else { if input.Pagesize != 0 { logInfo("Rider Deliveriesv2") q1 = deliveries + " where a.orderstatus in ('picked') and a.userid=? and a.deliverydate::date between ? and ? order by deliveryid desc LIMIT ? OFFSET ?" db.DB.Raw(q1, input.UserID, input.Fromdate, input.ToDate, input.Pagesize, offset).Find(&data) } else { logInfo("Rider Deliveriesv1") q1 = deliveries + " where a.orderstatus in ('picked') and a.userid=? and a.deliverydate::date between ? and ? order by deliveryid desc" db.DB.Raw(q1, input.UserID, input.Fromdate, input.ToDate).Find(&data) } } return data } func GetAppUserDeliveries(input models.DeliveryQuery) []models.Deliveryinfo { var data []models.Deliveryinfo logInfo("App User Deliveries", "appuserid", input.UserID) var ( q1 strings.Builder params []interface{} ) offset := (input.Pageno - 1) * input.Pagesize // πŸ”Ή Base query q1.WriteString(deliveries) q1.WriteString(" WHERE b.moduleid = 6 AND g.status = 'Active' ") // πŸ”Ή Apply userid filter ONLY if userid > 0 if input.UserID > 0 { q1.WriteString(" AND g.userid = ? ") params = append(params, input.UserID) } // πŸ”Ή Status filter (IGNORE if status = all) if input.Status != "" && strings.ToLower(input.Status) != "all" { q1.WriteString(" AND a.orderstatus = ? ") params = append(params, input.Status) } // πŸ”Ή Date filter if input.Fromdate != "" && input.ToDate != "" { q1.WriteString(" AND a.deliverydate::date BETWEEN ? AND ? ") params = append(params, input.Fromdate, input.ToDate) } // πŸ”Ή Keyword filter (case-insensitive) if input.Keyword != "" { k := "%" + strings.ToLower(input.Keyword) + "%" q1.WriteString(` AND ( LOWER(a.pickupcustomer) LIKE ? OR LOWER(b.tenantname) LIKE ? OR LOWER(a.deliverycustomer) LIKE ? OR LOWER(a.pickupcontactno) LIKE ? OR LOWER(a.deliverycontactno) LIKE ? OR LOWER(CAST(a.orderid AS CHAR)) LIKE ? OR LOWER(CAST(a.deliveryid AS CHAR)) LIKE ? OR LOWER(c.firstname) LIKE ? OR LOWER(c.contactno) LIKE ? ) `) for i := 0; i < 9; i++ { params = append(params, k) } } q1.WriteString(" ORDER BY a.deliveryid DESC ") if input.Pagesize > 0 { q1.WriteString(" LIMIT ? OFFSET ? ") params = append(params, input.Pagesize, offset) } db.DB.Raw(q1.String(), params...).Scan(&data) return data } func GetDeliveries(input models.DeliveryQuery) []models.Deliveryinfo { var data []models.Deliveryinfo var queryBuilder strings.Builder var params []interface{} logInfo("Get All Deliveries -new") offset := (input.Pageno - 1) * input.Pagesize baseQuery := ` SELECT a.*, b.tenantname, c.userid, CONCAT(c.firstname, ' ', c.lastname) AS ridername, c.contactno AS ridercontact, d.slab, d.pricingdate, d.baseprice, d.minkm, d.priceperkm, d.maxkm, d.orders, d.othercharges, d.surgecharges FROM deliveries a JOIN tenants b ON a.tenantid = b.tenantid JOIN app_users c ON a.userid = c.userid JOIN tenantpricing d ON a.tenantid = d.tenantid WHERE 1=1 ` queryBuilder.WriteString(baseQuery) // βœ… DATE FILTER if input.Fromdate != "" && input.ToDate != "" { queryBuilder.WriteString(" AND b.moduleid=6 AND a.deliverydate::date BETWEEN ? AND ?") params = append(params, input.Fromdate, input.ToDate) } // βœ… STATUS FILTER (ignore "all") if input.Status != "" && strings.ToLower(input.Status) != "all" { queryBuilder.WriteString(" AND b.moduleid=6 AND LOWER(a.orderstatus) = LOWER(?)") params = append(params, input.Status) } // βœ… KEYWORD FILTER if input.Keyword != "" { k := "%" + strings.ToLower(input.Keyword) + "%" queryBuilder.WriteString(` AND ( LOWER(a.pickupcustomer) LIKE ? OR LOWER(b.tenantname) LIKE ? OR LOWER(a.deliverycustomer) LIKE ? OR LOWER(a.pickupcontactno) LIKE ? OR LOWER(a.deliverycontactno) LIKE ? OR LOWER(CAST(a.orderid AS CHAR)) LIKE ? ) `) for i := 0; i < 6; i++ { params = append(params, k) } } queryBuilder.WriteString(" ORDER BY a.deliveryid DESC") if input.Pagesize > 0 { queryBuilder.WriteString(" LIMIT ? OFFSET ?") params = append(params, input.Pagesize, offset) } query := queryBuilder.String() db.DB.Raw(query, params...).Scan(&data) return data } func GetTenantLocationDeliveries(input models.DeliveryQuery) []models.Deliveryinfo { logInfo("Tenant Location Deliveries", "tenantid", input.Tenantid, "locationid", input.Locationid) var data []models.Deliveryinfo var queryBuilder strings.Builder var params []interface{} offset := (input.Pageno - 1) * input.Pagesize // πŸ”Ή Base query queryBuilder.WriteString(deliveries) queryBuilder.WriteString(` WHERE b.moduleid = 6 AND a.tenantid = ? AND a.locationid = ?`) params = append(params, input.Tenantid, input.Locationid) // πŸ”Ή USER FILTER (apply only if userid > 0) if input.UserID > 0 { queryBuilder.WriteString(` AND a.userid = ?`) params = append(params, input.UserID) } // πŸ”Ή STATUS FILTER (ignore "all", case-insensitive) if input.Status != "" && strings.ToLower(input.Status) != "all" { queryBuilder.WriteString(` AND LOWER(a.orderstatus) = LOWER(?)`) params = append(params, input.Status) } // πŸ”Ή DATE FILTER if input.Fromdate != "" && input.ToDate != "" { queryBuilder.WriteString(` AND a.deliverydate::date BETWEEN ? AND ?`) params = append(params, input.Fromdate, input.ToDate) } // πŸ”Ή KEYWORD FILTER (case-insensitive) if input.Keyword != "" { k := "%" + strings.ToLower(input.Keyword) + "%" queryBuilder.WriteString(` AND ( LOWER(a.pickupcustomer) LIKE ? OR LOWER(b.tenantname) LIKE ? OR LOWER(a.deliverycustomer) LIKE ? OR LOWER(a.pickupcontactno) LIKE ? OR LOWER(a.deliverycontactno) LIKE ? OR LOWER(CAST(a.orderid AS CHAR)) LIKE ? ) `) // βœ” exactly 6 placeholders for i := 0; i < 6; i++ { params = append(params, k) } } // πŸ”Ή ORDER + PAGINATION queryBuilder.WriteString(` ORDER BY a.deliveryid DESC`) if input.Pagesize > 0 { queryBuilder.WriteString(` LIMIT ? OFFSET ?`) params = append(params, input.Pagesize, offset) } finalQuery := queryBuilder.String() logInfo("Final Query", "query", finalQuery) logInfo("Params", "params", params) db.DB.Raw(finalQuery, params...).Scan(&data) return data } func GetLocationDeliveries(input models.DeliveryQuery) []models.Deliveryinfo { logInfo("Location Deliveries", "locationid", input.Locationid) var q1 string var data []models.Deliveryinfo offset := (input.Pageno - 1) * input.Pagesize if input.Status != "" { if input.Fromdate != "" && input.ToDate != "" { if input.Pagesize != 0 { q1 = deliveries + " WHERE b.moduleid=6 and a.locationid=? AND a.orderstatus=? AND a.deliverydate::date BETWEEN ? AND ? ORDER BY a.deliveryid DESC LIMIT ? OFFSET ?" db.DB.Raw(q1, input.Locationid, input.Status, input.Fromdate, input.ToDate, input.Pagesize, offset).Find(&data) } else { q1 = deliveries + " WHERE b.moduleid=6 and a.locationid=? AND a.orderstatus=? AND a.deliverydate::date BETWEEN ? AND ? ORDER BY a.deliveryid DESC" db.DB.Raw(q1, input.Locationid, input.Status, input.Fromdate, input.ToDate).Find(&data) } } else { if input.Pagesize != 0 { q1 = deliveries + " WHERE b.moduleid=6 and a.locationid=? AND a.orderstatus=? ORDER BY a.deliveryid DESC LIMIT ? OFFSET ?" db.DB.Raw(q1, input.Locationid, input.Status, input.Pagesize, offset).Find(&data) } else { q1 = deliveries + " WHERE b.moduleid=6 and a.locationid=? AND a.orderstatus=? ORDER BY a.deliveryid DESC" db.DB.Raw(q1, input.Locationid, input.Status).Find(&data) } } } else { if input.Pagesize != 0 { q1 = deliveries + " WHERE b.moduleid=6 and a.locationid=? AND a.deliverydate::date BETWEEN ? AND ? ORDER BY a.deliveryid DESC LIMIT ? OFFSET ?" db.DB.Raw(q1, input.Locationid, input.Fromdate, input.ToDate, input.Pagesize, offset).Find(&data) } else { q1 = deliveries + " WHERE b.moduleid=6 and a.locationid=? AND a.deliverydate::date BETWEEN ? AND ? ORDER BY a.deliveryid DESC" db.DB.Raw(q1, input.Locationid, input.Fromdate, input.ToDate).Find(&data) } } return data } // func PublishLogv1(input []models.Deliverylogs) error { // key := "Deliverylogs" // for _, item := range input { // // Convert each item to JSON // jsonData, err := json.Marshal(item) // if err != nil { // return fmt.Errorf("failed to marshal delivery log: %v", err) // } // // Push each record into Redis list // if err := db.Rdb.RPush(db.Ctx, key, jsonData).Err(); err != nil { // return fmt.Errorf("failed to push to Redis: %v", err) // } // } // return nil // } // func PublishLogv1(input []models.Deliverylogs) error { // for _, item := range input { // // key per delivery // key := fmt.Sprintf("Deliverylogs:%d", item.Deliveryid) // // Convert to JSON // jsonData, err := json.Marshal(item) // if err != nil { // return fmt.Errorf("marshal error: %v", err) // } // // Write to delivery-specific list // if err := db.Rdb.RPush(db.Ctx, key, jsonData).Err(); err != nil { // return fmt.Errorf("redis push error: %v", err) // } // } // return nil // } func PublishLogv1(input []models.Deliverylogs) error { logInfo("PublishLogv1", "records", len(input)) pipe := db.Rdb.TxPipeline() for _, item := range input { logInfo("DELIVERY LOG RECEIVED", "deliveryid", item.Deliveryid, "userid", item.Userid, "logdate", item.Logdate, ) logTime, err := time.Parse("2006-01-02 15:04:05", item.Logdate) if err != nil { logError("❌ TIME PARSE FAILED", "error", err) continue } ts := logTime.Unix() logKey := "Deliverylogs:" + strconv.Itoa(item.Deliveryid) userIndexKey := "user:deliverylogs:" + strconv.Itoa(item.Userid) jsonData, _ := json.Marshal(item) pipe.RPush(db.Ctx, logKey, jsonData) pipe.ZAdd(db.Ctx, userIndexKey, redis.Z{ Score: float64(ts), Member: item.Deliveryid, }) logInfo("βœ… ZADD PREPARED", "key", userIndexKey, "deliveryid", item.Deliveryid) } _, err := pipe.Exec(db.Ctx) if err != nil { logError("❌ PIPELINE EXEC FAILED", "error", err) } return err } func GetDeliverylogsv1(did int) ([]models.Deliverylogs, error) { logInfo("GetDeliverylogsv1", "deliveryid", did) var result []models.Deliverylogs key := "Deliverylogs" // Get all elements from the Redis list values, err := db.Rdb.LRange(db.Ctx, key, 0, -1).Result() if err != nil { return nil, errors.New("failed to read from Redis: " + err.Error()) } for _, v := range values { var log models.Deliverylogs if err := json.Unmarshal([]byte(v), &log); err != nil { continue // skip invalid JSON entries } // filter only the deliveryid we need if log.Deliveryid == did { result = append(result, log) } } return result, nil } func GetDeliveryLogsv1(deliveryID string) ([]models.Deliverylogs, error) { logInfo("GetDeliveryLogsv1", "deliveryid", deliveryID) ctx := context.Background() var results []models.Deliverylogs key := "Deliverylogs:" + deliveryID // Fetch logs ONLY for this delivery listItems, err := db.Rdb.LRange(ctx, key, 0, -1).Result() if err != nil { return nil, errors.New("redis lrange error: " + err.Error()) } for _, item := range listItems { var log models.Deliverylogs if err := json.Unmarshal([]byte(item), &log); err != nil { continue } // Fetch username using redis cached function if log.Userid != 0 { user, err := GetUserCached(log.Userid) if err == nil { log.Firstname = user.Firstname log.Lastname = user.Lastname } } results = append(results, log) } return results, nil } // func GetDeliveryCached(deliveryID int) (models.Delivery, error) { // ctx := context.Background() // var data models.Delivery // key := fmt.Sprintf("delivery:info:%d", deliveryID) // // Check in Redis // cached, err := db.Rdb.Get(ctx, key).Result() // if err == nil { // json.Unmarshal([]byte(cached), &data) // return data, nil // } // // Fetch from DB if not cached // q := ` // SELECT deliveryid, pickupcustomer, deliverycustomer, // pickupcontactno, deliverycontactno // FROM deliveries // WHERE deliveryid=? LIMIT 1 // ` // if err := db.DB.Raw(q, deliveryID).Scan(&data).Error; err != nil { // return data, err // } // // Store back to Redis for 6 hours // b, _ := json.Marshal(data) // db.Rdb.Set(ctx, key, b, 6*time.Hour) // return data, nil // } func GetUserDeliveryLogs(userid int, fromdate, todate string) ([]models.Deliverylogs, error) { logInfo("GetUserDeliveryLogs", "userid", userid) var fromTS int64 = 0 var toTS int64 = time.Now().Unix() if fromdate != "" { t, err := time.Parse("2006-01-02", fromdate) if err != nil { return nil, errors.New("invalid fromdate") } fromTS = t.Unix() } if todate != "" { t, err := time.Parse("2006-01-02", todate) if err != nil { return nil, errors.New("invalid todate") } toTS = t.Add(23*time.Hour + 59*time.Minute + 59*time.Second).Unix() } // 1️⃣ Get delivery IDs for user (O(logN)) deliveryIDs, err := db.Rdb.ZRangeByScore( db.Ctx, "user:deliverylogs:"+strconv.Itoa(userid), &redis.ZRangeBy{ Min: strconv.FormatInt(fromTS, 10), Max: strconv.FormatInt(toTS, 10), }, ).Result() if err != nil || len(deliveryIDs) == 0 { return []models.Deliverylogs{}, nil } // 2️⃣ Batch fetch logs var result []models.Deliverylogs for _, id := range deliveryIDs { key := "Deliverylogs:" + id values, err := db.Rdb.LRange(db.Ctx, key, 0, -1).Result() if err != nil { continue } for _, v := range values { var log models.Deliverylogs if err := json.Unmarshal([]byte(v), &log); err == nil { result = append(result, log) } } } return result, nil } func logInfo(msg string, props ...interface{}) { utils.Logger.Infow(msg, props...) } func logError(msg string, props ...interface{}) { utils.Logger.Errorw(msg, props...) }