chore: update id order
This commit is contained in:
@@ -6,7 +6,6 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
@@ -22,52 +21,38 @@ var allowedStatuses = map[string]bool{
|
||||
// CountDeliveriesByStatus compte les livraisons d'un livreur par statut
|
||||
func (d *Database) CountDeliveriesByStatus(livreurUsername string, statuses string) (int, error) {
|
||||
if statuses == "" {
|
||||
// Cas simple: toutes les livraisons
|
||||
query := `SELECT COUNT(*)
|
||||
FROM commandes
|
||||
WHERE livreur_assign = $1`
|
||||
|
||||
var count int
|
||||
err := d.QueryRow(query, livreurUsername).Scan(&count)
|
||||
var result struct {
|
||||
Count int `gorm:"column:count"`
|
||||
}
|
||||
err := d.GDB.Raw(`SELECT COUNT(*) as count FROM commandes WHERE livreur_assign = ?`, livreurUsername).Scan(&result).Error
|
||||
if err != nil {
|
||||
log.Printf("❌ [CountDeliveries] Erreur: %v", err)
|
||||
return 0, fmt.Errorf("erreur comptage livraisons: %w", err)
|
||||
}
|
||||
return count, nil
|
||||
return result.Count, nil
|
||||
}
|
||||
|
||||
// ✅ Valider les statuts
|
||||
cleanStatuses, err := ValidateStatuses(statuses)
|
||||
if err != nil {
|
||||
log.Printf("❌ [CountDeliveries] Validation échouée: %v", err)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// ✅ Construire la requête avec IN et placeholders
|
||||
placeholders := make([]string, len(cleanStatuses))
|
||||
args := []interface{}{livreurUsername}
|
||||
|
||||
for i, status := range cleanStatuses {
|
||||
placeholders[i] = fmt.Sprintf("$%d", i+2)
|
||||
args = append(args, status)
|
||||
var result struct {
|
||||
Count int `gorm:"column:count"`
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(`SELECT COUNT(*)
|
||||
FROM commandes
|
||||
WHERE livreur_assign = $1
|
||||
AND status IN (%s)`, strings.Join(placeholders, ","))
|
||||
|
||||
var count int
|
||||
err = d.QueryRow(query, args...).Scan(&count)
|
||||
err = d.GDB.Raw(
|
||||
`SELECT COUNT(*) as count FROM commandes WHERE livreur_assign = ? AND status IN ?`,
|
||||
livreurUsername, cleanStatuses,
|
||||
).Scan(&result).Error
|
||||
if err != nil {
|
||||
log.Printf("❌ [CountDeliveries] Erreur: %v", err)
|
||||
return 0, fmt.Errorf("erreur comptage livraisons: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("✅ [CountDeliveries] %d livraisons pour %s avec statuts %v",
|
||||
count, livreurUsername, cleanStatuses)
|
||||
|
||||
return count, nil
|
||||
result.Count, livreurUsername, cleanStatuses)
|
||||
return result.Count, nil
|
||||
}
|
||||
|
||||
func ValidateStatuses(statuses string) ([]string, error) {
|
||||
@@ -77,7 +62,6 @@ func ValidateStatuses(statuses string) ([]string, error) {
|
||||
|
||||
statusList := strings.Split(statuses, ",")
|
||||
|
||||
// Liste blanche complète
|
||||
validStatusMap := map[string]bool{
|
||||
"pending": true,
|
||||
"assigned": true,
|
||||
@@ -93,12 +77,9 @@ func ValidateStatuses(statuses string) ([]string, error) {
|
||||
|
||||
for _, status := range statusList {
|
||||
status = strings.TrimSpace(status)
|
||||
|
||||
// Ignorer les chaînes vides
|
||||
if status == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if validStatusMap[status] {
|
||||
cleanStatuses = append(cleanStatuses, status)
|
||||
} else {
|
||||
@@ -106,7 +87,6 @@ func ValidateStatuses(statuses string) ([]string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// Logger les statuts invalides
|
||||
if len(invalidStatuses) > 0 {
|
||||
log.Printf("⚠️ [ValidateStatuses] Statuts invalides ignorés: %v", invalidStatuses)
|
||||
}
|
||||
@@ -120,32 +100,25 @@ func ValidateStatuses(statuses string) ([]string, error) {
|
||||
|
||||
// GetLastDeliveryDate récupère la date de la dernière livraison d'un livreur
|
||||
func (d *Database) GetLastDeliveryDate(livreurUsername string) (*time.Time, error) {
|
||||
query := `SELECT MAX(updated_at)
|
||||
FROM commandes
|
||||
WHERE livreur_assign = $1
|
||||
AND status = 'approved'`
|
||||
|
||||
var lastDate sql.NullTime
|
||||
err := d.QueryRow(query, livreurUsername).Scan(&lastDate)
|
||||
var result struct {
|
||||
LastDate *time.Time `gorm:"column:last_date"`
|
||||
}
|
||||
err := d.GDB.Raw(`
|
||||
SELECT MAX(updated_at) as last_date
|
||||
FROM commandes
|
||||
WHERE livreur_assign = ? AND status = 'approved'`, livreurUsername).Scan(&result).Error
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("erreur récupération dernière livraison: %w", err)
|
||||
}
|
||||
|
||||
if !lastDate.Valid {
|
||||
return nil, nil // Aucune livraison
|
||||
}
|
||||
|
||||
t := lastDate.Time
|
||||
return &t, nil
|
||||
return result.LastDate, nil
|
||||
}
|
||||
|
||||
// GetCurrentCommand récupère l'ID de la commande en cours d'un livreur
|
||||
func (d *Database) GetCurrentCommand(livreurUsername string) (int, error) {
|
||||
// Récupérer depuis Redis
|
||||
currentKey := fmt.Sprintf("delivery:current:%s", livreurUsername)
|
||||
currentIDStr, err := Redis.Get(RedisCtx, currentKey).Result()
|
||||
if err != nil {
|
||||
return 0, nil // Pas de commande en cours
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var currentID int
|
||||
@@ -157,93 +130,40 @@ func (d *Database) GetCurrentCommand(livreurUsername string) (int, error) {
|
||||
return currentID, nil
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 📜 HISTORIQUE DES LIVRAISONS
|
||||
// ============================================
|
||||
|
||||
// GetDeliveryPersonHistory récupère l'historique paginé des livraisons d'un livreur
|
||||
func (d *Database) GetDeliveryPersonHistory(livreurUsername string, limit, offset int) ([]map[string]interface{}, error) {
|
||||
query := `
|
||||
func (d *Database) GetDeliveryPersonHistory(livreurUsername string, limit, offset int) ([]map[string]any, error) {
|
||||
var history []map[string]any
|
||||
err := d.GDB.Raw(`
|
||||
SELECT
|
||||
c.id as command_id,
|
||||
c.username as client,
|
||||
c.status,
|
||||
c.adresse,
|
||||
c.total_prix,
|
||||
c.total_prix::float8 as total_prix,
|
||||
c.created_at as assigned_at,
|
||||
c.updated_at as completed_at
|
||||
FROM commandes c
|
||||
WHERE c.livreur_assign = $1
|
||||
WHERE c.livreur_assign = ?
|
||||
ORDER BY c.created_at DESC
|
||||
LIMIT $2 OFFSET $3
|
||||
`
|
||||
|
||||
rows, err := d.Query(query, livreurUsername, limit, offset)
|
||||
LIMIT ? OFFSET ?`, livreurUsername, limit, offset).Scan(&history).Error
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("erreur récupération historique: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var history []map[string]interface{}
|
||||
for rows.Next() {
|
||||
var commandID int
|
||||
var client, status, adresse string
|
||||
var totalPrix float64
|
||||
var assignedAt, completedAt time.Time
|
||||
|
||||
err := rows.Scan(
|
||||
&commandID,
|
||||
&client,
|
||||
&status,
|
||||
&adresse,
|
||||
&totalPrix,
|
||||
&assignedAt,
|
||||
&completedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("erreur scan historique: %w", err)
|
||||
}
|
||||
|
||||
// Calculer la durée de livraison si complétée
|
||||
var deliveryTime float64
|
||||
if status == "approved" || status == "livre" {
|
||||
deliveryTime = completedAt.Sub(assignedAt).Minutes()
|
||||
}
|
||||
|
||||
entry := map[string]interface{}{
|
||||
"command_id": commandID,
|
||||
"client": client,
|
||||
"status": status,
|
||||
"adresse": adresse,
|
||||
"total_prix": totalPrix,
|
||||
"assigned_at": assignedAt.Format("2006-01-02 15:04:05"),
|
||||
"completed_at": completedAt.Format("2006-01-02 15:04:05"),
|
||||
"delivery_time": deliveryTime,
|
||||
}
|
||||
|
||||
history = append(history, entry)
|
||||
}
|
||||
|
||||
return history, nil
|
||||
}
|
||||
|
||||
// GetDeliveryPersonStatus récupère le statut d'un livreur
|
||||
func (d *Database) GetDeliveryPersonStatus(livreurUsername string) (string, error) {
|
||||
statusKey := fmt.Sprintf("delivery:status:%s", livreurUsername)
|
||||
|
||||
status, err := Redis.Get(RedisCtx, statusKey).Result()
|
||||
if err != nil {
|
||||
// Statut par défaut si non trouvé
|
||||
return "offline", nil
|
||||
}
|
||||
|
||||
return status, nil
|
||||
}
|
||||
|
||||
// UpdateDeliveryPersonStatus met à jour le statut d'un livreur
|
||||
|
||||
func (d *Database) UpdateDeliveryPersonStatus(livreurUsername string, status string) error {
|
||||
// 🔹 Valider le statut
|
||||
if !allowedStatuses[status] {
|
||||
return fmt.Errorf("statut invalide: %s", status)
|
||||
}
|
||||
@@ -251,9 +171,7 @@ func (d *Database) UpdateDeliveryPersonStatus(livreurUsername string, status str
|
||||
log.Printf("🔄 [UpdateStatus] Mise à jour: %s → %s", livreurUsername, status)
|
||||
|
||||
statusKey := fmt.Sprintf("delivery:status:%s", livreurUsername)
|
||||
|
||||
err := Redis.Set(RedisCtx, statusKey, status, 0).Err()
|
||||
if err != nil {
|
||||
if err := Redis.Set(RedisCtx, statusKey, status, 0).Err(); err != nil {
|
||||
log.Printf("❌ [UpdateStatus] Erreur Redis: %v", err)
|
||||
return fmt.Errorf("erreur mise à jour statut: %w", err)
|
||||
}
|
||||
@@ -265,19 +183,16 @@ func (d *Database) UpdateDeliveryPersonStatus(livreurUsername string, status str
|
||||
// GetDeliverymanQueueSize récupère la taille de la queue d'un livreur
|
||||
func (d *Database) GetDeliverymanQueueSize(livreurUsername string) (int, error) {
|
||||
queueKey := fmt.Sprintf("delivery:queue:%s", livreurUsername)
|
||||
|
||||
size, err := Redis.LLen(RedisCtx, queueKey).Result()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("erreur récupération taille queue: %w", err)
|
||||
}
|
||||
|
||||
return int(size), nil
|
||||
}
|
||||
|
||||
// GetDeliverymanQueue récupère la queue complète d'un livreur
|
||||
func (d *Database) GetDeliverymanQueue(livreurUsername string) ([]int, error) {
|
||||
queueKey := fmt.Sprintf("delivery:queue:%s", livreurUsername)
|
||||
|
||||
commands, err := Redis.LRange(RedisCtx, queueKey, 0, -1).Result()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("erreur récupération queue: %w", err)
|
||||
@@ -289,84 +204,66 @@ func (d *Database) GetDeliverymanQueue(livreurUsername string) ([]int, error) {
|
||||
fmt.Sscanf(cmdStr, "%d", &cmdID)
|
||||
queue = append(queue, cmdID)
|
||||
}
|
||||
|
||||
return queue, nil
|
||||
}
|
||||
|
||||
// UpdateCommandLivreur met à jour le livreur assigné à une commande
|
||||
func (d *Database) UpdateCommandLivreur(commandID int, livreurUsername string) error {
|
||||
query := `UPDATE commandes
|
||||
SET livreur_assign = $1, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $2`
|
||||
|
||||
result, err := d.Exec(query, livreurUsername, commandID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("erreur mise à jour livreur: %w", err)
|
||||
result := d.GDB.Exec(`
|
||||
UPDATE commandes
|
||||
SET livreur_assign = ?, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = ?`, livreurUsername, commandID)
|
||||
if result.Error != nil {
|
||||
return fmt.Errorf("erreur mise à jour livreur: %w", result.Error)
|
||||
}
|
||||
|
||||
rowsAffected, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return fmt.Errorf("erreur vérification: %w", err)
|
||||
}
|
||||
if rowsAffected == 0 {
|
||||
if result.RowsAffected == 0 {
|
||||
return fmt.Errorf("commande non trouvée")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAllDeliveryPersonsStats récupère les stats de tous les livreurs
|
||||
func (d *Database) GetAllDeliveryPersonsStats() ([]map[string]any, error) {
|
||||
// Récupérer tous les livreurs
|
||||
livreurs, err := d.GetAvailableDeliveryPersons()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("erreur récupération livreurs: %w", err)
|
||||
}
|
||||
|
||||
var stats []map[string]any
|
||||
|
||||
for _, livreur := range livreurs {
|
||||
username := livreur["username"].(string)
|
||||
|
||||
// Compter les livraisons
|
||||
totalDeliveries, _ := d.CountDeliveriesByStatus(username, "")
|
||||
completedDeliveries, _ := d.CountDeliveriesByStatus(username, "approved")
|
||||
queueSize, _ := d.GetDeliverymanQueueSize(username)
|
||||
status, _ := d.GetDeliveryPersonStatus(username)
|
||||
|
||||
statEntry := map[string]any{
|
||||
stats = append(stats, map[string]any{
|
||||
"username": username,
|
||||
"total_deliveries": totalDeliveries,
|
||||
"completed_deliveries": completedDeliveries,
|
||||
"queue_size": queueSize,
|
||||
"status": status,
|
||||
}
|
||||
|
||||
stats = append(stats, statEntry)
|
||||
})
|
||||
}
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
// GetDeliveryPersonsByStatus récupère les livreurs par statut
|
||||
func (d *Database) GetDeliveryPersonsByStatus(status string) ([]string, error) {
|
||||
// Récupérer tous les livreurs
|
||||
livreurs, err := d.GetAvailableDeliveryPersons()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("erreur récupération livreurs: %w", err)
|
||||
}
|
||||
|
||||
var filteredLivreurs []string
|
||||
|
||||
for _, livreur := range livreurs {
|
||||
username := livreur["username"].(string)
|
||||
currentStatus, _ := d.GetDeliveryPersonStatus(username)
|
||||
|
||||
if currentStatus == status {
|
||||
filteredLivreurs = append(filteredLivreurs, username)
|
||||
}
|
||||
}
|
||||
|
||||
return filteredLivreurs, nil
|
||||
}
|
||||
|
||||
@@ -376,7 +273,6 @@ func (d *Database) GetAvailableDeliveryPersonsCount() (int, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return len(availableLivreurs), nil
|
||||
}
|
||||
|
||||
@@ -384,7 +280,6 @@ func (d *Database) GetAvailableDeliveryPersonsCount() (int, error) {
|
||||
func (d *Database) ClearDeliveryPersonData(livreurUsername string) error {
|
||||
log.Printf("🗑️ [ClearDeliveryData] Nettoyage données pour: %s", livreurUsername)
|
||||
|
||||
// Supprimer de Redis
|
||||
keys := []string{
|
||||
fmt.Sprintf("delivery:status:%s", livreurUsername),
|
||||
fmt.Sprintf("delivery:location:%s", livreurUsername),
|
||||
@@ -394,8 +289,7 @@ func (d *Database) ClearDeliveryPersonData(livreurUsername string) error {
|
||||
}
|
||||
|
||||
for _, key := range keys {
|
||||
err := Redis.Del(RedisCtx, key).Err()
|
||||
if err != nil {
|
||||
if err := Redis.Del(RedisCtx, key).Err(); err != nil {
|
||||
log.Printf("⚠️ [ClearDeliveryData] Erreur suppression clé %s: %v", key, err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user