From 39216fc1371072fa137803d1a10d328e968e3217 Mon Sep 17 00:00:00 2001 From: Xor290 Date: Tue, 4 Aug 2026 18:08:50 +0200 Subject: [PATCH] fix: fixup adresse correction --- backend/gestion/db/db_address.go | 27 +++++++--- .../gestion/services/adresses_correction.go | 21 ++------ backend/gestion/utils/utils.go | 13 +++++ frontend-prep/src/api/api.ts | 2 + frontend-prep/src/pages/User/Checkout.tsx | 50 +++++++++++++++++++ mobile/src/api/api.ts | 11 ++-- 6 files changed, 96 insertions(+), 28 deletions(-) diff --git a/backend/gestion/db/db_address.go b/backend/gestion/db/db_address.go index ad544f1c..ee10a52f 100644 --- a/backend/gestion/db/db_address.go +++ b/backend/gestion/db/db_address.go @@ -3,19 +3,34 @@ package db import ( "fmt" "gestion/models" + "gestion/utils" ) func (d *Database) CheckAddress(addressByUser *models.Command) error { var correction models.Address result := d.GDB.Where("invalid_address = ?", addressByUser.DeliveryAddress).First(&correction) - if result.Error != nil { - if isNotFound(result.Error) { - return nil - } + if result.Error == nil { + addressByUser.DeliveryAddress = correction.CorrectAddress + return fmt.Errorf("adresse invalide %s", correction.CorrectAddress) + } + if !isNotFound(result.Error) { return fmt.Errorf("checkAddress: %w", result.Error) } - addressByUser.DeliveryAddress = correction.CorrectAddress - return fmt.Errorf("adresse invalide %s", correction.CorrectAddress) + + // Pas de correspondance exacte — fallback sur une comparaison normalisée + // (accents/casse/espaces) pour rattraper les variantes mineures de saisie. + corrections, err := d.AllAddress() + if err != nil { + return nil + } + normalizedInput := utils.NormalizeAddress(addressByUser.DeliveryAddress) + for _, c := range corrections { + if utils.NormalizeAddress(c.InvalidAddress) == normalizedInput { + addressByUser.DeliveryAddress = c.CorrectAddress + return fmt.Errorf("adresse invalide %s", c.CorrectAddress) + } + } + return nil } func (d *Database) AddAddress(CorrectAddressByAdmin string, InvalidAddressByAdmin string) error { diff --git a/backend/gestion/services/adresses_correction.go b/backend/gestion/services/adresses_correction.go index c1ff1fbb..ea2a30f8 100644 --- a/backend/gestion/services/adresses_correction.go +++ b/backend/gestion/services/adresses_correction.go @@ -3,17 +3,13 @@ package services import ( "encoding/json" "fmt" + "gestion/utils" "io" "math" "net/http" "net/url" "strings" "time" - "unicode" - - "golang.org/x/text/runes" - "golang.org/x/text/transform" - "golang.org/x/text/unicode/norm" ) // ============================================ @@ -125,7 +121,7 @@ func (acs *AddressCorrectionService) nominatimFuzzySearch(address string) (*Addr CorrectedAddress: corrected, Coordinates: Coordinates{Latitude: best.Latitude, Longitude: best.Longitude}, Confidence: confidence, - CorrectionApplied: !strings.EqualFold(normalize(address), normalize(corrected)), + CorrectionApplied: !strings.EqualFold(utils.NormalizeAddress(address), utils.NormalizeAddress(corrected)), Source: "fuzzy", }, nil } @@ -233,7 +229,7 @@ func (acs *AddressCorrectionService) structuredSearch(address string) (*AddressS // buildAddressVariants génère plusieurs variantes d'une adresse pour maximiser les chances func buildAddressVariants(address string) []string { variants := []string{address} - normalized := normalize(address) + normalized := utils.NormalizeAddress(address) // Variante sans accents if normalized != address { @@ -377,8 +373,8 @@ func parseAddressParts(address string) addressParts { // computeConfidence calcule un score de similarité entre l'adresse originale et la suggestion func computeConfidence(original, suggested string, nominatimImportance float64) float64 { - origNorm := normalize(strings.ToLower(original)) - suggNorm := normalize(strings.ToLower(suggested)) + origNorm := utils.NormalizeAddress(strings.ToLower(original)) + suggNorm := utils.NormalizeAddress(strings.ToLower(suggested)) // Score de similarité sur les mots communs origWords := strings.Fields(origNorm) @@ -439,13 +435,6 @@ func formatNominatimAddress(s NominatimSuggestion) string { return strings.Join(parts, ", ") } -// normalize supprime les accents et normalise les espaces -func normalize(s string) string { - t := transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC) - result, _, _ := transform.String(t, s) - return strings.Join(strings.Fields(result), " ") -} - // isPostcode retourne true si le mot ressemble à un code postal français func isPostcode(s string) bool { if len(s) != 5 { diff --git a/backend/gestion/utils/utils.go b/backend/gestion/utils/utils.go index 8fe6ab13..526b33ca 100644 --- a/backend/gestion/utils/utils.go +++ b/backend/gestion/utils/utils.go @@ -6,6 +6,11 @@ import ( "math/big" "path/filepath" "strings" + "unicode" + + "golang.org/x/text/runes" + "golang.org/x/text/transform" + "golang.org/x/text/unicode/norm" ) func GenerateUniqueFileName(productName string, originalFileName string) string { @@ -30,3 +35,11 @@ func SanitizeFilePath(path string) (string, error) { return cleaned, nil } + +// NormalizeAddress supprime les accents et normalise les espaces, pour +// comparer deux adresses saisies différemment (casse/accents/espaces). +func NormalizeAddress(s string) string { + t := transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC) + result, _, _ := transform.String(t, s) + return strings.Join(strings.Fields(result), " ") +} diff --git a/frontend-prep/src/api/api.ts b/frontend-prep/src/api/api.ts index 5f0b7d22..6845f306 100644 --- a/frontend-prep/src/api/api.ts +++ b/frontend-prep/src/api/api.ts @@ -697,6 +697,8 @@ export const createCheckout = async (checkoutData: CheckoutData) => { message: data.error || "Erreur création", postal_code: data.postal_code as string | undefined, zone_error: isZoneError as boolean, + invalid_address: !!data.corrected_address, + suggested_address: data.corrected_address as string | undefined, }; } diff --git a/frontend-prep/src/pages/User/Checkout.tsx b/frontend-prep/src/pages/User/Checkout.tsx index 5b00ccf2..80c44803 100644 --- a/frontend-prep/src/pages/User/Checkout.tsx +++ b/frontend-prep/src/pages/User/Checkout.tsx @@ -48,6 +48,10 @@ function Checkout() { const [showZoneModal, setShowZoneModal] = useState(false); const [zoneErrorMsg, setZoneErrorMsg] = useState(''); + // État pour le modal adresse invalide (correction suggérée) + const [showInvalidAddressModal, setShowInvalidAddressModal] = useState(false); + const [suggestedAddress, setSuggestedAddress] = useState(''); + // Informations personnelles const [firstName, setFirstName] = useState(''); const [lastName, setLastName] = useState(''); @@ -315,6 +319,12 @@ function Checkout() { return; } + if (!response.success && response.invalid_address && response.suggested_address) { + setSuggestedAddress(response.suggested_address); + setShowInvalidAddressModal(true); + return; + } + if (response.success && response.command_id) { const { command_id, assigned_to, queue_info, delivery_address } = response; @@ -725,6 +735,46 @@ function Checkout() { )} + {/* ============================================ */} + {/* MODAL ADRESSE INVALIDE (CORRECTION SUGGÉRÉE) */} + {/* ============================================ */} + {showInvalidAddressModal && ( +
setShowInvalidAddressModal(false)}> +
e.stopPropagation()}> +
+ +

Adresse invalide

+
+
+
+
+

+ L'adresse saisie n'est pas reconnue. Voulez-vous utiliser l'adresse correcte suggérée ? +

+

+ {suggestedAddress} +

+
+
+
+
+ + +
+
+
+ )} + {/* ============================================ */} {/* MODAL DE CONFIRMATION STYLISÉ */} {/* ============================================ */} diff --git a/mobile/src/api/api.ts b/mobile/src/api/api.ts index 5cf050b6..20977ee1 100644 --- a/mobile/src/api/api.ts +++ b/mobile/src/api/api.ts @@ -360,19 +360,18 @@ export const checkoutCart = async ( price_currency: data.price_currency, }; } catch (error: any) { - const errMsg: string = error.response?.data?.error || "Erreur serveur"; - if (errMsg.startsWith("Adresse invalide ")) { - const suggested = errMsg.replace("Adresse invalide ", "").trim(); + const data = error.response?.data; + if (data?.corrected_address) { return { success: false, invalid_address: true, - suggested_address: suggested, - message: errMsg, + suggested_address: data.corrected_address, + message: data.error || "Adresse non reconnue", }; } return { success: false, - message: errMsg, + message: data?.error || "Erreur serveur", }; } };