From 9e6473ed3fe34465ab92c2d589387838cbc749c2 Mon Sep 17 00:00:00 2001 From: Xor290 Date: Wed, 1 Jul 2026 20:10:00 +0200 Subject: [PATCH] fix: sql and redis request --- backend/gestion/db/db_clients.go | 22 +++++++ backend/gestion/db/db_command_items.go | 86 ++++++++++++++++++++++++++ backend/gestion/handlers/deleviry.go | 19 +++++- 3 files changed, 124 insertions(+), 3 deletions(-) diff --git a/backend/gestion/db/db_clients.go b/backend/gestion/db/db_clients.go index 2afb93ca..1337524b 100644 --- a/backend/gestion/db/db_clients.go +++ b/backend/gestion/db/db_clients.go @@ -292,6 +292,28 @@ func (d *Database) GetClientByTelephone(telephone string) (*models.Client, error } // GetClientByUsername récupère un client par son username +// GetClientsByUsernames charge plusieurs clients en une seule requête. +// Retourne map[username]*Client ; les usernames sans correspondance sont absents de la map. +func (d *Database) GetClientsByUsernames(usernames []string) (map[string]*models.Client, error) { + result := make(map[string]*models.Client, len(usernames)) + if len(usernames) == 0 { + return result, nil + } + var rows []struct { + ID int `gorm:"column:id"` + Username string `gorm:"column:username"` + Nom string `gorm:"column:nom"` + Prenom string `gorm:"column:prenom"` + } + if err := d.GDB.Raw(`SELECT id, username, nom, prenom FROM clients WHERE username IN ?`, usernames).Scan(&rows).Error; err != nil { + return nil, err + } + for _, r := range rows { + result[r.Username] = &models.Client{ID: r.ID, Username: r.Username, Nom: r.Nom, Prenom: r.Prenom} + } + return result, nil +} + func (d *Database) GetClientByUsername(username string) (*models.Client, error) { var row struct { ID int `gorm:"column:id"` diff --git a/backend/gestion/db/db_command_items.go b/backend/gestion/db/db_command_items.go index ed5e9865..61ef85a5 100644 --- a/backend/gestion/db/db_command_items.go +++ b/backend/gestion/db/db_command_items.go @@ -308,6 +308,92 @@ func (d *Database) GetCommandItems(commandID int) ([]map[string]any, error) { return items, nil } +// GetCommandItemsBatch charge les items de plusieurs commandes en une seule requête. +// Retourne map[commandID][]items, même structure que GetCommandItems. +func (d *Database) GetCommandItemsBatch(commandIDs []int) (map[int][]map[string]any, error) { + result := make(map[int][]map[string]any, len(commandIDs)) + if len(commandIDs) == 0 { + return result, nil + } + + var rows []struct { + ID int `gorm:"column:id"` + CommandID int `gorm:"column:command_id"` + Produit string `gorm:"column:produit"` + ProductID *int64 `gorm:"column:product_id"` + Quantite float64 `gorm:"column:quantite"` + Prix float64 `gorm:"column:prix"` + IsReward bool `gorm:"column:is_reward"` + RewardPoolKey string `gorm:"column:reward_pool_key"` + ClientUsername string `gorm:"column:client_username"` + ClientNom string `gorm:"column:client_nom"` + ClientPrenom string `gorm:"column:client_prenom"` + ClientTelephone string `gorm:"column:client_telephone"` + DeliveryAddress *string `gorm:"column:delivery_address"` + Status *string `gorm:"column:status"` + CreatedAt time.Time `gorm:"column:created_at"` + UpdatedAt time.Time `gorm:"column:updated_at"` + CommandStatus *string `gorm:"column:command_status"` + CommandAddress *string `gorm:"column:command_address"` + TotalPrix float64 `gorm:"column:total_prix"` + ReferralUsed float64 `gorm:"column:referral_used"` + LivreurAssign *string `gorm:"column:livreur_assign"` + CommandCreatedAt *time.Time `gorm:"column:command_created_at"` + Category string `gorm:"column:category"` + Unit string `gorm:"column:unit"` + ClientOrderNumber int `gorm:"column:client_order_number"` + } + + err := d.GDB.Raw(` + SELECT + ci.id, ci.command_id, ci.produit, ci.product_id, + ci.quantite, ci.prix, ci.is_reward, ci.reward_pool_key, + ci.client_username, ci.client_nom, ci.client_prenom, ci.client_telephone, + ci.delivery_address, ci.status, ci.created_at, ci.updated_at, + c.status as command_status, c.adresse as command_address, + c.total_prix, c.referral_used, c.livreur_assign, + c.created_at as command_created_at, + COALESCE(p.category, '') as category, + COALESCE(p.unit, '') as unit, + c.client_order_id as client_order_number + FROM command_items ci + LEFT JOIN commandes c ON ci.command_id = c.id + LEFT JOIN products p ON ci.product_id = p.id + WHERE ci.command_id IN ? + ORDER BY ci.command_id ASC, ci.id ASC`, commandIDs).Scan(&rows).Error + if err != nil { + return nil, fmt.Errorf("erreur récupération items batch: %w", err) + } + + for _, row := range rows { + productIDValue := 0 + if row.ProductID != nil { + productIDValue = int(*row.ProductID) + } + var commandCreatedAt any + if row.CommandCreatedAt != nil { + commandCreatedAt = *row.CommandCreatedAt + } + item := map[string]any{ + "id": row.ID, "command_id": row.CommandID, + "produit": row.Produit, "product_id": productIDValue, + "quantite": row.Quantite, "prix": row.Prix, + "is_reward": row.IsReward, "reward_pool_key": row.RewardPoolKey, + "client_username": row.ClientUsername, "client_nom": row.ClientNom, + "client_prenom": row.ClientPrenom, "client_telephone": row.ClientTelephone, + "delivery_address": ptrStr(row.DeliveryAddress), "status": ptrStr(row.Status), + "created_at": row.CreatedAt, "updated_at": row.UpdatedAt, + "command_status": ptrStr(row.CommandStatus), "command_address": ptrStr(row.CommandAddress), + "total_prix": row.TotalPrix, "referral_used": row.ReferralUsed, + "livreur_assign": ptrStr(row.LivreurAssign), "command_created_at": commandCreatedAt, + "category": row.Category, "unit": row.Unit, + "client_order_number": row.ClientOrderNumber, + } + result[row.CommandID] = append(result[row.CommandID], item) + } + return result, nil +} + // ptrStr retourne la valeur d'un *string ou "" si nil func ptrStr(s *string) string { if s == nil { diff --git a/backend/gestion/handlers/deleviry.go b/backend/gestion/handlers/deleviry.go index 3d8d8fca..ccb33326 100644 --- a/backend/gestion/handlers/deleviry.go +++ b/backend/gestion/handlers/deleviry.go @@ -40,14 +40,27 @@ func GetMyDeliveries(c *gin.Context) { return } + // Collecter tous les IDs et usernames en une passe pour éviter les N+1 + commandIDs := make([]int, 0, len(commands)) + clientUsernames := make([]string, 0, len(commands)) + for _, cmd := range commands { + if cid, _ := strconv.Atoi(fmt.Sprintf("%v", cmd["id"])); cid > 0 { + commandIDs = append(commandIDs, cid) + } + if u, _ := cmd["username"].(string); u != "" { + clientUsernames = append(clientUsernames, u) + } + } + allItems, _ := database.GetCommandItemsBatch(commandIDs) + allClients, _ := database.GetClientsByUsernames(clientUsernames) + filteredCommands := make([]gin.H, len(commands)) for i, cmd := range commands { commandID, _ := strconv.Atoi(fmt.Sprintf("%v", cmd["id"])) - items, _ := database.GetCommandItems(commandID) + items := allItems[commandID] - // Client info SANS téléphone clientUsername, _ := cmd["username"].(string) - client, _ := database.GetClientByUsername(clientUsername) + client := allClients[clientUsername] clientInfo := gin.H{"nom": "Client", "prenom": ""} if client != nil {