fix: fixup adresse correction
This commit is contained in:
@@ -3,19 +3,34 @@ package db
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"gestion/models"
|
"gestion/models"
|
||||||
|
"gestion/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (d *Database) CheckAddress(addressByUser *models.Command) error {
|
func (d *Database) CheckAddress(addressByUser *models.Command) error {
|
||||||
var correction models.Address
|
var correction models.Address
|
||||||
result := d.GDB.Where("invalid_address = ?", addressByUser.DeliveryAddress).First(&correction)
|
result := d.GDB.Where("invalid_address = ?", addressByUser.DeliveryAddress).First(&correction)
|
||||||
if result.Error != nil {
|
if result.Error == nil {
|
||||||
if isNotFound(result.Error) {
|
addressByUser.DeliveryAddress = correction.CorrectAddress
|
||||||
return nil
|
return fmt.Errorf("adresse invalide %s", correction.CorrectAddress)
|
||||||
}
|
}
|
||||||
|
if !isNotFound(result.Error) {
|
||||||
return fmt.Errorf("checkAddress: %w", 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 {
|
func (d *Database) AddAddress(CorrectAddressByAdmin string, InvalidAddressByAdmin string) error {
|
||||||
|
|||||||
@@ -3,17 +3,13 @@ package services
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"gestion/utils"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"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,
|
CorrectedAddress: corrected,
|
||||||
Coordinates: Coordinates{Latitude: best.Latitude, Longitude: best.Longitude},
|
Coordinates: Coordinates{Latitude: best.Latitude, Longitude: best.Longitude},
|
||||||
Confidence: confidence,
|
Confidence: confidence,
|
||||||
CorrectionApplied: !strings.EqualFold(normalize(address), normalize(corrected)),
|
CorrectionApplied: !strings.EqualFold(utils.NormalizeAddress(address), utils.NormalizeAddress(corrected)),
|
||||||
Source: "fuzzy",
|
Source: "fuzzy",
|
||||||
}, nil
|
}, 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
|
// buildAddressVariants génère plusieurs variantes d'une adresse pour maximiser les chances
|
||||||
func buildAddressVariants(address string) []string {
|
func buildAddressVariants(address string) []string {
|
||||||
variants := []string{address}
|
variants := []string{address}
|
||||||
normalized := normalize(address)
|
normalized := utils.NormalizeAddress(address)
|
||||||
|
|
||||||
// Variante sans accents
|
// Variante sans accents
|
||||||
if normalized != address {
|
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
|
// computeConfidence calcule un score de similarité entre l'adresse originale et la suggestion
|
||||||
func computeConfidence(original, suggested string, nominatimImportance float64) float64 {
|
func computeConfidence(original, suggested string, nominatimImportance float64) float64 {
|
||||||
origNorm := normalize(strings.ToLower(original))
|
origNorm := utils.NormalizeAddress(strings.ToLower(original))
|
||||||
suggNorm := normalize(strings.ToLower(suggested))
|
suggNorm := utils.NormalizeAddress(strings.ToLower(suggested))
|
||||||
|
|
||||||
// Score de similarité sur les mots communs
|
// Score de similarité sur les mots communs
|
||||||
origWords := strings.Fields(origNorm)
|
origWords := strings.Fields(origNorm)
|
||||||
@@ -439,13 +435,6 @@ func formatNominatimAddress(s NominatimSuggestion) string {
|
|||||||
return strings.Join(parts, ", ")
|
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
|
// isPostcode retourne true si le mot ressemble à un code postal français
|
||||||
func isPostcode(s string) bool {
|
func isPostcode(s string) bool {
|
||||||
if len(s) != 5 {
|
if len(s) != 5 {
|
||||||
|
|||||||
@@ -6,6 +6,11 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"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 {
|
func GenerateUniqueFileName(productName string, originalFileName string) string {
|
||||||
@@ -30,3 +35,11 @@ func SanitizeFilePath(path string) (string, error) {
|
|||||||
|
|
||||||
return cleaned, nil
|
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), " ")
|
||||||
|
}
|
||||||
|
|||||||
@@ -697,6 +697,8 @@ export const createCheckout = async (checkoutData: CheckoutData) => {
|
|||||||
message: data.error || "Erreur création",
|
message: data.error || "Erreur création",
|
||||||
postal_code: data.postal_code as string | undefined,
|
postal_code: data.postal_code as string | undefined,
|
||||||
zone_error: isZoneError as boolean,
|
zone_error: isZoneError as boolean,
|
||||||
|
invalid_address: !!data.corrected_address,
|
||||||
|
suggested_address: data.corrected_address as string | undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,10 @@ function Checkout() {
|
|||||||
const [showZoneModal, setShowZoneModal] = useState(false);
|
const [showZoneModal, setShowZoneModal] = useState(false);
|
||||||
const [zoneErrorMsg, setZoneErrorMsg] = useState('');
|
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
|
// Informations personnelles
|
||||||
const [firstName, setFirstName] = useState('');
|
const [firstName, setFirstName] = useState('');
|
||||||
const [lastName, setLastName] = useState('');
|
const [lastName, setLastName] = useState('');
|
||||||
@@ -315,6 +319,12 @@ function Checkout() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!response.success && response.invalid_address && response.suggested_address) {
|
||||||
|
setSuggestedAddress(response.suggested_address);
|
||||||
|
setShowInvalidAddressModal(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (response.success && response.command_id) {
|
if (response.success && response.command_id) {
|
||||||
const { command_id, assigned_to, queue_info, delivery_address } = response;
|
const { command_id, assigned_to, queue_info, delivery_address } = response;
|
||||||
|
|
||||||
@@ -725,6 +735,46 @@ function Checkout() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* ============================================ */}
|
||||||
|
{/* MODAL ADRESSE INVALIDE (CORRECTION SUGGÉRÉE) */}
|
||||||
|
{/* ============================================ */}
|
||||||
|
{showInvalidAddressModal && (
|
||||||
|
<div className="confirmation-modal-overlay" onClick={() => setShowInvalidAddressModal(false)}>
|
||||||
|
<div className="confirmation-modal" onClick={(e) => e.stopPropagation()}>
|
||||||
|
<div className="confirmation-modal-header confirmation-modal-header--error">
|
||||||
|
<i className="fas fa-map-marker-alt confirmation-icon"></i>
|
||||||
|
<h2>Adresse invalide</h2>
|
||||||
|
</div>
|
||||||
|
<div className="confirmation-modal-body">
|
||||||
|
<div className="confirmation-section">
|
||||||
|
<div className="confirmation-detail confirmation-detail--centered">
|
||||||
|
<p style={{ marginBottom: '0.75rem' }}>
|
||||||
|
L'adresse saisie n'est pas reconnue. Voulez-vous utiliser l'adresse correcte suggérée ?
|
||||||
|
</p>
|
||||||
|
<p className="confirmation-detail--muted" style={{ fontWeight: 600 }}>
|
||||||
|
{suggestedAddress}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="confirmation-modal-actions">
|
||||||
|
<button className="confirmation-button confirmation-button--neutral" onClick={() => setShowInvalidAddressModal(false)}>
|
||||||
|
Modifier
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="confirmation-button"
|
||||||
|
onClick={() => {
|
||||||
|
setAddress(suggestedAddress);
|
||||||
|
setShowInvalidAddressModal(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Utiliser cette adresse
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* ============================================ */}
|
{/* ============================================ */}
|
||||||
{/* MODAL DE CONFIRMATION STYLISÉ */}
|
{/* MODAL DE CONFIRMATION STYLISÉ */}
|
||||||
{/* ============================================ */}
|
{/* ============================================ */}
|
||||||
|
|||||||
@@ -360,19 +360,18 @@ export const checkoutCart = async (
|
|||||||
price_currency: data.price_currency,
|
price_currency: data.price_currency,
|
||||||
};
|
};
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
const errMsg: string = error.response?.data?.error || "Erreur serveur";
|
const data = error.response?.data;
|
||||||
if (errMsg.startsWith("Adresse invalide ")) {
|
if (data?.corrected_address) {
|
||||||
const suggested = errMsg.replace("Adresse invalide ", "").trim();
|
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
invalid_address: true,
|
invalid_address: true,
|
||||||
suggested_address: suggested,
|
suggested_address: data.corrected_address,
|
||||||
message: errMsg,
|
message: data.error || "Adresse non reconnue",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: errMsg,
|
message: data?.error || "Erreur serveur",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user