From b9073954f1f40078170a00ffb641880c40f809bb Mon Sep 17 00:00:00 2001 From: Xor290 Date: Wed, 19 Aug 2026 12:26:50 +0200 Subject: [PATCH] chore: build --- backend/gestion/db/db_commands.go | 2 +- backend/gestion/handlers/commands.go | 2 +- .../gestion/handlers/validation_deleviry.go | 12 ---- backend/gestion/tests/deleviry_gps_test.go | 55 +++++++------------ .../tests/points_approval_staff_test.go | 17 +++--- 5 files changed, 31 insertions(+), 57 deletions(-) diff --git a/backend/gestion/db/db_commands.go b/backend/gestion/db/db_commands.go index 16ff7ceb..5427ffea 100644 --- a/backend/gestion/db/db_commands.go +++ b/backend/gestion/db/db_commands.go @@ -655,7 +655,7 @@ func (d *Database) ValidateDeliveryAtomic(commandID int, adminUsername string) ( log.Printf("📋 [ValidateAtomic] Commande trouvĂ©e - status=%s, client=%s, livreur=%s", cmd.Status, cmd.Username, cmd.LivreurAssign) - validStatuses := []string{"assigned", "en_route", "pending", "livre"} + validStatuses := []string{"assigned", "en_route", "arrived", "pending", "livre"} if !slices.Contains(validStatuses, cmd.Status) { log.Printf("❌ [ValidateAtomic] Statut invalide pour validation: %s", cmd.Status) return fmt.Errorf("statut invalide pour validation: %s", cmd.Status) diff --git a/backend/gestion/handlers/commands.go b/backend/gestion/handlers/commands.go index 38c4dbc4..86f15024 100644 --- a/backend/gestion/handlers/commands.go +++ b/backend/gestion/handlers/commands.go @@ -670,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, diff --git a/backend/gestion/handlers/validation_deleviry.go b/backend/gestion/handlers/validation_deleviry.go index a567f72b..af206928 100644 --- a/backend/gestion/handlers/validation_deleviry.go +++ b/backend/gestion/handlers/validation_deleviry.go @@ -12,18 +12,6 @@ import ( "github.com/gin-gonic/gin" ) -// ============================================ -// CONSTANTES DE CONFIGURATION -// ============================================ - -const ( - // Distance maximale en mĂštres pour valider une livraison - MAX_DELIVERY_VALIDATION_DISTANCE_METERS = 100 // 100 mĂštres - - // Distance maximale en kilomĂštres - MAX_DELIVERY_VALIDATION_DISTANCE_KM = 0.1 // 100 mĂštres = 0.1 km -) - // ============================================ // 3ïžâƒŁ DÉMARRER UNE LIVRAISON (PASSER EN IN_ROUTE) // ============================================ diff --git a/backend/gestion/tests/deleviry_gps_test.go b/backend/gestion/tests/deleviry_gps_test.go index ebee46a0..3ec1597d 100644 --- a/backend/gestion/tests/deleviry_gps_test.go +++ b/backend/gestion/tests/deleviry_gps_test.go @@ -14,10 +14,13 @@ import ( "github.com/gin-gonic/gin" ) -// UpdateDeliveryStatus (handlers/deleviry.go) refuse de valider une livraison -// (statut "livre") si le livreur se trouve Ă  plus de 350m de la destination -// (contrĂŽle anti-fraude — seuil relevĂ© de 100m Ă  350m Ă  la demande explicite, -// pour tolĂ©rer l'imprĂ©cision GPS rĂ©elle en zone urbaine/immeuble). +// UpdateDeliveryStatus (handlers/deleviry.go) n'impose plus aucune limite de +// distance entre le livreur et la destination pour valider une livraison +// (statut "livre") — la vĂ©rification GPS a Ă©tĂ© volontairement retirĂ©e pour ne +// pas bloquer le livreur (l'imprĂ©cision GPS rĂ©elle en zone urbaine/immeuble +// provoquait des rejets sur des livraisons pourtant lĂ©gitimes). Les +// coordonnĂ©es GPS restent obligatoires et la distance est toujours calculĂ©e +// et loguĂ©e Ă  des fins de suivi, mais elle n'entraĂźne plus de rejet. const earthRadiusMeters = 6371000.0 @@ -58,7 +61,7 @@ func deliveryStatusContextJSON(username string, commandID int, body []byte) (*gi const nantesLat, nantesLon = 47.2184, -1.5536 -func TestUpdateDeliveryStatus_GPS_WithinThresholdValidatesDelivery(t *testing.T) { +func TestUpdateDeliveryStatus_GPS_ValidatesDeliveryAtModerateDistance(t *testing.T) { cleanupStockTestData(t) livreur := newTestClient(t, "gps_livreur_within") client := newTestClient(t, "gps_client_within") @@ -66,7 +69,7 @@ func TestUpdateDeliveryStatus_GPS_WithinThresholdValidatesDelivery(t *testing.T) cmdID := newTestCommandWithItem(t, client, "en_route", livreur, productID, 1, 10) setCommandDestination(t, cmdID, nantesLat, nantesLon) - livreurLat, livreurLon := destinationPointNorthOf(nantesLat, nantesLon, 200) // 200m < 350m + livreurLat, livreurLon := destinationPointNorthOf(nantesLat, nantesLon, 200) body, _ := json.Marshal(map[string]any{"status": "livre", "latitude": livreurLat, "longitude": livreurLon}) c, rec := deliveryStatusContextJSON(livreur, cmdID, body) handlers.UpdateDeliveryStatus(c) @@ -79,47 +82,27 @@ func TestUpdateDeliveryStatus_GPS_WithinThresholdValidatesDelivery(t *testing.T) } } -func TestUpdateDeliveryStatus_GPS_BeyondThresholdRejectsValidation(t *testing.T) { +// Aucune distance, aussi grande soit-elle, ne doit bloquer la validation : la +// vĂ©rification GPS a Ă©tĂ© retirĂ©e pour ne jamais empĂȘcher un livreur de +// marquer une commande "livre". +func TestUpdateDeliveryStatus_GPS_FarBeyondOldThresholdStillValidatesDelivery(t *testing.T) { cleanupStockTestData(t) - livreur := newTestClient(t, "gps_livreur_beyond") - client := newTestClient(t, "gps_client_beyond") - productID := newTestProduct(t, "GPSBeyond", 10) + livreur := newTestClient(t, "gps_livreur_far") + client := newTestClient(t, "gps_client_far") + productID := newTestProduct(t, "GPSFar", 10) cmdID := newTestCommandWithItem(t, client, "en_route", livreur, productID, 1, 10) setCommandDestination(t, cmdID, nantesLat, nantesLon) - livreurLat, livreurLon := destinationPointNorthOf(nantesLat, nantesLon, 400) // 400m > 350m - body, _ := json.Marshal(map[string]any{"status": "livre", "latitude": livreurLat, "longitude": livreurLon}) - c, rec := deliveryStatusContextJSON(livreur, cmdID, body) - handlers.UpdateDeliveryStatus(c) - - if rec.Code != http.StatusBadRequest { - t.Fatalf("status HTTP: got=%d want=%d body=%s", rec.Code, http.StatusBadRequest, rec.Body.String()) - } - if got := commandStatus(t, cmdID); got != "en_route" { - t.Errorf("le statut ne doit pas passer Ă  'livre' au-delĂ  de 350m: got=%s want=en_route", got) - } -} - -// Preuve directe du changement demandĂ© : une distance de 150m, qui aurait -// Ă©chouĂ© sous l'ancien seuil de 100m, doit maintenant rĂ©ussir sous 350m. -func TestUpdateDeliveryStatus_GPS_150Meters_PassesUnderNewThreshold(t *testing.T) { - cleanupStockTestData(t) - livreur := newTestClient(t, "gps_livreur_150m") - client := newTestClient(t, "gps_client_150m") - productID := newTestProduct(t, "GPS150m", 10) - cmdID := newTestCommandWithItem(t, client, "en_route", livreur, productID, 1, 10) - setCommandDestination(t, cmdID, nantesLat, nantesLon) - - livreurLat, livreurLon := destinationPointNorthOf(nantesLat, nantesLon, 150) + livreurLat, livreurLon := destinationPointNorthOf(nantesLat, nantesLon, 5000) // 5km : loin de toute ancienne limite body, _ := json.Marshal(map[string]any{"status": "livre", "latitude": livreurLat, "longitude": livreurLon}) c, rec := deliveryStatusContextJSON(livreur, cmdID, body) handlers.UpdateDeliveryStatus(c) if rec.Code != http.StatusOK { - t.Fatalf("150m doit ĂȘtre acceptĂ© sous le nouveau seuil de 350m: got=%d body=%s", rec.Code, rec.Body.String()) + t.Fatalf("aucune distance ne doit bloquer la validation: got=%d body=%s", rec.Code, rec.Body.String()) } if got := commandStatus(t, cmdID); got != "livre" { - t.Errorf("statut aprĂšs validation Ă  150m: got=%s want=livre", got) + t.Errorf("statut aprĂšs validation Ă  5km: got=%s want=livre", got) } } diff --git a/backend/gestion/tests/points_approval_staff_test.go b/backend/gestion/tests/points_approval_staff_test.go index 3d30573f..38079a7e 100644 --- a/backend/gestion/tests/points_approval_staff_test.go +++ b/backend/gestion/tests/points_approval_staff_test.go @@ -18,8 +18,8 @@ import ( // destination pĂ©rimĂ©es) empĂȘchait le livreur d'atteindre 'livre', laissant le // staff sans recours pour confirmer une commande par ailleurs lĂ©gitime — voir // db.ApproveDeliveryAtomicByStaff. Tout statut non terminal est acceptĂ© — y -// compris "arrived", que ValidateDeliveryAtomic (validation admin en masse, -// non modifiĂ©e) continue lui de rejeter. +// compris "arrived". ValidateDeliveryAtomic (validation admin en masse) +// accepte dĂ©sormais "arrived" aussi, pour la mĂȘme raison (voir plus bas). func TestApproveDeliveryAtomicByStaff_CreditsPointsExactlyOnApproval(t *testing.T) { cleanupStockTestData(t) @@ -183,9 +183,12 @@ func TestApproveDeliveryAtomicByStaff_NoOwnershipCheck_AnyStaffCanConfirmAnyClie // Divergence de rĂšgle mĂ©tier volontaire (confirmĂ©e) : contrairement aux deux // autres chemins d'approbation (client et staff), qui exigent tous deux le // statut 'livre', ValidateDeliveryAtomic accepte "pending", "assigned", -// "en_route" ET "livre" — c'est un override admin assumĂ© pour rĂ©gulariser une -// commande gĂ©rĂ©e hors flux normal, pas un bug. Les tests suivants documentent -// ce comportement rĂ©el pour qu'une future rĂ©gression involontaire soit dĂ©tectĂ©e. +// "en_route", "arrived" ET "livre" — c'est un override admin assumĂ© pour +// rĂ©gulariser une commande gĂ©rĂ©e hors flux normal, pas un bug. "arrived" a Ă©tĂ© +// ajoutĂ© pour que l'admin puisse toujours finaliser une commande arrivĂ©e Ă  +// destination (le seul bouton de finalisation cĂŽtĂ© admin passe par ce chemin), +// Ă  l'image de ApproveDeliveryAtomicByStaff. Les tests suivants documentent ce +// comportement rĂ©el pour qu'une future rĂ©gression involontaire soit dĂ©tectĂ©e. func TestValidateDeliveryAtomic_AcceptsAllDocumentedStatusesAndCreditsPoints(t *testing.T) { cleanupStockTestData(t) @@ -193,7 +196,7 @@ func TestValidateDeliveryAtomic_AcceptsAllDocumentedStatusesAndCreditsPoints(t * {Key: "pool_0", Name: "Pool Test", Categories: []string{"test"}, Tiers: []models.PointsTier{{Min: 0, Max: 0, Points: 6}}}, }) - for _, status := range []string{"pending", "assigned", "en_route", "livre"} { + for _, status := range []string{"pending", "assigned", "en_route", "arrived", "livre"} { t.Run(status, func(t *testing.T) { username := newTestClient(t, "validate_status_"+status) productID := newTestProduct(t, "ValidateStatus"+status, 20) @@ -218,7 +221,7 @@ func TestValidateDeliveryAtomic_AcceptsAllDocumentedStatusesAndCreditsPoints(t * func TestValidateDeliveryAtomic_RejectsStatusOutsideAllowedList(t *testing.T) { cleanupStockTestData(t) - for _, status := range []string{"cancelled", "pending_payment", "arrived"} { + for _, status := range []string{"cancelled", "pending_payment"} { t.Run(status, func(t *testing.T) { username := newTestClient(t, "validate_invalid_"+status) productID := newTestProduct(t, "ValidateInvalid"+status, 20)