This commit is contained in:
Xor290
2026-05-13 16:43:20 +02:00
parent 65d1367f42
commit 0039dda8a0
8 changed files with 61 additions and 700 deletions
-146
View File
@@ -7,58 +7,6 @@ import (
"gorm.io/gorm"
)
// AddProductInBasket ajoute un produit au panier de l'utilisateur
func (d *Database) AddProductInBasket(username, nameProduct string, quantity float64, category string) (*models.Panier, error) {
var productResult struct {
ID int `gorm:"column:id"`
}
err := d.GDB.Raw(`SELECT id FROM products WHERE LOWER(name) = LOWER(?) AND LOWER(category) = LOWER(?)`,
nameProduct, category).Scan(&productResult).Error
if err != nil {
return nil, fmt.Errorf("erreur lors de la recherche du produit: %w", err)
}
if productResult.ID == 0 {
return nil, fmt.Errorf("produit '%s' non trouvé dans la catégorie '%s'", nameProduct, category)
}
productID := productResult.ID
price, err := d.GetProductPrice(nameProduct, category, quantity)
if err != nil {
return nil, fmt.Errorf("erreur récupération prix: %w", err)
}
var existing struct {
ID int `gorm:"column:id"`
Quantity float64 `gorm:"column:quantity"`
Price float64 `gorm:"column:price"`
}
d.GDB.Raw(`SELECT id, quantity, price FROM baskets WHERE username = ? AND product_id = ?`,
username, productID).Scan(&existing)
var basket models.Panier
if existing.ID != 0 {
newQuantity := existing.Quantity + quantity
newPrice := existing.Price + price
err = d.GDB.Raw(`
UPDATE baskets SET quantity = ?, price = ?, created_at = CURRENT_TIMESTAMP
WHERE id = ? RETURNING id, username, product_id, quantity, price, created_at`,
newQuantity, newPrice, existing.ID).Scan(&basket).Error
if err != nil {
return nil, fmt.Errorf("erreur lors de la mise à jour du panier: %w", err)
}
} else {
err = d.GDB.Raw(`
INSERT INTO baskets (username, product_id, quantity, price, created_at)
VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP)
RETURNING id, username, product_id, quantity, price, created_at`,
username, productID, quantity, price).Scan(&basket).Error
if err != nil {
return nil, fmt.Errorf("erreur lors de l'ajout au panier: %w", err)
}
}
return &basket, nil
}
// GetProductPrice récupère le prix réel d'un produit pour une quantité donnée (legacy)
func (d *Database) GetProductPrice(name, category string, quantity float64) (float64, error) {
var result struct {
@@ -79,32 +27,6 @@ func (d *Database) GetProductPrice(name, category string, quantity float64) (flo
return result.Price, nil
}
func (d *Database) GetProductStock(name, category string) (float64, error) {
var result struct {
Stock float64 `gorm:"column:stock"`
}
err := d.GDB.Raw(`SELECT stock FROM products WHERE LOWER(name) = LOWER(?) AND LOWER(category) = LOWER(?)`,
name, category).Scan(&result).Error
if err != nil {
return 0, fmt.Errorf("produit non trouvé: %w", err)
}
return result.Stock, nil
}
func (d *Database) DecrementProductStock(name, category string, quantity float64) error {
result := d.GDB.Exec(`
UPDATE products SET stock = stock - ?
WHERE LOWER(name) = LOWER(?) AND LOWER(category) = LOWER(?) AND stock >= ?`,
quantity, name, category, quantity)
if result.Error != nil {
return fmt.Errorf("erreur mise à jour stock: %w", result.Error)
}
if result.RowsAffected == 0 {
return fmt.Errorf("stock insuffisant pour le produit")
}
return nil
}
// GetAllProductsInBasket récupère tous les produits du panier d'un utilisateur
func (d *Database) GetAllProductsInBasket(username string) ([]models.Panier, error) {
var baskets []models.Panier
@@ -223,74 +145,6 @@ func (d *Database) ClearBasketOnCheckout(username string) error {
return d.GDB.Exec(`DELETE FROM baskets WHERE username = ?`, username).Error
}
// GetBasketTotal calcule le montant total du panier d'un utilisateur
func (d *Database) GetBasketTotal(username string) (float64, error) {
var result struct {
Total float64 `gorm:"column:total"`
}
err := d.GDB.Raw(`SELECT COALESCE(SUM(price), 0) as total FROM baskets WHERE username = ?`,
username).Scan(&result).Error
if err != nil {
return 0, fmt.Errorf("erreur lors du calcul du total: %w", err)
}
return result.Total, nil
}
// GetBasketItemCount compte le nombre d'items dans le panier
func (d *Database) GetBasketItemCount(username string) (int, error) {
var result struct {
Count int `gorm:"column:count"`
}
err := d.GDB.Raw(`SELECT COUNT(*) as count FROM baskets WHERE username = ?`,
username).Scan(&result).Error
if err != nil {
return 0, fmt.Errorf("erreur lors du comptage des items: %w", err)
}
return result.Count, nil
}
func (d *Database) UpdateBasketItemQuantity(basketID int, newQuantity float64) error {
if newQuantity <= 0 {
return fmt.Errorf("quantité invalide")
}
return d.GDB.Transaction(func(tx *gorm.DB) error {
var item struct {
ProductID int `gorm:"column:product_id"`
Quantity float64 `gorm:"column:quantity"`
}
if err := tx.Raw(`SELECT product_id, quantity FROM baskets WHERE id = ? FOR UPDATE`, basketID).Scan(&item).Error; err != nil {
return fmt.Errorf("produit non trouvé: %w", err)
}
if item.ProductID == 0 {
return fmt.Errorf("panier item introuvable: %d", basketID)
}
diff := newQuantity - item.Quantity
if diff > 0 {
result := tx.Exec(`UPDATE products SET stock = stock - ? WHERE id = ? AND stock >= ?`,
diff, item.ProductID, diff)
if result.Error != nil {
return fmt.Errorf("erreur stock: %w", result.Error)
}
if result.RowsAffected == 0 {
return fmt.Errorf("stock insuffisant")
}
} else if diff < 0 {
if err := tx.Exec(`UPDATE products SET stock = stock + ? WHERE id = ?`,
-diff, item.ProductID).Error; err != nil {
return fmt.Errorf("erreur stock: %w", err)
}
}
if err := tx.Exec(`UPDATE baskets SET quantity = ? WHERE id = ?`,
newQuantity, basketID).Error; err != nil {
return fmt.Errorf("erreur panier: %w", err)
}
return nil
})
}
func (d *Database) GetBasketItemOwner(basketID int) (string, error) {
var username string
err := d.GDB.Raw(`SELECT username FROM baskets WHERE id = ?`, basketID).Scan(&username).Error
+22 -106
View File
@@ -35,16 +35,16 @@ func (d *Database) CreateClient(client *models.Client) error {
// GetClientByID récupère un client par son ID
func (d *Database) GetClientByID(id int) (*models.Client, error) {
var row struct {
ID int `gorm:"column:id"`
Username string `gorm:"column:username"`
Password string `gorm:"column:password"`
Nom string `gorm:"column:nom"`
Prenom string `gorm:"column:prenom"`
Telephone string `gorm:"column:telephone"`
Command int `gorm:"column:command"`
Amende float64 `gorm:"column:amende"`
PointsExtraJSON []byte `gorm:"column:points_extra"`
CreatedAt time.Time `gorm:"column:created_at"`
ID int `gorm:"column:id"`
Username string `gorm:"column:username"`
Password string `gorm:"column:password"`
Nom string `gorm:"column:nom"`
Prenom string `gorm:"column:prenom"`
Telephone string `gorm:"column:telephone"`
Command int `gorm:"column:command"`
Amende float64 `gorm:"column:amende"`
PointsExtraJSON []byte `gorm:"column:points_extra"`
CreatedAt time.Time `gorm:"column:created_at"`
}
err := d.GDB.Raw(`
SELECT id, username, password, nom, prenom, telephone, command, amende,
@@ -190,44 +190,6 @@ func (d *Database) UpdateClientPasswordAndClearFlag(clientID int, hashedPassword
return nil
}
// GetClientStats récupère les statistiques d'un client
func (d *Database) GetClientStats(clientID int) (map[string]interface{}, error) {
client, err := d.GetClientByID(clientID)
if err != nil {
return nil, err
}
var statsResult struct {
Total int `gorm:"column:total"`
Pending int `gorm:"column:pending"`
Completed int `gorm:"column:completed"`
}
if err := d.GDB.Raw(`
SELECT
COUNT(*) as total,
COALESCE(SUM(CASE WHEN status = 'pending' OR status = 'livre' THEN 1 ELSE 0 END), 0) as pending,
COALESCE(SUM(CASE WHEN status = 'approved' THEN 1 ELSE 0 END), 0) as completed
FROM commandes WHERE username = ?`, client.Username).Scan(&statsResult).Error; err != nil {
log.Printf("⚠️ Erreur calcul stats: %v", err)
}
stats := map[string]interface{}{
"id": clientID,
"username": client.Username,
"nom": client.Nom,
"prenom": client.Prenom,
"telephone": client.Telephone,
"total_commands": statsResult.Total,
"pending_commands": statsResult.Pending,
"completed_commands": statsResult.Completed,
"points_extra": client.PointsExtra,
"amende": client.Amende,
"member_since": client.CreatedAt,
}
return stats, nil
}
func (d *Database) GetClientAmende(username string) (float64, error) {
var result struct {
Amende float64 `gorm:"column:amende"`
@@ -242,37 +204,6 @@ func (d *Database) GetClientAmende(username string) (float64, error) {
return result.Amende, nil
}
func (d *Database) PayClientPenalties(username string, amountPaid float64) error {
log.Printf("💳 [PayClientPenalties] Paiement de %.2f points pour %s", amountPaid, username)
currentAmount, err := d.GetClientAmende(username)
if err != nil {
return err
}
if currentAmount <= 0 {
return fmt.Errorf("aucune pénalité à payer")
}
if amountPaid < currentAmount {
return fmt.Errorf("montant insuffisant: %.2f payé, %.2f requis", amountPaid, currentAmount)
}
result := d.GDB.Model(&models.Client{}).Where("username = ?", username).Update("amende", 0.0)
if result.Error != nil {
log.Printf("❌ [PayClientPenalties] Erreur UPDATE: %v", result.Error)
return fmt.Errorf("erreur paiement pénalités: %w", result.Error)
}
if result.RowsAffected == 0 {
return fmt.Errorf("client non trouvé")
}
cacheKey := fmt.Sprintf("client:%s", username)
Redis.Del(RedisCtx, cacheKey)
return nil
}
// IncrementClientCommandCount incrémente le compteur de commandes du client
func (d *Database) IncrementClientCommandCount(username string) error {
result := d.GDB.Model(&models.Client{}).Where("username = ?", username).UpdateColumn("command", gorm.Expr("command + 1"))
@@ -413,7 +344,7 @@ func (d *Database) SetClientTwoFAEnabled(clientID int, enabled bool) error {
return d.GDB.Model(&models.Client{}).Where("id = ?", clientID).Update("two_fa_enabled", enabled).Error
}
func (d *Database) GetClientPenaltiesInfo(username string) (map[string]interface{}, error) {
func (d *Database) GetClientPenaltiesInfo(username string) (map[string]any, error) {
amende, err := d.GetClientAmende(username)
if err != nil {
return nil, err
@@ -428,13 +359,13 @@ func (d *Database) GetClientPenaltiesInfo(username string) (map[string]interface
cancellationHistory, err := d.GetClientCancellationHistory(username)
if err != nil {
log.Printf("⚠️ [GetClientPenaltiesInfo] Erreur récup historique: %v", err)
cancellationHistory = map[string]interface{}{
cancellationHistory = map[string]any{
"cancellations_count": cancellationsCount,
"next_penalty": 20,
}
}
info := map[string]interface{}{
info := map[string]any{
"username": username,
"total_penalty": amende,
"cancellations_count": cancellationsCount,
@@ -445,21 +376,6 @@ func (d *Database) GetClientPenaltiesInfo(username string) (map[string]interface
return info, nil
}
// CheckClientCanOrder vérifie si un client peut passer commande (pas de pénalités impayées)
func (d *Database) CheckClientCanOrder(username string) (bool, float64, error) {
amende, err := d.GetClientAmende(username)
if err != nil {
return false, 0, err
}
if amende > 0 {
log.Printf("⚠️ [CheckClientCanOrder] Client %s bloqué: %.2f points de pénalités", username, amende)
return false, amende, fmt.Errorf("pénalités impayées: %.2f points", amende)
}
return true, 0, nil
}
// ResetClientPoint réinitialise les points d'un client.
// extraPoolKey != "" → reset points_extra[extraPoolKey] uniquement
// extraPoolKey == "" (poolIdx=-1) → reset total points_extra
@@ -520,12 +436,12 @@ func (d *Database) ResetClientPenalties(username string, resetCancellationsCount
return nil
}
func (d *Database) GetAllClientsWithPenalties() ([]map[string]interface{}, error) {
func (d *Database) GetAllClientsWithPenalties() ([]map[string]any, error) {
var rows []struct {
Username string `gorm:"column:username"`
Amende float64 `gorm:"column:amende"`
CancellationsCount int `gorm:"column:cancellations_count"`
UpdatedAt interface{} `gorm:"column:updated_at"`
Username string `gorm:"column:username"`
Amende float64 `gorm:"column:amende"`
CancellationsCount int `gorm:"column:cancellations_count"`
UpdatedAt any `gorm:"column:updated_at"`
}
err := d.GDB.Raw(`
SELECT username, amende, COALESCE(cancellations_count, 0) as cancellations_count, updated_at
@@ -537,9 +453,9 @@ func (d *Database) GetAllClientsWithPenalties() ([]map[string]interface{}, error
return nil, fmt.Errorf("erreur récupération clients: %w", err)
}
clients := make([]map[string]interface{}, 0, len(rows))
clients := make([]map[string]any, 0, len(rows))
for _, row := range rows {
clients = append(clients, map[string]interface{}{
clients = append(clients, map[string]any{
"username": row.Username,
"total_penalty": row.Amende,
"cancellations_count": row.CancellationsCount,
@@ -552,7 +468,7 @@ func (d *Database) GetAllClientsWithPenalties() ([]map[string]interface{}, error
return clients, nil
}
func (d *Database) GetClientPenaltiesStats() (map[string]interface{}, error) {
func (d *Database) GetClientPenaltiesStats() (map[string]any, error) {
var result struct {
ClientsWithPenalties int `gorm:"column:clients_with_penalties"`
TotalPenalties float64 `gorm:"column:total_penalties"`
@@ -574,7 +490,7 @@ func (d *Database) GetClientPenaltiesStats() (map[string]interface{}, error) {
return nil, fmt.Errorf("erreur récupération stats: %w", err)
}
stats := map[string]interface{}{
stats := map[string]any{
"clients_with_penalties": result.ClientsWithPenalties,
"total_penalties": result.TotalPenalties,
"average_penalty": result.AvgPenalty,
+35 -134
View File
@@ -3,6 +3,7 @@ package db
import (
"fmt"
"log"
"slices"
"strings"
"time"
)
@@ -79,10 +80,8 @@ func validateItemStatus(status string) error {
status = strings.ToLower(strings.TrimSpace(status))
for _, valid := range validStatuses {
if status == valid {
return nil
}
if !slices.Contains(validStatuses, status) {
return fmt.Errorf("...")
}
return fmt.Errorf("statut invalide: %s", status)
@@ -181,7 +180,7 @@ func (d *Database) InsertCommandItemWithClientInfo(
// GET COMMAND ITEMS - VERSION SÉCURISÉE + FIX NULL
// ============================================
func (d *Database) GetCommandItems(commandID int) ([]map[string]interface{}, error) {
func (d *Database) GetCommandItems(commandID int) ([]map[string]any, error) {
log.Printf("📦 [GetCommandItems] START - commandID=%d", commandID)
// ✅ VALIDATION
@@ -191,28 +190,28 @@ func (d *Database) GetCommandItems(commandID int) ([]map[string]interface{}, err
}
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"`
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"`
ClientOrderNumber int `gorm:"column:client_order_number"`
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"`
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"`
ClientOrderNumber int `gorm:"column:client_order_number"`
}
err := d.GDB.Raw(`
@@ -249,19 +248,19 @@ func (d *Database) GetCommandItems(commandID int) ([]map[string]interface{}, err
return nil, fmt.Errorf("erreur récupération items: %w", err)
}
items := make([]map[string]interface{}, 0, len(rows))
items := make([]map[string]any, 0, len(rows))
for _, row := range rows {
productIDValue := 0
if row.ProductID != nil {
productIDValue = int(*row.ProductID)
}
var commandCreatedAt interface{}
var commandCreatedAt any
if row.CommandCreatedAt != nil {
commandCreatedAt = *row.CommandCreatedAt
}
item := map[string]interface{}{
item := map[string]any{
"id": row.ID,
"command_id": row.CommandID,
"produit": row.Produit,
@@ -277,11 +276,11 @@ func (d *Database) GetCommandItems(commandID int) ([]map[string]interface{}, err
"created_at": row.CreatedAt,
"updated_at": row.UpdatedAt,
// Infos commande
"command_status": ptrStr(row.CommandStatus),
"command_address": ptrStr(row.CommandAddress),
"total_prix": row.TotalPrix,
"referral_used": row.ReferralUsed,
"livreur_assign": ptrStr(row.LivreurAssign),
"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,
"client_order_number": row.ClientOrderNumber,
@@ -301,104 +300,6 @@ func ptrStr(s *string) string {
return *s
}
func (d *Database) GetCommandItemsByUsername(username string) ([]map[string]interface{}, error) {
if err := validateUsername(username); err != nil {
log.Printf("❌ [GetCommandItemsByUsername] %v", err)
return nil, err
}
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"`
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"`
LivreurAssign *string `gorm:"column:livreur_assign"`
CommandCreatedAt *time.Time `gorm:"column:command_created_at"`
}
err := d.GDB.Raw(`
SELECT
ci.id,
ci.command_id,
ci.produit,
ci.product_id,
ci.quantite,
ci.prix,
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.livreur_assign,
c.created_at as command_created_at
FROM command_items ci
LEFT JOIN commandes c ON ci.command_id = c.id
WHERE ci.client_username = ?
ORDER BY ci.command_id DESC, ci.id ASC`, username).Scan(&rows).Error
if err != nil {
log.Printf("❌ Erreur query: %v", err)
return nil, fmt.Errorf("erreur récupération items: %w", err)
}
items := make([]map[string]interface{}, 0, len(rows))
for _, row := range rows {
productIDValue := 0
if row.ProductID != nil {
productIDValue = int(*row.ProductID)
}
var commandCreatedAt interface{}
if row.CommandCreatedAt != nil {
commandCreatedAt = *row.CommandCreatedAt
}
item := map[string]interface{}{
"id": row.ID,
"command_id": row.CommandID,
"produit": row.Produit,
"product_id": productIDValue,
"quantite": row.Quantite,
"prix": row.Prix,
"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,
"livreur_assign": ptrStr(row.LivreurAssign),
"command_created_at": commandCreatedAt,
}
items = append(items, item)
}
log.Printf("✅ %d items récupérés pour l'utilisateur %s", len(items), username)
return items, nil
}
func (d *Database) DeleteCommandItem(commandID, itemID int) error {
log.Printf("🗑️ [DeleteCommandItem] START - commandID=%d, itemID=%d", commandID, itemID)
@@ -411,7 +312,7 @@ func (d *Database) DeleteCommandItem(commandID, itemID int) error {
// Récupérer le prix et la quantité avant suppression pour mettre à jour le total
var result struct {
Prix float64 `gorm:"column:prix"`
Prix float64 `gorm:"column:prix"`
Quantite float64 `gorm:"column:quantite"`
}
if err := d.GDB.Raw(`SELECT prix, quantite FROM command_items WHERE id = ? AND command_id = ?`, itemID, commandID).Scan(&result).Error; err != nil {
+4 -87
View File
@@ -7,7 +7,6 @@ package db
import (
"fmt"
"gestion/models"
"log"
"slices"
)
@@ -44,95 +43,13 @@ func (d *Database) GetAllCommandsOldestFirst(status, username string) ([]map[str
return commands, nil
}
// GetOldestPendingCommand récupère la commande pending la plus ancienne
func (d *Database) GetOldestPendingCommand() (map[string]any, error) {
var commands []map[string]any
err := d.GDB.Raw(`
SELECT c.id, c.username, c.status, c.adresse, c.total_prix,
c.livreur_assign, c.created_at, c.updated_at
FROM commandes c
WHERE c.status = 'pending'
ORDER BY c.created_at ASC
LIMIT 1`).Scan(&commands).Error
if err != nil {
return nil, fmt.Errorf("erreur récupération commande la plus ancienne: %w", err)
}
if len(commands) == 0 {
return nil, nil
}
return commands[0], nil
}
// GetPendingCommandsWithPriority récupère les commandes pending avec calcul de priorité
func (d *Database) GetPendingCommandsWithPriority() ([]*models.CommandPriority, error) {
var rows []struct {
ID int `gorm:"column:id"`
Username string `gorm:"column:username"`
Status string `gorm:"column:status"`
Adresse string `gorm:"column:adresse"`
TotalPrix float64 `gorm:"column:total_prix"`
CreatedAt string `gorm:"column:created_at"`
UpdatedAt string `gorm:"column:updated_at"`
WaitingSeconds float64 `gorm:"column:waiting_seconds"`
}
err := d.GDB.Raw(`
SELECT c.id, c.username, c.status, c.adresse, c.total_prix,
c.created_at, c.updated_at,
EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - c.created_at)) as waiting_seconds
FROM commandes c
WHERE c.status = 'pending'
ORDER BY c.created_at ASC`).Scan(&rows).Error
if err != nil {
return nil, fmt.Errorf("erreur récupération commandes avec priorité: %w", err)
}
commands := make([]*models.CommandPriority, 0, len(rows))
for _, row := range rows {
cmd := &models.CommandPriority{
ID: row.ID,
Username: row.Username,
Status: row.Status,
Address: row.Adresse,
TotalPrice: row.TotalPrix,
WaitingSeconds: int(row.WaitingSeconds),
WaitingMinutes: int(row.WaitingSeconds / 60),
}
commands = append(commands, cmd)
}
return commands, nil
}
// GetCommandWaitingTime récupère le temps d'attente d'une commande
func (d *Database) GetCommandWaitingTime(commandID int) (int, error) {
var result struct {
WaitingSeconds int `gorm:"column:waiting_seconds"`
}
err := d.GDB.Raw(`
SELECT EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - created_at))::INTEGER as waiting_seconds
FROM commandes WHERE id = ?`, commandID).Scan(&result).Error
if err != nil {
return 0, fmt.Errorf("erreur récupération temps d'attente: %w", err)
}
if result.WaitingSeconds == 0 {
// Vérifie si la commande existe vraiment
var exists bool
d.GDB.Raw(`SELECT EXISTS(SELECT 1 FROM commandes WHERE id = ?)`, commandID).Scan(&exists)
if !exists {
return 0, fmt.Errorf("commande non trouvée")
}
}
return result.WaitingSeconds, nil
}
// GetPendingCommandsStats récupère des statistiques sur les commandes en attente
func (d *Database) GetPendingCommandsStats() (map[string]any, error) {
var result struct {
TotalPending int `gorm:"column:total_pending"`
AvgWaitingSeconds *float64 `gorm:"column:avg_waiting_seconds"`
OldestCommandDate *string `gorm:"column:oldest_command_date"`
NewestCommandDate *string `gorm:"column:newest_command_date"`
TotalPending int `gorm:"column:total_pending"`
AvgWaitingSeconds *float64 `gorm:"column:avg_waiting_seconds"`
OldestCommandDate *string `gorm:"column:oldest_command_date"`
NewestCommandDate *string `gorm:"column:newest_command_date"`
}
err := d.GDB.Raw(`
-22
View File
@@ -349,14 +349,6 @@ func (d *Database) GetAllCommands(status, username string) ([]map[string]any, er
return commands, nil
}
func (d *Database) GetCommandCount() (int, error) {
var count int64
if err := d.GDB.Model(&models.Command{}).Count(&count).Error; err != nil {
return 0, fmt.Errorf("erreur récupération count commandes: %w", err)
}
return int(count), nil
}
func (d *Database) SetCommandReferralUsed(commandID int, amount float64) error {
return d.GDB.Exec(`UPDATE commandes SET referral_used = ? WHERE id = ?`, amount, commandID).Error
}
@@ -432,20 +424,6 @@ func (d *Database) GetClientOrderID(commandID int) int {
return result.ClientOrderID
}
func (d *Database) GetCommandAddress(commandID int) (string, error) {
var result struct {
Adresse string `gorm:"column:adresse"`
}
if err := d.GDB.Model(&models.Command{}).Select("adresse").Where("id = ?", commandID).First(&result).Error; err != nil {
return "", fmt.Errorf("erreur lors de la récupération de l'adresse: %w", err)
}
if result.Adresse == "" {
return "", fmt.Errorf("commande non trouvée")
}
return result.Adresse, nil
}
func (d *Database) UpdateCommandAddress(commandID int, deliveryAddress string) error {
if len(deliveryAddress) > 500 {
return fmt.Errorf("adresse trop longue (max 500 caractères)")
-16
View File
@@ -117,22 +117,6 @@ func (d *Database) GetDeliveryPersonCommands(livreurUsername string, status stri
return commands, nil
}
func (d *Database) IncrementLivreurDeliveryCount(livreurUsername string) error {
result := d.GDB.Exec(`
UPDATE users
SET livraison = livraison + 1,
total = total + 1,
updated_at = CURRENT_TIMESTAMP
WHERE username = ? AND role = 'livreur'`, livreurUsername)
if result.Error != nil {
return fmt.Errorf("erreur lors de l'incrémentation des livraisons: %w", result.Error)
}
if result.RowsAffected == 0 {
return fmt.Errorf("livreur non trouvé")
}
return nil
}
func (d *Database) ApproveDelivery(commandID int, clientUsername string) error {
return d.GDB.Transaction(func(tx *gorm.DB) error {
var cmdResult struct {
-76
View File
@@ -221,79 +221,3 @@ func (d *Database) UpdateCommandLivreur(commandID int, livreurUsername string) e
}
return nil
}
// GetAllDeliveryPersonsStats récupère les stats de tous les livreurs
func (d *Database) GetAllDeliveryPersonsStats() ([]map[string]any, error) {
livreurs, err := d.GetAvailableDeliveryPersons()
if err != nil {
return nil, fmt.Errorf("erreur récupération livreurs: %w", err)
}
var stats []map[string]any
for _, livreur := range livreurs {
username := livreur["username"].(string)
totalDeliveries, _ := d.CountDeliveriesByStatus(username, "")
completedDeliveries, _ := d.CountDeliveriesByStatus(username, "approved")
queueSize, _ := d.GetDeliverymanQueueSize(username)
status, _ := d.GetDeliveryPersonStatus(username)
stats = append(stats, map[string]any{
"username": username,
"total_deliveries": totalDeliveries,
"completed_deliveries": completedDeliveries,
"queue_size": queueSize,
"status": status,
})
}
return stats, nil
}
// GetDeliveryPersonsByStatus récupère les livreurs par statut
func (d *Database) GetDeliveryPersonsByStatus(status string) ([]string, error) {
livreurs, err := d.GetAvailableDeliveryPersons()
if err != nil {
return nil, fmt.Errorf("erreur récupération livreurs: %w", err)
}
var filteredLivreurs []string
for _, livreur := range livreurs {
username := livreur["username"].(string)
currentStatus, _ := d.GetDeliveryPersonStatus(username)
if currentStatus == status {
filteredLivreurs = append(filteredLivreurs, username)
}
}
return filteredLivreurs, nil
}
// GetAvailableDeliveryPersonsCount compte les livreurs disponibles
func (d *Database) GetAvailableDeliveryPersonsCount() (int, error) {
availableLivreurs, err := d.GetDeliveryPersonsByStatus("available")
if err != nil {
return 0, err
}
return len(availableLivreurs), nil
}
// ClearDeliveryPersonData supprime toutes les données d'un livreur (admin uniquement)
func (d *Database) ClearDeliveryPersonData(livreurUsername string) error {
log.Printf("🗑️ [ClearDeliveryData] Nettoyage données pour: %s", livreurUsername)
keys := []string{
fmt.Sprintf("delivery:status:%s", livreurUsername),
fmt.Sprintf("delivery:location:%s", livreurUsername),
fmt.Sprintf("delivery:queue:%s", livreurUsername),
fmt.Sprintf("delivery:queue:size:%s", livreurUsername),
fmt.Sprintf("delivery:current:%s", livreurUsername),
}
for _, key := range keys {
if err := Redis.Del(RedisCtx, key).Err(); err != nil {
log.Printf("⚠️ [ClearDeliveryData] Erreur suppression clé %s: %v", key, err)
}
}
log.Printf("✅ [ClearDeliveryData] Données nettoyées pour %s", livreurUsername)
return nil
}
-113
View File
@@ -8,8 +8,6 @@ package db
import (
"fmt"
"log"
"maps"
"strconv"
)
// GetCompletedCommandsByUsername récupère toutes les commandes terminées (approved) d'un utilisateur
@@ -37,114 +35,3 @@ func (d *Database) GetCompletedCommandsByUsername(username string) ([]map[string
}
return commands, nil
}
// GetCompletedCommandsWithItems récupère les commandes terminées avec leurs items
func (d *Database) GetCompletedCommandsWithItems(username string) ([]map[string]any, error) {
commands, err := d.GetCompletedCommandsByUsername(username)
if err != nil {
return nil, err
}
var enrichedCommands []map[string]any
for _, command := range commands {
commandID, _ := strconv.Atoi(fmt.Sprintf("%v", command["id"]))
if commandID == 0 {
continue
}
items, err := d.GetCommandItems(commandID)
if err != nil {
log.Printf("⚠️ [GetCompletedWithItems] Erreur items pour cmd %d: %v", commandID, err)
items = []map[string]any{}
}
enrichedCommand := make(map[string]any)
maps.Copy(enrichedCommand, command)
enrichedCommand["items"] = items
enrichedCommand["items_count"] = len(items)
enrichedCommands = append(enrichedCommands, enrichedCommand)
}
return enrichedCommands, nil
}
// GetCommandsStatsByUsername récupère les statistiques des commandes d'un utilisateur
func (d *Database) GetCommandsStatsByUsername(username string) (map[string]any, error) {
query := `
SELECT
COUNT(*) FILTER (WHERE status = 'approved') as approved_count,
COUNT(*) FILTER (WHERE status = 'pending') as pending_count,
COUNT(*) FILTER (WHERE status = 'assigned') as assigned_count,
COUNT(*) FILTER (WHERE status = 'en_route') as en_route_count,
COUNT(*) FILTER (WHERE status = 'livre') as livre_count,
COUNT(*) FILTER (WHERE status = 'cancelled') as cancelled_count,
COUNT(*) as total_count,
COALESCE(SUM(total_prix) FILTER (WHERE status = 'approved'), 0) as total_spent
FROM commandes
WHERE username = ?
`
var result map[string]any
if err := d.GDB.Raw(query, username).Scan(&result).Error; err != nil {
log.Printf("❌ [GetCommandsStats] Erreur: %v", err)
return nil, fmt.Errorf("erreur lors de la récupération des statistiques: %w", err)
}
return result, nil
}
// GetCommandsByStatus récupère les commandes d'un utilisateur par statut
func (d *Database) GetCommandsByStatus(username, status string) ([]map[string]any, error) {
log.Printf("📋 [GetCommandsByStatus] START - username=%s, status=%s", username, status)
query := `
SELECT
id,
client_order_id AS client_order_number,
username,
status,
adresse,
total_prix::float8 as total_prix,
livreur_assign,
created_at,
updated_at
FROM commandes
WHERE username = ? AND status = ?
ORDER BY created_at DESC
`
var commands []map[string]any
if err := d.GDB.Raw(query, username, status).Scan(&commands).Error; err != nil {
return nil, fmt.Errorf("erreur lors de la récupération des commandes: %w", err)
}
return commands, nil
}
// GetRecentCompletedOrders récupère les N dernières commandes terminées d'un utilisateur
func (d *Database) GetRecentCompletedOrders(username string, limit int) ([]map[string]any, error) {
query := `
SELECT
id,
client_order_id AS client_order_number,
username,
status,
adresse,
total_prix::float8 as total_prix,
livreur_assign,
created_at,
updated_at
FROM commandes
WHERE username = ? AND status = 'approved'
ORDER BY created_at DESC
LIMIT ?
`
var commands []map[string]any
if err := d.GDB.Raw(query, username, limit).Scan(&commands).Error; err != nil {
log.Printf("❌ [GetRecentCompleted] Erreur query: %v", err)
return nil, fmt.Errorf("erreur lors de la récupération: %w", err)
}
return commands, nil
}