Files
backend_jupiter/domain/partner.go
2026-05-25 11:45:56 +05:30

1389 lines
34 KiB
Go

package domain
import (
"context"
"encoding/json"
"errors"
"nearle/db"
"nearle/models"
"nearle/utils"
"reflect"
"strconv"
"strings"
"time"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
func GetActiveRiders(partnerid, aid, uid int, keyword string, pageno, pagesize int) []models.RiderInfo {
data := make([]models.RiderInfo, 0) // ✅ IMPORTANT
var qb strings.Builder
var params []interface{}
offset := 0
if pageno > 0 && pagesize > 0 {
offset = (pageno - 1) * pagesize
}
qb.WriteString(`
WITH latest_logs AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY userid ORDER BY logdate DESC) AS rn
FROM riderlogs
WHERE logdate >= CURRENT_DATE
AND logdate < CURRENT_DATE + INTERVAL '1 day'
)
SELECT DISTINCT
a.userid,a.firstname,a.lastname,CONCAT(a.firstname,' ',a.lastname) AS fullname,a.contactno,a.userfcmtoken,a.partnerid,a.applocationid,c.identificationno,
c.registrationno,c.licenseno,c.vehiclename,c.vehicleno,d.shiftid,d.starttime,d.endtime,d.shifthours,d.basefare,d.fuelcharge,e.logdate,e.login,e.logout,
e.workhours,e.shorthours,e.logstatus,e.latitude,e.longitude,a.status,f.locationname AS applocation
FROM app_users a
JOIN ridersettings c ON c.userid = a.userid
JOIN ridershifts d ON d.shiftid = c.shiftid
JOIN latest_logs e ON e.userid = a.userid AND e.rn = 1
JOIN app_location f ON f.applocationid = a.applocationid
WHERE a.configid = 6
AND a.status = 'Active'
AND e.logstatus = 0
AND EXISTS (
SELECT 1
FROM app_userpools p
WHERE p.userid = a.userid
AND p.onduty = 1
)
`)
if aid != 0 {
qb.WriteString(" AND a.applocationid = ?")
params = append(params, aid)
}
if partnerid != 0 {
qb.WriteString(" AND a.partnerid = ?")
params = append(params, partnerid)
}
if uid != 0 {
qb.WriteString(" AND a.userid = ?")
params = append(params, uid)
}
if keyword != "" {
k := "%" + strings.ToLower(keyword) + "%"
qb.WriteString(`
AND (
LOWER(a.firstname) LIKE ? OR
LOWER(a.lastname) LIKE ? OR
LOWER(a.contactno) LIKE ? OR
LOWER(a.userid::text) LIKE ?
)
`)
for i := 0; i < 4; i++ {
params = append(params, k)
}
}
qb.WriteString(" ORDER BY a.userid DESC")
if pageno > 0 && pagesize > 0 {
qb.WriteString(" LIMIT ? OFFSET ?")
params = append(params, pagesize, offset)
}
utils.Logger.Debugf("ActiveRiders SQL: %s", qb.String())
utils.Logger.Debugf("Params: %v", params)
print(qb.String())
print(params)
db.DB.Raw(qb.String(), params...).Scan(&data)
return data
}
func GetActiveRidersv2(partnerid, aid, uid, tenantid int) []models.RiderInfo {
var data []models.RiderInfo
var q1 string
const riders = `SELECT DISTINCT a.*,a.userid, a.firstname, a.lastname,
CONCAT(a.firstname, ' ', a.lastname) AS fullname,
a.contactno, a.userfcmtoken, a.partnerid, a.applocationid,
c.identificationno, c.registrationno, c.licenseno, c.vehiclename, c.vehicleno,
d.shiftid, d.starttime, d.endtime, d.shifthours, d.basefare, d.fuelcharge,
e.logdate, e.login, e.logout, e.workhours, e.shorthours, e.logstatus, a.status,
f.locationname AS applocation
FROM
app_users a
LEFT JOIN ridersettings c ON a.userid = c.userid
INNER JOIN ridershifts d ON a.shiftid = d.shiftid
INNER JOIN (
SELECT r1.*
FROM riderlogs r1
INNER JOIN (
SELECT userid, MAX(logdate) AS max_logdate
FROM riderlogs
WHERE logdate::date = CURRENT_DATE
GROUP BY userid
) r2 ON r1.userid = r2.userid AND r1.logdate = r2.max_logdate
WHERE r1.logstatus = 0
) e ON a.userid = e.userid
INNER JOIN app_location f ON a.applocationid = f.applocationid
INNER JOIN app_locationconfig g ON g.applocationid = f.applocationid`
if aid != 0 {
q1 = riders + " WHERE a.configid = 6 AND a.status = 'Active' AND e.logdate::date = CURRENT_DATE AND e.logstatus = 0 AND a.applocationid = ?"
db.DB.Raw(q1, aid).Find(&data)
} else if partnerid != 0 {
q1 = riders + " WHERE a.configid = 6 AND a.status = 'Active' AND e.logdate::date = CURRENT_DATE AND e.logstatus = 0 AND a.partnerid = ?"
db.DB.Raw(q1, partnerid).Find(&data)
} else if tenantid != 0 {
q1 = riders + " WHERE a.status = 'Active' AND a.configid = 6 AND a.status = 'Active' AND a.tenantid = ?"
db.DB.Raw(q1, tenantid).Find(&data)
} else {
q1 = riders + " WHERE g.status = 'Active' AND a.configid = 6 AND a.status = 'Active' AND e.logdate::date = CURRENT_DATE AND e.logstatus = 0 AND g.userid = ?"
db.DB.Raw(q1, uid).Find(&data)
}
utils.Logger.Debugf("Query executed for riders")
return data
}
func GetRiderShifts(aid int) []models.Ridershifts {
var data []models.Ridershifts
q1 := "Select a.*,concat(a.starttime,'-',a.endtime) as shiftname from ridershifts a where a.applocationid=?"
db.DB.Raw(q1, aid).Find(&data)
return data
}
func GetRiderPricing(aid int) []models.RiderPricing {
var data []models.RiderPricing
q1 := `SELECT a.shiftid, a.basefare, a.additionalcharges, a.fuelcharge, a.applocationid, b.locationname from ridershifts a
LEFT JOIN app_location b ON a.applocationid = b.applocationid`
if aid > 0 {
q1 += ` WHERE a.applocationid=` + strconv.Itoa(aid)
}
db.DB.Raw(q1).Find(&data)
return data
}
func GetRiderPool(partnerid int) []models.RiderPool {
var data []models.RiderPool
q1 := `SELECT b.poolid,a.userid,a.firstname,a.lastname,CONCAT(a.firstname,' ',a.lastname) AS fullname,
a.contactno,a.userfcmtoken,a.partnerid,a.applocationid,
c.identificationno,c.registrationno,c.licenseno,c.vehiclename,c.vehicleno,
d.shiftid,d.starttime,d.endtime,d.shifthours,d.basefare,d.fuelcharge,a.status
FROM
app_users a
INNER JOIN app_userpools b ON a.userid=b.userid
INNER JOIN ridersettings c ON a.userid=c.userid
INNER JOIN ridershifts d ON c.shiftid=d.shiftid
WHERE a.configid=6 and a.status='Active' and a.partnerid=?`
db.DB.Raw(q1, partnerid).Find(&data)
return data
}
func GetRiderInfo(userid int) models.RiderInfo {
var data models.RiderInfo
q1 := `SELECT a.userid,a.firstname,a.lastname, CONCAT(a.firstname,' ',a.lastname) as fullname,
a.partnerid,a.configid,a.contactno,
a.address,a.suburb,a.city,a.state,a.postcode,a.latitude,a.longitude,
b.identificationno,b.vehicleno,b.vehiclename,b.licenseno,b.insuranceno,b.insurancedate,
c.shiftid,c.starttime,c.endtime,c.shifthours,c.basefare,c.additionalcharges,c.orders,c.fuelcharge,a.status,
a.applocationid,d.locationname as applocation,d.logseconds
FROM app_users a
INNER JOIN ridersettings b ON a.userid=b.userid
INNER JOIN ridershifts c on b.shiftid=c.shiftid
INNER JOIN app_location d on a.applocationid=d.applocationid
WHERE a.userid=?`
utils.Logger.Debugf("Query executed for userid: %d", userid)
db.DB.Raw(q1, userid).Find(&data)
return data
}
func GetRiderInfov2(userid int) models.RiderInfo {
var data models.RiderInfo
q1 := `SELECT a.userid,a.firstname,a.lastname, CONCAT(a.firstname,' ',a.lastname) as fullname,
a.partnerid,a.configid,a.contactno,
a.address,a.suburb,a.city,a.state,a.postcode,a.latitude,a.longitude,a.tenantid,
b.identificationno,b.vehicleno,b.vehiclename,b.licenseno,b.insuranceno,b.insurancedate,
c.shiftid,c.starttime,c.endtime,c.shifthours,c.basefare,c.additionalcharges,c.orders,c.fuelcharge,a.status,
a.applocationid,d.locationname as applocation,d.logseconds
FROM app_users a
LEFT JOIN ridersettings b ON a.userid=b.userid
INNER JOIN ridershifts c ON a.shiftid=c.shiftid
INNER JOIN app_location d on a.applocationid=d.applocationid
WHERE a.userid=?`
utils.Logger.Debugf("Query executed for userid: %d", userid)
db.DB.Raw(q1, userid).Find(&data)
return data
}
func GetRiderDetails(userid int) models.RiderDetails {
var data models.RiderDetails
q1 := `SELECT a.*,b.*,c.* from app_users a
INNER JOIN ridersettings b ON a.userid=b.userid
LEFT JOIN ridershifts c ON b.shiftid=c.shiftid
WHERE a.userid=?`
db.DB.Raw(q1, userid).Find(&data)
return data
}
func GetAllRiders(aid, pid, uid int, status, keyword string, pageno, pagesize int) []models.RiderInfo {
var data []models.RiderInfo
var q1 string
var params []interface{}
const riders = `SELECT DISTINCT a.userid,a.firstname,a.lastname,
CONCAT(a.firstname,' ',a.lastname) AS username,
a.partnerid,a.configid,a.contactno,
a.address,a.suburb,a.city,a.state,a.postcode,a.latitude,a.longitude,a.name,a.capacity,a.rangekm,a.batterypercentage,a.type,
b.identificationno,b.vehicleno,b.vehiclename,b.licenseno,b.insuranceno,b.insurancedate,
c.shiftid,c.starttime,c.endtime,c.shifthours,c.basefare,c.additionalcharges,c.orders,
c.fuelcharge,a.status,a.applocationid,d.locationname AS applocation
FROM app_users a
INNER JOIN ridersettings b ON a.userid=b.userid
INNER JOIN ridershifts c ON b.shiftid=c.shiftid
INNER JOIN app_location d ON a.applocationid=d.applocationid
INNER JOIN app_locationconfig e ON a.applocationid=e.applocationid`
conditions := []string{"e.status='Active'"}
if aid != 0 {
conditions = append(conditions, "a.applocationid=?")
params = append(params, aid)
}
if pid != 0 {
conditions = append(conditions, "a.partnerid=?")
params = append(params, pid)
}
if uid != 0 {
conditions = append(conditions, "a.userid=?")
params = append(params, uid)
}
if status != "" {
conditions = append(conditions, "a.status=?")
params = append(params, status)
}
if keyword != "" {
k := "%" + strings.ToLower(keyword) + "%"
conditions = append(conditions,
`(LOWER(a.firstname) LIKE ?
OR LOWER(a.lastname) LIKE ?
OR LOWER(a.contactno) LIKE ?
OR LOWER(a.userid::text) LIKE ?)`)
params = append(params, k, k, k, k)
}
q1 = riders + " WHERE " + strings.Join(conditions, " AND ") + " ORDER BY a.userid DESC"
// Apply pagination only if pagesize > 0
if pagesize > 0 {
offset := (pageno - 1) * pagesize
q1 += " LIMIT ? OFFSET ?"
params = append(params, pagesize, offset)
}
db.DB.Raw(q1, params...).Find(&data)
return data
}
func GetPartners(aid, pid int) []models.Partnerinfo {
// onduty := c.Query("onduty")
var data []models.Partnerinfo
var q1 string
if pid != 0 {
q1 = `select partnerid,applocationid,partnertypeid,partnername,primarycontact,primaryemail,
contactno,address,suburb,state,city,partnerimage from partnerinfo where status='Active' and partnerid=?`
db.DB.Raw(q1, pid).Find(&data)
} else if aid != 0 {
q1 = `select partnerid,applocationid,partnertypeid,partnername,primarycontact,primaryemail,
contactno,address,suburb,state,city,partnerimage from partnerinfo where status='Active' and applocationid=?`
db.DB.Raw(q1, aid).Find(&data)
} else {
q1 = `select partnerid,applocationid,partnertypeid,partnername,primarycontact,primaryemail,
contactno,address,suburb,state,city,partnerimage from partnerinfo where status='Active'`
db.DB.Raw(q1).Find(&data)
}
return data
}
func GetLocationConfig(uid, cid int) []models.Locationconfigs {
var data []models.Locationconfigs
q1 := `SELECT Distinct a.applocationid,a.locationname FROM app_location a
inner join app_locationconfig b ON a.applocationid=b.applocationid
INNER JOIN app_users c ON a.applocationid=c.applocationid
INNER JOIN app_roles d ON d.roleid=c.roleid
WHERE b.status='Active' and b.userid=? ORDER BY applocationid ASC`
db.DB.Raw(q1, uid).Find(&data)
return data
}
func GetPartnerUsers(aid int) []models.UserInfo {
var data []models.UserInfo
q1 := `SELECT a.userid,a.authname,a.email,a.configid,a.roleid,a.authmode,a.contactno,a.firstname,a.lastname,concat(a.firstname,' ',a.lastname) as fullname,
a.userfcmtoken,a.pin,a.deviceid,a.devicetype,a.tenantid,a.applocationid,a.partnerid
from app_users a where configid=5 and a.applocationid=?`
db.DB.Raw(q1, aid).Find(&data)
return data
}
func GetAdmintoken(pid, uid, tid, aid int) models.AdminToken {
var data models.AdminToken
var q1 string
if tid != 0 && pid != 0 {
q1 = `SELECT a.userid,a.userfcmtoken, b.closetime,b.opentime,c.tenantid
FROM app_users a
INNER JOIN partnerinfo b ON a.partnerid=b.partnerid
INNER JOIN tenants c ON a.userid=c.partneruserid
WHERE b.partnerid=? AND c.tenantid=?`
db.DB.Raw(q1, pid, tid).Find(&data)
} else if aid != 0 {
q1 = `SELECT distinct a.userid,a.userfcmtoken,b.notify,b.applocationid,c.opentime,c.closetime FROM app_users a
INNER JOIN app_locationconfig b ON a.userid=b.userid
INNER JOiN app_location c on a.applocationid= c.applocationid
WHERE b.notify='true' AND b.applocationid=?`
db.DB.Raw(q1, aid).Find(&data)
}
return data
}
func CreateRider(data models.Rider) error {
var userpools models.Userpools
tx := db.DB.Begin()
// ✅ FIX 1: Proper upsert for app_users
t1 := tx.Table("app_users").Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "email"}}, // REQUIRED
DoUpdates: clause.AssignmentColumns([]string{
"firstname",
"lastname",
"contactno",
"address",
"city",
"state",
}),
}).Create(&data)
if t1.Error != nil {
tx.Rollback()
return t1.Error
}
// ✅ FIX 2: Manually insert ridersettings (prevents ON CONFLICT error)
data.Ridersettings.Userid = data.Userid
data.Ridersettings.Partnerid = data.Partnerid
tRs := tx.Table("ridersettings").
Omit("riderid"). // 🚀 THIS FIXES YOUR ISSUE
Create(&data.Ridersettings)
if tRs.Error != nil {
tx.Rollback()
return tRs.Error
}
// ✅ Existing logic (unchanged)
userpools.Userid = data.Userid
userpools.Partnerid = data.Partnerid
userpools.Vehicleid = data.Ridersettings.Vehicleid
t2 := tx.Table("app_userpools").Create(&userpools)
if t2.Error != nil {
tx.Rollback()
return t2.Error
}
return tx.Commit().Error
}
func UpdateRiderSettings(data models.Rider) error {
tx := db.DB.Begin()
t1 := tx.Table("app_users").Where("userid=?", data.Userid).Updates(&data)
if t1.Error != nil {
tx.Rollback()
return t1.Error
}
t2 := tx.Table("ridersettings").Where("userid=?", data.Userid).Updates(&data.Ridersettings)
if t2.Error != nil {
tx.Rollback()
return t2.Error
}
err := tx.Commit().Error
if err != nil {
return err
}
return nil
}
// func UpdateRiderInfo(data models.Rider) error {
// tx := db.DB.Begin()
// t1 := tx.Table("app_users").Where("userid=?", data.Userid).Updates(&data)
// if t1.Error != nil {
// tx.Rollback()
// return t1.Error
// }
// err := tx.Commit().Error
// if err != nil {
// return err
// }
// return nil
// }
func UpdateRiderInfo(data models.Rider) error {
tx := db.DB.Begin()
t1 := tx.Table("app_users").Where("userid=?", data.Userid).Updates(&data)
if t1.Error != nil {
tx.Rollback()
return t1.Error
}
t2 := tx.Table("ridersettings").Where("userid=?", data.Userid).Updates(&data.Ridersettings)
if t2.Error != nil {
tx.Rollback()
return t2.Error
}
err := tx.Commit().Error
if err != nil {
return err
}
return nil
}
func CreateRiderShift(data models.Ridershifts) error {
tx := db.DB.Begin()
t1 := tx.Table("ridershifts").Create(&data)
if t1.Error != nil {
tx.Rollback()
return t1.Error
}
err := tx.Commit().Error
if err != nil {
return err
}
return nil
}
func CreateRiderLog(data models.Riderlogs) error {
tx := db.DB.Begin()
t1 := tx.Table("riderlogs").Create(&data)
if t1.Error != nil {
tx.Rollback()
return t1.Error
}
t2 := tx.Table("app_userpools").Where("userid=?", data.Userid).UpdateColumn("onduty", 1)
if t2.Error != nil {
tx.Rollback()
return t2.Error
}
err := tx.Commit().Error
if err != nil {
return err
}
return nil
}
func GetBreaklog(bid int) models.Riderbreaks {
var data models.Riderbreaks
q1 := "select * from riderbreaks where breakid=?"
db.DB.Raw(q1, bid).Find(&data)
return data
}
func CreateBreakLog(data models.Riderbreaks) (int, error) {
tx := db.DB.Begin()
t1 := tx.Table("riderbreaks").Create(&data)
if t1.Error != nil {
tx.Rollback()
return 0, t1.Error
}
t2 := tx.Table("app_userpools").Where("userid=?", data.Userid).UpdateColumn("onduty", 0)
if t2.Error != nil {
tx.Rollback()
return 0, t2.Error
}
err := tx.Commit().Error
if err != nil {
return 0, err
}
return data.Breakid, nil
}
func UpdateBreakLog(data models.Riderbreaks) error {
tx := db.DB.Begin()
t1 := tx.Table("riderbreaks").Where("breakid=?", data.Breakid).Updates(&data)
if t1.Error != nil {
tx.Rollback()
return t1.Error
}
t2 := tx.Table("app_userpools").Where("userid=?", data.Userid).UpdateColumn("onduty", 1)
if t2.Error != nil {
tx.Rollback()
return t2.Error
}
err := tx.Commit().Error
if err != nil {
return err
}
return nil
}
func UpdateRiderLog(data models.Riderlogs) error {
tx := db.DB.Begin()
t1 := tx.Table("riderlogs").Where("userid=?", data.Userid).Updates(&data)
if t1.Error != nil {
tx.Rollback()
return t1.Error
}
t2 := tx.Table("app_userpools").Where("userid=?", data.Userid).UpdateColumn("onduty", 0)
if t2.Error != nil {
tx.Rollback()
return t2.Error
}
err := tx.Commit().Error
if err != nil {
return err
}
return nil
}
func GetRiderLog(uid int) (models.Riderlogs, error) {
var data models.Riderlogs
q1 := `SELECT a.*,b.onduty from riderlogs a
INNER JOIN app_userpools b ON a.userid=b.userid WHERE a.userid=? and a.logdate::date=CURRENT_DATE`
err := db.DB.Raw(q1, uid).Find(&data).Error
if err != nil {
return data, err
}
return data, nil
}
func GetRiderLogs(pid, aid int, fdate, tdate, keyword string) []models.RiderlogDetails {
var data []models.RiderlogDetails
var q1 string
var params []interface{}
if pid != 0 {
if fdate != "" && tdate != "" {
q1 = `SELECT a.*,b.*,CONCAT(b.firstname,' ',b.lastname) AS username,
(SELECT SUM(breakhours) FROM riderbreaks WHERE logid = a.logid AND userid = a.userid) as breakhours
FROM riderlogs a
INNER JOIN app_users b ON a.userid=b.userid
WHERE a.partnerid = ?
AND a.logdate::date between ? and ?`
params = append(params, pid, fdate, tdate)
} else {
q1 = `SELECT a.*,b.*,CONCAT(b.firstname,' ',b.lastname) AS username,
(SELECT SUM(breakhours) FROM riderbreaks WHERE logid = a.logid AND userid = a.userid) as breakhours
FROM riderlogs a
INNER JOIN app_users b ON a.userid=b.userid
WHERE a.partnerid = ?
AND a.logdate::date=CURRENT_DATE`
params = append(params, pid)
}
} else if aid != 0 {
if fdate != "" && tdate != "" {
q1 = `SELECT a.*,b.*,CONCAT(b.firstname,' ',b.lastname) AS username,
(SELECT SUM(breakhours) FROM riderbreaks WHERE logid = a.logid AND userid = a.userid) as breakhours
FROM riderlogs a
INNER JOIN app_users b ON a.userid=b.userid
WHERE b.applocationid = ?
AND a.logdate::date between ? and ?`
params = append(params, aid, fdate, tdate)
} else {
q1 = `SELECT a.*,b.*,CONCAT(b.firstname,' ',b.lastname) AS username,
(SELECT SUM(breakhours) FROM riderbreaks WHERE logid = a.logid AND userid = a.userid) as breakhours
FROM riderlogs a
INNER JOIN app_users b ON a.userid=b.userid
WHERE b.applocationid = ?
AND a.logdate::date=CURRENT_DATE`
params = append(params, aid)
}
} else {
if fdate != "" && tdate != "" {
q1 = `SELECT a.*,b.*,CONCAT(b.firstname,' ',b.lastname) AS username,
(SELECT SUM(breakhours) FROM riderbreaks WHERE logid = a.logid AND userid = a.userid) as breakhours
FROM riderlogs a
INNER JOIN app_users b ON a.userid=b.userid
WHERE a.logdate::date between ? and ?`
params = append(params, fdate, tdate)
} else {
q1 = `SELECT a.*,b.*,CONCAT(b.firstname,' ',b.lastname) AS username,
(SELECT SUM(breakhours) FROM riderbreaks WHERE logid = a.logid AND userid = a.userid) as breakhours
FROM riderlogs a
INNER JOIN app_users b ON a.userid=b.userid
WHERE a.logdate::date=CURRENT_DATE`
}
}
if keyword != "" {
k := "%" + strings.ToLower(keyword) + "%"
q1 += `
AND (
LOWER(b.firstname) LIKE ? OR
LOWER(b.lastname) LIKE ? OR
LOWER(CONCAT(b.firstname,' ',b.lastname)) LIKE ? OR
b.userid LIKE ?
)`
params = append(params, k, k, k, keyword)
}
// Finish query
q1 += " ORDER BY logid ASC"
utils.Logger.Debugf("Query executed for RiderLogs")
db.DB.Raw(q1, params...).Find(&data)
return data
}
func GetRiderOrderCount(uid int) (int, error) {
var dc int
// q1 = `SELECT COUNT(*) as deliverycount FROM deliveryqueues WHERE queuestatus=0 and userid=` + strconv.Itoa(uid)
q1 := `SELECT COUNT(*) as deliverycount FROM deliveries
WHERE orderstatus IN('pending','accepted','arrived','picked') and userid=?`
db.DB.Raw(q1, uid).Find(&dc)
return dc, nil
}
func CreateBreakLogv1(data models.Riderbreaks) (int, error) {
if db.Rdb == nil {
return 0, errors.New("Redis client not initialized")
}
id, err := db.Rdb.Incr(db.Ctx, "riderbreaks:counter").Result()
if err != nil {
utils.Logger.Errorf("Redis INCR error: %v", err)
return 0, errors.New("failed to generate break ID")
}
data.Breakid = int(id)
jsonData, err := json.Marshal(data)
if err != nil {
utils.Logger.Errorf("JSON marshal error: %v", err)
return 0, errors.New("failed to serialize break data")
}
if err := db.Rdb.RPush(db.Ctx, "riderbreaks", jsonData).Err(); err != nil {
utils.Logger.Errorf("Redis RPush error: %v", err)
return 0, errors.New("failed to store break in Redis")
}
tx := db.DB.Begin()
if err := updateOnduty(tx, data.Userid); err != nil {
tx.Rollback()
return 0, err
}
if err := tx.Commit().Error; err != nil {
utils.Logger.Errorf("MySQL commit error: %v", err)
return 0, errors.New("failed to update onduty")
}
return data.Breakid, nil
}
func updateOnduty(tx *gorm.DB, userid int) error {
// Try update
result := tx.Table("app_userpools").
Where("userid = ?", userid).
UpdateColumn("onduty", 0)
if result.Error != nil {
return result.Error
}
// if result.RowsAffected == 0 {
// // INSERT instead of update
// err := tx.Table("app_userpools").Create(map[string]interface{}{
// "userid": userid,
// "onduty": 0,
// }).Error
// if err != nil {
// return errors.New("failed to insert onduty row: " + err.Error())
// }
// }
return nil
}
func GetBreaklogv1(breakID int) models.Riderbreaks {
if db.Rdb == nil {
return models.Riderbreaks{}
}
vals, err := db.Rdb.LRange(db.Ctx, "riderbreaks", 0, -1).Result()
if err != nil {
utils.Logger.Errorf("Redis LRange error: %v", err)
return models.Riderbreaks{}
}
var data models.Riderbreaks
for _, v := range vals {
var item models.Riderbreaks
if err := json.Unmarshal([]byte(v), &item); err != nil {
continue
}
if item.Breakid == breakID {
data = item
break
}
}
return data
}
func UpdateBreakLogv1(data models.Riderbreaks) error {
key := "riderbreaks"
values, err := db.Rdb.LRange(db.Ctx, key, 0, -1).Result()
if err != nil {
return errors.New("failed to read Redis list: " + err.Error())
}
if len(values) == 0 {
return errors.New("no data found in Redis list " + key)
}
var foundIndex int = -1
for i, val := range values {
var rb models.Riderbreaks
if err := json.Unmarshal([]byte(val), &rb); err != nil {
continue
}
if rb.Breakid == data.Breakid {
foundIndex = i
break
}
}
if foundIndex == -1 {
return errors.New("Break ID " + strconv.Itoa(data.Breakid) + " not found in Redis")
}
jsonData, err := json.Marshal(data)
if err != nil {
return errors.New("Redis marshal failed: " + err.Error())
}
if err := db.Rdb.LSet(db.Ctx, key, int64(foundIndex), jsonData).Err(); err != nil {
return errors.New("Redis LSET failed: " + err.Error())
}
tx := db.DB.Begin()
t2 := tx.Table("app_userpools").
Where("userid = ?", data.Userid).
UpdateColumn("onduty", 1)
if t2.Error != nil {
tx.Rollback()
return t2.Error
}
if err := tx.Commit().Error; err != nil {
return err
}
return nil
}
func GetRiderWeeklyKms(uid int) (*models.RiderWeeklyKms, error) {
var result []models.RiderKms
var overallKms float64
// 🔥 SAFE + POSTGRES COMPATIBLE QUERY
q1 := `
SELECT
TRIM(TO_CHAR(deliverydate, 'Dy')) AS day,
ROUND(
COALESCE(SUM(NULLIF(riderkms, '')::numeric), 0),
2) AS kms
FROM deliveries
WHERE userid = ?
AND deliverydate >= CURRENT_DATE - INTERVAL '7 days'
GROUP BY EXTRACT(DOW FROM deliverydate), TRIM(TO_CHAR(deliverydate, 'Dy'))
ORDER BY EXTRACT(DOW FROM deliverydate);
`
q2 := `
SELECT
ROUND(
COALESCE(SUM(NULLIF(riderkms, '')::numeric), 0),
2) AS overallkms
FROM deliveries
WHERE userid = ?;
`
// Execute queries
if err := db.DB.Raw(q1, uid).Scan(&result).Error; err != nil {
return nil, err
}
if err := db.DB.Raw(q2, uid).Scan(&overallKms).Error; err != nil {
return nil, err
}
// Map results
dayMap := make(map[string]float64)
for _, r := range result {
dayMap[r.Day] = r.Kms
}
// Ensure all 7 days
allDays := []string{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}
var final []models.RiderKms
var totalKms float64
for _, d := range allDays {
kms := dayMap[d]
final = append(final, models.RiderKms{
Day: d,
Kms: kms,
})
totalKms += kms
}
return &models.RiderWeeklyKms{
Details: final,
TotalKms: totalKms,
OverallKms: overallKms,
}, nil
}
func CreateRiderLogv1(data models.Riderlogs) error {
ctx := context.Background()
pong, err := db.Rdb.Ping(ctx).Result()
utils.Logger.Infof("[Redis] Ping: %s Error: %v", pong, err)
if err != nil {
return errors.New("redis connection error: " + err.Error())
}
tx := db.DB.Begin()
if err := tx.Table("riderlogs").Create(&data).Error; err != nil {
tx.Rollback()
return errors.New("mysql insert error (riderlogs): " + err.Error())
}
utils.Logger.Infof("[MySQL] Generated logid: %d", data.Logid)
if err := tx.Table("app_userpools").
Where("userid = ?", data.Userid).
UpdateColumn("onduty", 1).Error; err != nil {
tx.Rollback()
return errors.New("mysql update error (onduty): " + err.Error())
}
if err := tx.Commit().Error; err != nil {
return errors.New("mysql commit error: " + err.Error())
}
jsonData, err := json.Marshal(data)
if err != nil {
return errors.New("failed to marshal redis data: " + err.Error())
}
key := "riderlogs"
pushResult := db.Rdb.RPush(ctx, key, jsonData)
if pushResult.Err() != nil {
return errors.New("failed to push rider log to redis: " + pushResult.Err().Error())
}
insertedCount, _ := pushResult.Result()
utils.Logger.Infof("[Redis] RPush OK — key=%s, list length now=%d", key, insertedCount)
val, err := db.Rdb.LRange(ctx, key, -1, -1).Result()
if err != nil {
utils.Logger.Errorf("[Redis] LRange check error: %v", err)
} else {
utils.Logger.Infof("[Redis] Last inserted value: %v", val)
}
return nil
}
func UpdateRiderLogv1(data models.Riderlogs) error {
ctx := context.Background()
key := "riderlogs"
logs, err := db.Rdb.LRange(ctx, key, 0, -1).Result()
if err != nil {
return errors.New("failed to fetch logs from redis: " + err.Error())
}
found := false
for i, item := range logs {
var existing models.Riderlogs
if err := json.Unmarshal([]byte(item), &existing); err != nil {
continue
}
if existing.Userid == data.Userid {
found = true
existingVal := reflect.ValueOf(&existing).Elem()
dataVal := reflect.ValueOf(&data).Elem()
for i := 0; i < dataVal.NumField(); i++ {
field := dataVal.Field(i)
if !isZero(field) { // only update if non-zero
existingVal.Field(i).Set(field)
}
}
updatedJSON, _ := json.Marshal(existing)
if err := db.Rdb.LSet(ctx, key, int64(i), updatedJSON).Err(); err != nil {
return errors.New("failed to update redis: " + err.Error())
}
break
}
}
if !found {
return errors.New("rider log for userid " + strconv.Itoa(data.Userid) + " not found in redis")
}
tx := db.DB.Begin()
t1 := tx.Table("app_userpools").
Where("userid = ?", data.Userid).
UpdateColumn("onduty", 0)
if t1.Error != nil {
tx.Rollback()
return errors.New("mysql update error: " + t1.Error.Error())
}
if err := tx.Commit().Error; err != nil {
return errors.New("mysql commit error: " + err.Error())
}
return nil
}
func isZero(v reflect.Value) bool {
switch v.Kind() {
case reflect.String:
return v.Len() == 0
case reflect.Int, reflect.Int64, reflect.Float64:
return v.Int() == 0
case reflect.Ptr, reflect.Interface:
return v.IsNil()
default:
return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())
}
}
func CreateRiderSupport(data models.RiderSupport) error {
tx := db.DB.Begin()
t1 := tx.Table("ridersupport").Create(&data)
if t1.Error != nil {
tx.Rollback()
return t1.Error
}
err := tx.Commit().Error
if err != nil {
return err
}
return nil
}
func GetRiderSupport(uid int) ([]models.RiderSupport, error) {
var data []models.RiderSupport
q1 := "SELECT * FROM ridersupport WHERE userid=? ORDER BY ridersupportid DESC"
err := db.DB.Raw(q1, uid).Scan(&data).Error
if err != nil {
return data, err
}
return data, nil
}
func GetRiderLogsv1(fromdate, todate, keyword string, partnerid int) ([]models.Riderlogsv1, error) {
ctx := context.Background()
results := []models.Riderlogsv1{}
redisList, err := db.Rdb.LRange(ctx, "riderlogs", 0, -1).Result()
if err != nil {
return nil, errors.New("redis lrange error: " + err.Error())
}
if len(redisList) == 0 {
return results, nil
}
from, _ := time.Parse("2006-01-02", fromdate)
to, _ := time.Parse("2006-01-02", todate)
to = to.Add(24 * time.Hour)
keyword = strings.ToLower(keyword)
last := make(map[int]models.Riderlogsv1)
for _, item := range redisList {
idx := strings.Index(item, `"logdate":"`)
if idx == -1 {
continue
}
start := idx + len(`"logdate":"`)
end := start + 19
if end > len(item) {
continue
}
logDateStr := item[start:end]
logTime, err := time.Parse("2006-01-02 15:04:05", logDateStr)
if err != nil {
continue
}
if logTime.Before(from) || logTime.After(to) {
continue
}
var log models.Riderlogsv1
if err := json.Unmarshal([]byte(item), &log); err != nil {
continue
}
if partnerid > 0 && log.Partnerid != partnerid {
continue
}
if keyword != "" {
if !strings.Contains(strings.ToLower(log.Firstname), keyword) &&
!strings.Contains(strings.ToLower(log.Lastname), keyword) &&
!strings.Contains(strings.ToLower(log.Username), keyword) {
continue
}
}
if prev, ok := last[log.Userid]; ok {
prevTime, _ := time.Parse("2006-01-02 15:04:05", prev.Logdate)
if logTime.After(prevTime) {
last[log.Userid] = log
}
} else {
last[log.Userid] = log
}
}
for _, v := range last {
results = append(results, v)
}
return results, nil
}
func GetUserByID(userid int) (models.User, error) {
var user models.User
q := `SELECT userid, firstname, lastname FROM app_users WHERE userid=? LIMIT 1`
err := db.DB.Raw(q, userid).Scan(&user).Error
return user, err
}
func GetUserCached(userid int) (models.User, error) {
ctx := context.Background()
var user models.User
key := "user:info:" + strconv.Itoa(userid)
val, err := db.Rdb.Get(ctx, key).Result()
if err == nil {
json.Unmarshal([]byte(val), &user)
return user, nil
}
q := `SELECT *
FROM app_users
WHERE userid=? LIMIT 1`
if err := db.DB.Raw(q, userid).Scan(&user).Error; err != nil {
return user, err
}
b, _ := json.Marshal(user)
db.Rdb.Set(ctx, key, b, 6*time.Hour)
return user, nil
}
func GetAllRidersSummary(aid, pid, uid int, keyword string) models.RidersSummary {
var summary models.RidersSummary
var conditions []string
const baseQry = `
SELECT
COUNT(DISTINCT CASE WHEN a.status='Active' THEN a.userid END) AS active,
COUNT(DISTINCT CASE WHEN a.status='Inactive' THEN a.userid END) AS inactive,
COUNT(DISTINCT a.userid) AS total
FROM app_users a
INNER JOIN ridersettings b ON a.userid=b.userid
INNER JOIN ridershifts c ON b.shiftid=c.shiftid
INNER JOIN app_location d ON a.applocationid=d.applocationid
INNER JOIN app_locationconfig e
ON a.applocationid=e.applocationid AND e.status='Active'
WHERE 1=1
`
var params []interface{}
if aid != 0 {
conditions = append(conditions, "a.applocationid=?")
params = append(params, aid)
}
if pid != 0 {
conditions = append(conditions, "a.partnerid=?")
params = append(params, pid)
}
if uid != 0 {
conditions = append(conditions, "a.userid=?")
params = append(params, uid)
}
if keyword != "" {
k := "%" + strings.ToLower(keyword) + "%"
conditions = append(conditions, "(LOWER(a.firstname) LIKE ? OR LOWER(a.lastname) LIKE ? OR LOWER(a.contactno) LIKE ? OR LOWER(CAST(a.userid AS CHAR)) LIKE ?)")
params = append(params, k, k, k, k)
}
q := baseQry
if len(conditions) > 0 {
q += " AND " + strings.Join(conditions, " AND ")
}
utils.Logger.Debugf("SUMMARY QUERY Executed")
db.DB.Raw(q, params...).Scan(&summary)
return summary
}
type ActiveRidersSummary struct {
Total int `json:"total"`
}
func GetActiveRidersSummary(partnerid, aid, uid int, keyword string) ActiveRidersSummary {
var summary ActiveRidersSummary
var conditions []string
const baseQry = `
SELECT
COUNT(DISTINCT a.userid) AS total
FROM app_users a
INNER JOIN app_userpools b ON a.userid = b.userid
INNER JOIN ridersettings c ON a.userid = c.userid
INNER JOIN ridershifts d ON c.shiftid = d.shiftid
INNER JOIN (
SELECT r1.*
FROM riderlogs r1
INNER JOIN (
SELECT userid, MAX(logdate) AS max_logdate
FROM riderlogs
WHERE logdate::date = CURRENT_DATE
GROUP BY userid
) r2
ON r1.userid = r2.userid AND r1.logdate = r2.max_logdate
) e ON a.userid = e.userid
INNER JOIN app_location f ON a.applocationid = f.applocationid
INNER JOIN app_locationconfig g ON g.applocationid = f.applocationid
WHERE 1=1
`
conditions = append(conditions,
"a.configid = 6",
"a.status = 'Active'",
"b.onduty = 1",
"e.logdate::date = CURRENT_DATE",
"e.logstatus = 0",
)
var params []interface{}
if aid != 0 {
conditions = append(conditions, "a.applocationid = ?")
params = append(params, aid)
}
if partnerid != 0 {
conditions = append(conditions, "a.partnerid = ?")
params = append(params, partnerid)
}
if uid != 0 {
conditions = append(conditions, "a.userid = ?")
params = append(params, uid)
}
if keyword != "" {
k := "%" + strings.ToLower(keyword) + "%"
conditions = append(conditions, "(LOWER(a.firstname) LIKE ? OR LOWER(a.lastname) LIKE ? OR LOWER(a.contactno) LIKE ? OR LOWER(CAST(a.userid AS CHAR)) LIKE ?)")
params = append(params, k, k, k, k)
}
q := baseQry + " AND " + strings.Join(conditions, " AND ")
utils.Logger.Debugf("ACTIVE SUMMARY QUERY Executed")
db.DB.Raw(q, params...).Scan(&summary)
return summary
}