183 lines
5.0 KiB
Go
183 lines
5.0 KiB
Go
package db
|
|
|
|
import (
|
|
"fmt"
|
|
"gestion/services"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/redis/go-redis/v9"
|
|
)
|
|
|
|
func (d *Database) SetCommandETA(commandID, minutes int) error {
|
|
key := fmt.Sprintf("command:eta:%d", commandID)
|
|
|
|
now := time.Now()
|
|
arrivalTime := now.Add(time.Duration(minutes) * time.Minute)
|
|
|
|
eta := map[string]any{
|
|
"command_id": commandID,
|
|
"total_eta_minutes": minutes,
|
|
"eta_minutes": minutes,
|
|
"wait_time_minutes": 0,
|
|
"travel_time_minutes": minutes,
|
|
"queue_position": 1,
|
|
"updated_at": now.Unix(),
|
|
"arrival_time": arrivalTime.Unix(),
|
|
"estimated_arrival": arrivalTime.Format(time.RFC3339),
|
|
}
|
|
|
|
_, err := Redis.HSet(RedisCtx, key, eta).Result()
|
|
if err != nil {
|
|
return fmt.Errorf("erreur sauvegarde ETA: %w", err)
|
|
}
|
|
|
|
Redis.Expire(RedisCtx, key, 2*time.Hour)
|
|
|
|
d.ScheduleETANotifications(commandID, minutes)
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetCommandETA récupère l'ETA d'une commande depuis Redis
|
|
func (d *Database) GetCommandETA(commandID int) (map[string]string, error) {
|
|
key := fmt.Sprintf("command:eta:%d", commandID)
|
|
|
|
etaData, err := Redis.HGetAll(RedisCtx, key).Result()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(etaData) == 0 {
|
|
return nil, fmt.Errorf("aucun ETA trouvé pour la commande %d", commandID)
|
|
}
|
|
|
|
return etaData, nil
|
|
}
|
|
|
|
// CheckCommandETAExists vérifie si un ETA existe pour une commande
|
|
func (d *Database) CheckCommandETAExists(commandID int) bool {
|
|
key := fmt.Sprintf("command:eta:%d", commandID)
|
|
exists, _ := Redis.Exists(RedisCtx, key).Result()
|
|
return exists > 0
|
|
}
|
|
|
|
// ScheduleETANotifications programme les notifications 5min et 3min
|
|
func (d *Database) ScheduleETANotifications(commandID, etaMinutes int) error {
|
|
arrivalTime := time.Now().Add(time.Duration(etaMinutes) * time.Minute)
|
|
|
|
if etaMinutes > 5 {
|
|
notify5min := arrivalTime.Add(-5 * time.Minute).Unix()
|
|
Redis.ZAdd(RedisCtx, "notifications:scheduled", redis.Z{
|
|
Score: float64(notify5min),
|
|
Member: fmt.Sprintf("%d:5min", commandID),
|
|
})
|
|
}
|
|
|
|
if etaMinutes > 3 {
|
|
notify3min := arrivalTime.Add(-3 * time.Minute).Unix()
|
|
Redis.ZAdd(RedisCtx, "notifications:scheduled", redis.Z{
|
|
Score: float64(notify3min),
|
|
Member: fmt.Sprintf("%d:3min", commandID),
|
|
})
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ProcessScheduledNotifications traite les notifications à envoyer
|
|
func (d *Database) ProcessScheduledNotifications() error {
|
|
now := float64(time.Now().Unix())
|
|
|
|
results, err := Redis.ZRangeByScore(RedisCtx, "notifications:scheduled", &redis.ZRangeBy{
|
|
Min: "0",
|
|
Max: strconv.FormatFloat(now, 'f', 0, 64),
|
|
}).Result()
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, result := range results {
|
|
parts := splitNotificationKey(result)
|
|
commandID, _ := strconv.Atoi(parts[0])
|
|
notifType := parts[1]
|
|
|
|
d.SendETANotification(commandID, notifType)
|
|
Redis.ZRem(RedisCtx, "notifications:scheduled", result)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// SendETANotification envoie une notification ETA
|
|
func (d *Database) SendETANotification(commandID int, notifType string) {
|
|
message := fmt.Sprintf("Votre commande #%d arrive dans %s", d.GetClientOrderID(commandID), notifType)
|
|
|
|
channel := fmt.Sprintf("notifications:command:%d", commandID)
|
|
Redis.Publish(RedisCtx, channel, message)
|
|
}
|
|
|
|
// CalculateETAForDeliveryman calcule l'ETA entre un livreur et une destination
|
|
func (d *Database) CalculateETAForDeliveryman(deliveryman string, destLat, destLng float64) int {
|
|
livreurLat, livreurLng, err := d.GetDeliveryPersonLocation(deliveryman)
|
|
if err != nil {
|
|
return services.MinETA
|
|
}
|
|
|
|
from := services.Coordinates{
|
|
Latitude: livreurLat,
|
|
Longitude: livreurLng,
|
|
}
|
|
to := services.Coordinates{
|
|
Latitude: destLat,
|
|
Longitude: destLng,
|
|
}
|
|
|
|
eta, _, err2 := services.CalculateETAWithTomTom(from, to)
|
|
if err2 != nil {
|
|
distance := services.CalculateDistance(from, to)
|
|
eta = services.CalculateETA(distance)
|
|
}
|
|
|
|
return eta
|
|
}
|
|
|
|
// CalculateDistanceBetweenPoints calcule la distance entre deux points
|
|
func (d *Database) CalculateDistanceBetweenPoints(lat1, lng1, lat2, lng2 float64) float64 {
|
|
from := services.Coordinates{Latitude: lat1, Longitude: lng1}
|
|
to := services.Coordinates{Latitude: lat2, Longitude: lng2}
|
|
return services.CalculateDistance(from, to)
|
|
}
|
|
|
|
// CalculateETABetweenPoints calcule l'ETA entre deux points
|
|
func (d *Database) CalculateETABetweenPoints(lat1, lng1, lat2, lng2 float64) int {
|
|
distance := d.CalculateDistanceBetweenPoints(lat1, lng1, lat2, lng2)
|
|
return services.CalculateETA(distance)
|
|
}
|
|
|
|
func (d *Database) SetCommandETAWithDetails(commandID, totalETA, queuePosition int) error {
|
|
key := fmt.Sprintf("command:eta:%d", commandID)
|
|
|
|
now := time.Now()
|
|
arrivalTime := now.Add(time.Duration(totalETA) * time.Minute)
|
|
|
|
eta := map[string]any{
|
|
"command_id": commandID,
|
|
"total_eta_minutes": totalETA,
|
|
"queue_position": queuePosition,
|
|
"updated_at": now.Unix(),
|
|
"arrival_time": arrivalTime.Unix(),
|
|
"estimated_arrival": arrivalTime.Format(time.RFC3339),
|
|
}
|
|
|
|
_, err := Redis.HSet(RedisCtx, key, eta).Result()
|
|
if err != nil {
|
|
return fmt.Errorf("erreur sauvegarde ETA: %w", err)
|
|
}
|
|
|
|
Redis.Expire(RedisCtx, key, 4*time.Hour)
|
|
|
|
return nil
|
|
}
|