chore: build
Backend - Build & Lint / build (push) Failing after 28m7s
Frontend Admin - EAS Build / build (push) Failing after 1h39m13s
Frontend Client - EAS Build / build (push) Failing after 1h38m12s
Frontend Web - Build & Lint / build (push) Failing after 10m56s

This commit is contained in:
Xor290
2026-08-19 17:49:04 +02:00
parent 1623a9eafd
commit 901d013830
33 changed files with 1459 additions and 263 deletions
+115 -1
View File
@@ -73,8 +73,47 @@ func validateAddress(address string) error {
return nil
}
// updateCommandDestinationCoords regéocode l'adresse et met à jour
// dest_latitude/dest_longitude après tout changement d'adresse de livraison.
// Sans cet appel, ces coordonnées restent celles de l'ANCIENNE adresse
// (géocodées une seule fois à l'assignation) : la vérification GPS de
// handlers/deleviry.go compare alors la position réelle du livreur à un point
// périmé et peut refuser à tort une validation "trop loin de la destination"
// alors que le livreur est bien arrivé à la nouvelle adresse. En cas d'échec
// de géocodage, on réinitialise les coordonnées plutôt que de laisser
// l'ancienne valeur périmée : le contrôle GPS est alors ignoré (comportement
// déjà prévu quand dest_latitude/dest_longitude sont absentes) au lieu de
// bloquer sur un point qui ne correspond plus à l'adresse réelle.
func updateCommandDestinationCoords(database *db.Database, geoService *services.GeoService, commandID int, address string) {
if geoService == nil || strings.TrimSpace(address) == "" {
return
}
location, err := geoService.GeocodeAddress(address)
if err != nil || location == nil {
log.Printf("⚠️ [ADDR_GEOCODE] Échec géocodage cmd %d (%q): %v — coordonnées de destination réinitialisées", commandID, address, err)
if err := database.GDB.Exec(
`UPDATE commandes SET dest_latitude = NULL, dest_longitude = NULL WHERE id = ?`,
commandID,
).Error; err != nil {
log.Printf("⚠️ [ADDR_GEOCODE] Erreur reset coordonnées cmd %d: %v", commandID, err)
}
return
}
if err := database.GDB.Exec(
`UPDATE commandes SET dest_latitude = ?, dest_longitude = ? WHERE id = ?`,
location.Latitude, location.Longitude, commandID,
).Error; err != nil {
log.Printf("⚠️ [ADDR_GEOCODE] Erreur mise à jour coordonnées cmd %d: %v", commandID, err)
return
}
log.Printf("✅ [ADDR_GEOCODE] Coordonnées de destination mises à jour pour cmd %d", commandID)
}
func UpdateCommandAddress(c *gin.Context) {
database := c.MustGet("database").(*db.Database)
geoService := c.MustGet("geoService").(*services.GeoService)
userRole := c.GetString("role")
if !utils.CheckRoleAdmin(c, userRole) {
@@ -138,6 +177,8 @@ func UpdateCommandAddress(c *gin.Context) {
return
}
updateCommandDestinationCoords(database, geoService, commandID, req.DeliveryAddress)
database.AddCommandLog(commandID, "address_updated",
fmt.Sprintf("Adresse mise à jour par admin %s", adminUsername),
adminUsername)
@@ -220,6 +261,7 @@ func ProposeAddressChange(c *gin.Context) {
// POST /api/v1/commands/:id/address/respond
func RespondToAddressProposal(c *gin.Context) {
database := c.MustGet("database").(*db.Database)
geoService := c.MustGet("geoService").(*services.GeoService)
userRole := c.GetString("role")
if !utils.CheckRoleClient(c, userRole) {
@@ -246,11 +288,25 @@ func RespondToAddressProposal(c *gin.Context) {
return
}
// La colonne proposed_address est vidée par RespondToAddressProposal dès
// qu'elle est traitée : on la lit avant l'appel pour pouvoir regéocoder la
// nouvelle adresse en cas d'acceptation.
var proposedAddress string
if req.Accepted {
if command, err := database.GetCommandByID(commandID); err == nil {
proposedAddress, _ = command["proposed_address"].(string)
}
}
if err := database.RespondToAddressProposal(commandID, clientUsername, req.Accepted); err != nil {
utils.ServerErr(c, "Impossible de traiter la réponse", err)
return
}
if req.Accepted && proposedAddress != "" {
updateCommandDestinationCoords(database, geoService, commandID, proposedAddress)
}
action := "refusée"
if req.Accepted {
action = "acceptée"
@@ -263,6 +319,64 @@ func RespondToAddressProposal(c *gin.Context) {
})
}
// UpdateOwnCommandAddress permet à un client de corriger l'adresse de sa
// propre commande (ex: suite à un échec de géocodage bloquant l'assignation
// auto). Refusé si la commande est déjà en_route ou terminée (voir requête
// SQL dans db.UpdateOwnCommandAddress).
func UpdateOwnCommandAddress(c *gin.Context) {
database := c.MustGet("database").(*db.Database)
geoService := c.MustGet("geoService").(*services.GeoService)
userRole := c.GetString("role")
if !utils.CheckRoleClient(c, userRole) {
c.JSON(http.StatusForbidden, gin.H{"error": "Accès refusé"})
return
}
clientUsername, err := safeGetUsername(c)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Authentification requise"})
return
}
rateLimitKey := fmt.Sprintf("update_own_addr:%s", clientUsername)
if !checkRateLimit(rateLimitKey) {
c.JSON(http.StatusTooManyRequests, gin.H{"error": "Trop de requêtes, réessayez plus tard"})
return
}
commandID, err := strconv.Atoi(c.Param("id"))
if err != nil || commandID <= 0 {
c.JSON(http.StatusBadRequest, gin.H{"error": "ID de commande invalide"})
return
}
var req struct {
DeliveryAddress string `json:"delivery_address" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Données invalides"})
return
}
if !geoService.IsValidAddress(req.DeliveryAddress) {
c.JSON(http.StatusBadRequest, gin.H{"error": "Adresse introuvable, vérifiez l'orthographe ou le code postal"})
return
}
if err := database.UpdateOwnCommandAddress(commandID, clientUsername, req.DeliveryAddress); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
updateCommandDestinationCoords(database, geoService, commandID, req.DeliveryAddress)
log.Printf("✅ [UPD_OWN_ADDR] Commande %d mise à jour par %s", commandID, clientUsername)
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "Adresse mise à jour",
})
}
func ExportApprovedCommandsCSV(c *gin.Context) {
database := c.MustGet("database").(*db.Database)
@@ -556,7 +670,7 @@ func ValidateDelivery(c *gin.Context) {
currentStatus, _ := command["status"].(string)
validStatuses := []string{"assigned", "en_route", "pending", "livre"}
validStatuses := []string{"assigned", "en_route", "arrived", "pending", "livre"}
if !slices.Contains(validStatuses, currentStatus) {
failed = append(failed, gin.H{
"command_id": commandID,