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 }