chore: update

This commit is contained in:
2026-03-11 19:57:34 +01:00
parent f6b3948839
commit 375aa38454
62 changed files with 2714 additions and 1981 deletions
@@ -9,6 +9,7 @@ import (
"encoding/json"
"fmt"
"gestion/db"
"gestion/services"
"log"
"net/http"
"strconv"
@@ -178,6 +179,9 @@ func UpdateLivreurLocation(c *gin.Context) {
log.Printf("📍 Position GPS mise à jour pour %s: (%.6f, %.6f)",
usernameStr, req.Latitude, req.Longitude)
// ✅ Recalculer l'ETA en temps réel si livreur en_route
go refreshETAForActivDelivery(database, usernameStr, req.Latitude, req.Longitude)
// ✅ 2. Vérifier/Initialiser le statut du livreur
statusKey := fmt.Sprintf("delivery:status:%s", usernameStr)
statusData, err := db.Redis.Get(db.RedisCtx, statusKey).Result()
@@ -1049,3 +1053,89 @@ func GetRealtimeStats(c *gin.Context) {
"stats": stats,
})
}
// ============================================
// RECALCUL ETA EN TEMPS RÉEL (appelé à chaque update GPS)
// ============================================
// refreshETAForActivDelivery recalcule l'ETA depuis la position actuelle du livreur.
// Appelé en goroutine à chaque mise à jour GPS (toutes les ~15s).
func refreshETAForActivDelivery(database *db.Database, username string, lat, lon float64) {
// 1. Récupérer le statut actuel du livreur
statusKey := fmt.Sprintf("delivery:status:%s", username)
statusData, err := db.Redis.Get(db.RedisCtx, statusKey).Result()
if err != nil || statusData == "" {
return
}
var status map[string]interface{}
if err := json.Unmarshal([]byte(statusData), &status); err != nil {
return
}
// 2. Seulement si en_route ou arrived
currentStatus, _ := status["status"].(string)
if currentStatus != "en_route" && currentStatus != "arrived" {
return
}
// 3. Récupérer la commande active
var commandID int
switch v := status["current_command"].(type) {
case float64:
commandID = int(v)
case int:
commandID = v
default:
return
}
if commandID <= 0 {
return
}
// 4. Récupérer les coordonnées destination depuis le cache Redis
destCacheKey := fmt.Sprintf("command:destination:%d", commandID)
destData, err := db.Redis.Get(db.RedisCtx, destCacheKey).Result()
if err != nil || destData == "" {
return
}
var coords struct {
Lat float64 `json:"lat"`
Lon float64 `json:"lon"`
}
if err := json.Unmarshal([]byte(destData), &coords); err != nil || coords.Lat == 0 {
return
}
// 5. Calculer l'ETA depuis la position GPS actuelle
from := services.Coordinates{Latitude: lat, Longitude: lon}
to := services.Coordinates{Latitude: coords.Lat, Longitude: coords.Lon}
etaMinutes, distanceKm, err := services.GetETAWithTraffic(from, to)
if err != nil {
// Fallback Haversine uniquement si TomTom indisponible
distanceKm = services.CalculateDistance(from, to)
etaMinutes = services.CalculateETA(distanceKm)
log.Printf("⚠️ [ETA_REALTIME] TomTom indisponible pour %s cmd %d, fallback: %.2fkm → %dmin",
username, commandID, distanceKm, etaMinutes)
} else {
log.Printf("🔄 [ETA_REALTIME] %s cmd %d recalculé: %.2fkm → %dmin (TomTom)",
username, commandID, distanceKm, etaMinutes)
}
// 6. Mettre à jour le cache Redis ETA (écrase l'ancien)
now := time.Now()
arrivalTime := now.Add(time.Duration(etaMinutes) * time.Minute)
etaKey := fmt.Sprintf("command:eta:%d", commandID)
db.Redis.HSet(db.RedisCtx, etaKey, map[string]interface{}{
"command_id": commandID,
"eta_minutes": etaMinutes,
"updated_at": now.Unix(),
"arrival_time": arrivalTime.Unix(),
"distance_km": distanceKm,
"with_traffic": err == nil,
})
db.Redis.Expire(db.RedisCtx, etaKey, 4*time.Hour)
}