chore: add ansible backend docker frontend-prep
This commit is contained in:
@@ -0,0 +1,430 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"gestion/models"
|
||||
"log"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// AssignCommandToDeliverymanQueue assigne une commande à la queue d'un livreur
|
||||
func (d *Database) AssignCommandToDeliverymanQueue(commandID int, deliveryman string, estimatedTravelTime int) error {
|
||||
command, err := d.GetCommandByID(commandID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("commande introuvable: %w", err)
|
||||
}
|
||||
|
||||
activeCount, _ := d.CountActiveDeliverymen()
|
||||
|
||||
queueKey := fmt.Sprintf("queue:deliveryman:%s", deliveryman)
|
||||
currentQueueSize, _ := Redis.ZCard(RedisCtx, queueKey).Result()
|
||||
|
||||
// Si plusieurs livreurs, appliquer la limite de 10
|
||||
if activeCount > 1 && currentQueueSize >= MAX_COMMANDS_PER_DELIVERYMAN {
|
||||
return fmt.Errorf("livreur %s a atteint le maximum de commandes (%d)", deliveryman, MAX_COMMANDS_PER_DELIVERYMAN)
|
||||
}
|
||||
|
||||
// ✅ MODIFIÉ: ETA = temps de trajet direct uniquement
|
||||
totalETA := estimatedTravelTime
|
||||
|
||||
var lat, lng float64
|
||||
if command["dest_latitude"] != nil {
|
||||
if latVal, ok := command["dest_latitude"].(float64); ok {
|
||||
lat = latVal
|
||||
}
|
||||
}
|
||||
if command["dest_longitude"] != nil {
|
||||
if lngVal, ok := command["dest_longitude"].(float64); ok {
|
||||
lng = lngVal
|
||||
}
|
||||
}
|
||||
|
||||
var totalPrice float64
|
||||
if tp, ok := command["total_prix"].(float64); ok {
|
||||
totalPrice = tp
|
||||
}
|
||||
|
||||
var address string
|
||||
if addr, ok := command["delivery_address"].(string); ok {
|
||||
address = addr
|
||||
} else if addr, ok := command["adresse"].(string); ok {
|
||||
address = addr
|
||||
}
|
||||
|
||||
queueItem := models.CommandQueue{
|
||||
CommandID: commandID,
|
||||
Username: command["username"].(string),
|
||||
TotalPrice: totalPrice,
|
||||
Address: address,
|
||||
Lat: lat,
|
||||
Lng: lng,
|
||||
CreatedAt: time.Now(),
|
||||
EstimatedETA: totalETA,
|
||||
}
|
||||
|
||||
err = d.AddToDeliverymanQueue(deliveryman, queueItem)
|
||||
if err != nil {
|
||||
return fmt.Errorf("erreur ajout à la queue: %w", err)
|
||||
}
|
||||
|
||||
d.UpdateCommandStatus(commandID, "assigned")
|
||||
d.AssignDeliveryPerson(commandID, deliveryman)
|
||||
// ✅ MODIFIÉ: Position dans la queue pour info seulement
|
||||
d.SetCommandETAWithDetails(commandID, totalETA, int(currentQueueSize)+1)
|
||||
|
||||
limitInfo := ""
|
||||
if activeCount > 1 {
|
||||
limitInfo = fmt.Sprintf("/%d", MAX_COMMANDS_PER_DELIVERYMAN)
|
||||
} else {
|
||||
limitInfo = " (sans limite - seul livreur)"
|
||||
}
|
||||
|
||||
d.AddCommandLog(commandID, "queued",
|
||||
fmt.Sprintf("Ajouté à la queue de %s (position: %d%s, ETA trajet: %d min)",
|
||||
deliveryman, currentQueueSize+1, limitInfo, totalETA),
|
||||
"system")
|
||||
|
||||
log.Printf("✅ Commande %d -> Queue %s (pos: %d%s, ETA trajet: %d min)",
|
||||
commandID, deliveryman, currentQueueSize+1, limitInfo, totalETA)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AssignCommandToDeliverymanQueueUnlimited assigne sans limite (pour un seul livreur)
|
||||
func (d *Database) AssignCommandToDeliverymanQueueUnlimited(deliveryman string, queueItem models.CommandQueue) error {
|
||||
queueKey := fmt.Sprintf("queue:deliveryman:%s", deliveryman)
|
||||
currentQueueSize, _ := Redis.ZCard(RedisCtx, queueKey).Result()
|
||||
|
||||
// ✅ MODIFIÉ: Calculer le temps de trajet direct depuis la position du livreur
|
||||
travelTime := d.CalculateETAForDeliveryman(deliveryman, queueItem.Lat, queueItem.Lng)
|
||||
|
||||
// ✅ ETA = temps de trajet direct uniquement
|
||||
queueItem.EstimatedETA = travelTime
|
||||
|
||||
err := d.AddToDeliverymanQueue(deliveryman, queueItem)
|
||||
if err != nil {
|
||||
return fmt.Errorf("erreur ajout à la queue: %w", err)
|
||||
}
|
||||
|
||||
d.UpdateCommandStatus(queueItem.CommandID, "assigned")
|
||||
d.AssignDeliveryPerson(queueItem.CommandID, deliveryman)
|
||||
d.SetCommandETAWithDetails(queueItem.CommandID, travelTime, int(currentQueueSize)+1)
|
||||
|
||||
d.AddCommandLog(queueItem.CommandID, "queued",
|
||||
fmt.Sprintf("Assigné au seul livreur actif %s (position: %d, ETA trajet: %d min)",
|
||||
deliveryman, currentQueueSize+1, travelTime),
|
||||
"system")
|
||||
|
||||
log.Printf("✅ Commande %d -> Queue %s (SANS LIMITE - pos: %d, ETA trajet: %d min)",
|
||||
queueItem.CommandID, deliveryman, currentQueueSize+1, travelTime)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AssignCommandToDeliverymanQueueWithCoords assigne une commande avec les coordonnées GPS
|
||||
func (d *Database) AssignCommandToDeliverymanQueueWithCoords(commandID int, deliveryman string, estimatedTravelTime int, lat, lng float64, address string) error {
|
||||
command, err := d.GetCommandByID(commandID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("commande introuvable: %w", err)
|
||||
}
|
||||
|
||||
activeCount, _ := d.CountActiveDeliverymen()
|
||||
|
||||
queueKey := fmt.Sprintf("queue:deliveryman:%s", deliveryman)
|
||||
currentQueueSize, _ := Redis.ZCard(RedisCtx, queueKey).Result()
|
||||
|
||||
if activeCount > 1 && currentQueueSize >= MAX_COMMANDS_PER_DELIVERYMAN {
|
||||
return fmt.Errorf("livreur %s a atteint le maximum de commandes (%d)", deliveryman, MAX_COMMANDS_PER_DELIVERYMAN)
|
||||
}
|
||||
|
||||
// ✅ ETA = temps de trajet direct uniquement
|
||||
totalETA := estimatedTravelTime
|
||||
|
||||
var totalPrice float64
|
||||
if tp, ok := command["total_prix"].(float64); ok {
|
||||
totalPrice = tp
|
||||
}
|
||||
|
||||
var username string
|
||||
if u, ok := command["username"].(string); ok {
|
||||
username = u
|
||||
}
|
||||
|
||||
queueItem := models.CommandQueue{
|
||||
CommandID: commandID,
|
||||
Username: username,
|
||||
TotalPrice: totalPrice,
|
||||
Address: address,
|
||||
Lat: lat,
|
||||
Lng: lng,
|
||||
CreatedAt: time.Now(),
|
||||
EstimatedETA: totalETA,
|
||||
}
|
||||
|
||||
err = d.AddToDeliverymanQueue(deliveryman, queueItem)
|
||||
if err != nil {
|
||||
return fmt.Errorf("erreur ajout à la queue: %w", err)
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// ✅ CORRECTION: Mettre à jour livreur_assign dans la DB
|
||||
// ============================================
|
||||
updateQuery := `UPDATE commandes
|
||||
SET livreur_assign = $1,
|
||||
status = 'assigned',
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $2`
|
||||
|
||||
_, err = d.Exec(updateQuery, deliveryman, commandID)
|
||||
if err != nil {
|
||||
log.Printf("❌ Erreur mise à jour livreur_assign: %v", err)
|
||||
return fmt.Errorf("erreur mise à jour DB: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("✅ DB mise à jour: livreur_assign=%s pour commande %d", deliveryman, commandID)
|
||||
|
||||
d.SetCommandETAWithDetails(commandID, totalETA, int(currentQueueSize)+1)
|
||||
|
||||
// Sauvegarder dans le cache destination
|
||||
destCacheKey := fmt.Sprintf("command:destination:%d", commandID)
|
||||
coordsJSON, _ := json.Marshal(map[string]float64{
|
||||
"lat": lat,
|
||||
"lon": lng,
|
||||
})
|
||||
Redis.Set(RedisCtx, destCacheKey, coordsJSON, 4*time.Hour)
|
||||
|
||||
limitInfo := ""
|
||||
if activeCount > 1 {
|
||||
limitInfo = fmt.Sprintf("/%d", MAX_COMMANDS_PER_DELIVERYMAN)
|
||||
} else {
|
||||
limitInfo = " (sans limite - seul livreur)"
|
||||
}
|
||||
|
||||
d.AddCommandLog(commandID, "assigned",
|
||||
fmt.Sprintf("Assigné à %s (position: %d%s, ETA trajet: %d min, coords: %.4f,%.4f)",
|
||||
deliveryman, currentQueueSize+1, limitInfo, totalETA, lat, lng),
|
||||
"system")
|
||||
|
||||
log.Printf("✅ Commande %d -> Livreur %s (pos: %d%s, ETA trajet: %d min, coords: %.4f,%.4f)",
|
||||
commandID, deliveryman, currentQueueSize+1, limitInfo, totalETA, lat, lng)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ForceAssignCommandToDeliverymanWithCoords assigne une commande de force avec coordonnées
|
||||
// ForceAssignCommandToDeliverymanWithCoords assigne une commande de force avec coordonnées
|
||||
func (d *Database) ForceAssignCommandToDeliverymanWithCoords(commandID int, deliveryman string, estimatedTravelTime int, lat, lng float64, address string) error {
|
||||
command, err := d.GetCommandByID(commandID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("commande introuvable: %w", err)
|
||||
}
|
||||
|
||||
queueKey := fmt.Sprintf("queue:deliveryman:%s", deliveryman)
|
||||
currentQueueSize, _ := Redis.ZCard(RedisCtx, queueKey).Result()
|
||||
|
||||
// ✅ MODIFIÉ: ETA = temps de trajet direct uniquement
|
||||
totalETA := estimatedTravelTime
|
||||
|
||||
var totalPrice float64
|
||||
if tp, ok := command["total_prix"].(float64); ok {
|
||||
totalPrice = tp
|
||||
}
|
||||
|
||||
var username string
|
||||
if u, ok := command["username"].(string); ok {
|
||||
username = u
|
||||
}
|
||||
|
||||
queueItem := models.CommandQueue{
|
||||
CommandID: commandID,
|
||||
Username: username,
|
||||
TotalPrice: totalPrice,
|
||||
Address: address,
|
||||
Lat: lat,
|
||||
Lng: lng,
|
||||
CreatedAt: time.Now(),
|
||||
EstimatedETA: totalETA,
|
||||
}
|
||||
|
||||
err = d.AddToDeliverymanQueue(deliveryman, queueItem)
|
||||
if err != nil {
|
||||
return fmt.Errorf("erreur ajout à la queue: %w", err)
|
||||
}
|
||||
|
||||
d.UpdateCommandStatus(commandID, "assigned")
|
||||
d.AssignDeliveryPerson(commandID, deliveryman)
|
||||
d.SetCommandETAWithDetails(commandID, totalETA, int(currentQueueSize)+1)
|
||||
|
||||
// Sauvegarder dans le cache destination
|
||||
destCacheKey := fmt.Sprintf("command:destination:%d", commandID)
|
||||
coordsJSON, _ := json.Marshal(map[string]float64{
|
||||
"lat": lat,
|
||||
"lon": lng,
|
||||
})
|
||||
Redis.Set(RedisCtx, destCacheKey, coordsJSON, 4*time.Hour)
|
||||
|
||||
d.AddCommandLog(commandID, "force_queued",
|
||||
fmt.Sprintf("Assignation forcée à %s (position: %d, ETA trajet: %d min, coords: %.4f,%.4f)",
|
||||
deliveryman, currentQueueSize+1, totalETA, lat, lng),
|
||||
"system")
|
||||
|
||||
log.Printf("⚠️ FORCE: Commande %d -> Queue %s (pos: %d, ETA trajet: %d min, coords: %.4f,%.4f)",
|
||||
commandID, deliveryman, currentQueueSize+1, totalETA, lat, lng)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ForceAssignCommandToDeliveryman assigne une commande à un livreur SANS vérifier la limite de 10
|
||||
func (d *Database) ForceAssignCommandToDeliveryman(commandID int, deliveryman string, estimatedTravelTime int) error {
|
||||
command, err := d.GetCommandByID(commandID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("commande introuvable: %w", err)
|
||||
}
|
||||
|
||||
queueKey := fmt.Sprintf("queue:deliveryman:%s", deliveryman)
|
||||
currentQueueSize, _ := Redis.ZCard(RedisCtx, queueKey).Result()
|
||||
|
||||
// ✅ MODIFIÉ: ETA = temps de trajet direct uniquement
|
||||
totalETA := estimatedTravelTime
|
||||
|
||||
var lat, lng float64
|
||||
if command["dest_latitude"] != nil {
|
||||
if latVal, ok := command["dest_latitude"].(float64); ok {
|
||||
lat = latVal
|
||||
}
|
||||
}
|
||||
if command["dest_longitude"] != nil {
|
||||
if lngVal, ok := command["dest_longitude"].(float64); ok {
|
||||
lng = lngVal
|
||||
}
|
||||
}
|
||||
|
||||
var totalPrice float64
|
||||
if tp, ok := command["total_prix"].(float64); ok {
|
||||
totalPrice = tp
|
||||
}
|
||||
|
||||
var address string
|
||||
if addr, ok := command["delivery_address"].(string); ok {
|
||||
address = addr
|
||||
} else if addr, ok := command["adresse"].(string); ok {
|
||||
address = addr
|
||||
}
|
||||
|
||||
queueItem := models.CommandQueue{
|
||||
CommandID: commandID,
|
||||
Username: command["username"].(string),
|
||||
TotalPrice: totalPrice,
|
||||
Address: address,
|
||||
Lat: lat,
|
||||
Lng: lng,
|
||||
CreatedAt: time.Now(),
|
||||
EstimatedETA: totalETA,
|
||||
}
|
||||
|
||||
err = d.AddToDeliverymanQueue(deliveryman, queueItem)
|
||||
if err != nil {
|
||||
return fmt.Errorf("erreur ajout à la queue: %w", err)
|
||||
}
|
||||
|
||||
d.UpdateCommandStatus(commandID, "assigned")
|
||||
d.AssignDeliveryPerson(commandID, deliveryman)
|
||||
d.SetCommandETAWithDetails(commandID, totalETA, int(currentQueueSize)+1)
|
||||
|
||||
d.AddCommandLog(commandID, "force_queued",
|
||||
fmt.Sprintf("Assignation forcée à %s (position: %d, ETA trajet: %d min)",
|
||||
deliveryman, currentQueueSize+1, totalETA),
|
||||
"system")
|
||||
|
||||
log.Printf("⚠️ FORCE: Commande %d -> Queue %s (pos: %d, ETA trajet: %d min)",
|
||||
commandID, deliveryman, currentQueueSize+1, totalETA)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AutoAssignCommand assigne automatiquement une commande au premier livreur disponible
|
||||
func (d *Database) AutoAssignCommand(commandID int) error {
|
||||
// Récupérer les livreurs disponibles
|
||||
available, err := d.GetAvailableDeliveryPersonsRedis()
|
||||
if err != nil || len(available) == 0 {
|
||||
return fmt.Errorf("aucun livreur disponible")
|
||||
}
|
||||
|
||||
// Prendre le premier livreur
|
||||
livreur := available[0]
|
||||
|
||||
// Assigner dans la DB principale
|
||||
err = d.AssignDeliveryPerson(commandID, livreur.Username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Mettre à jour le statut dans Redis
|
||||
d.SetDeliveryPersonStatus(livreur.Username, "busy", commandID)
|
||||
|
||||
// Retirer de la file d'attente
|
||||
d.RemoveCommandFromQueue(commandID)
|
||||
|
||||
// Définir l'ETA initial
|
||||
d.SetCommandETA(commandID, 30)
|
||||
|
||||
log.Printf("✅ Commande %d auto-assignée à %s", commandID, livreur.Username)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Database) ProcessNextCommandInQueue(deliveryman string) error {
|
||||
log.Printf("🔄 Traitement de la prochaine commande pour %s", deliveryman)
|
||||
|
||||
// Vérifier d'abord la queue spécifique du livreur
|
||||
queueKey := fmt.Sprintf("queue:deliveryman:%s", deliveryman)
|
||||
results, err := Redis.ZRangeWithScores(RedisCtx, queueKey, 0, 0).Result()
|
||||
|
||||
if err == nil && len(results) > 0 {
|
||||
// Une commande est dans sa queue - la traiter
|
||||
commandID := extractCommandID(results[0].Member)
|
||||
|
||||
// Mettre à jour le statut
|
||||
d.SetDeliveryPersonStatus(deliveryman, "busy", commandID)
|
||||
|
||||
log.Printf("✅ Livreur %s traite la commande %d de sa queue", deliveryman, commandID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Si aucune commande dans sa queue, chercher dans la queue générale
|
||||
generalResults, err := Redis.ZRangeWithScores(RedisCtx, "queue:pending:sorted", 0, 0).Result()
|
||||
|
||||
if err != nil || len(generalResults) == 0 {
|
||||
log.Printf("ℹ️ Aucune commande en attente pour %s", deliveryman)
|
||||
return nil
|
||||
}
|
||||
|
||||
commandID := extractCommandID(generalResults[0].Member)
|
||||
|
||||
// Assigner la commande
|
||||
err = d.AssignDeliveryPerson(commandID, deliveryman)
|
||||
if err != nil {
|
||||
log.Printf("❌ Erreur assignation commande %d: %v", commandID, err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Retirer de la queue générale
|
||||
Redis.ZRem(RedisCtx, "queue:pending:sorted", strconv.Itoa(commandID))
|
||||
|
||||
// Mettre à jour le statut
|
||||
d.SetDeliveryPersonStatus(deliveryman, "busy", commandID)
|
||||
|
||||
// Définir un ETA par défaut
|
||||
d.SetCommandETA(commandID, 30)
|
||||
|
||||
// Ajouter log
|
||||
d.AddCommandLog(commandID, "auto_assigned",
|
||||
fmt.Sprintf("Assigné automatiquement à %s depuis la queue générale", deliveryman),
|
||||
"system")
|
||||
|
||||
log.Printf("✅ Commande %d assignée automatiquement à %s (queue générale)", commandID, deliveryman)
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user