chore: update id order

This commit is contained in:
2026-03-28 17:00:00 +01:00
parent 5380abe8ed
commit 3bf3f5e605
48 changed files with 2347 additions and 3693 deletions
+39 -145
View File
@@ -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)
}
}