package db import ( "fmt" "gestion/models" "gorm.io/gorm" ) // 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 { Price float64 `gorm:"column:price"` } err := d.GDB.Raw(` SELECT price FROM product_prices pp INNER JOIN products p ON pp.product_id = p.id WHERE LOWER(p.name) = LOWER(?) AND LOWER(p.category) = LOWER(?) AND pp.quantity <= ? ORDER BY pp.quantity DESC LIMIT 1`, name, category, quantity).Scan(&result).Error if err != nil || result.Price == 0 { return 0, fmt.Errorf("prix produit introuvable pour %f %s: %w", quantity, name, err) } return result.Price, 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 err := d.GDB.Raw(` SELECT b.id, b.username, b.product_id, b.quantity, b.price, b.created_at, p.name as product_name, p.category, p.description FROM baskets b INNER JOIN products p ON b.product_id = p.id WHERE b.username = ? ORDER BY b.created_at DESC`, username).Scan(&baskets).Error if err != nil { return nil, fmt.Errorf("erreur lors de la récupération du panier: %w", err) } return baskets, nil } func (d *Database) DecrementAndAddToBasket(username string, productID int, quantity float64) (*models.Panier, error) { var basket models.Panier err := d.GDB.Transaction(func(tx *gorm.DB) error { result := tx.Exec(`UPDATE products SET stock = stock - ? WHERE id = ? AND stock >= ?`, quantity, productID, quantity) if result.Error != nil { return fmt.Errorf("erreur stock: %w", result.Error) } if result.RowsAffected == 0 { return fmt.Errorf("stock insuffisant") } var priceResult struct { Price float64 `gorm:"column:price"` } if err := tx.Raw(` SELECT price FROM product_prices WHERE product_id = ? AND quantity <= ? AND active_price = true ORDER BY quantity DESC LIMIT 1`, productID, quantity).Scan(&priceResult).Error; err != nil || priceResult.Price == 0 { return fmt.Errorf("prix introuvable pour product_id=%d qty=%.3f", productID, quantity) } var existing struct { ID int `gorm:"column:id"` Quantity float64 `gorm:"column:quantity"` Price float64 `gorm:"column:price"` } tx.Raw(`SELECT id, quantity, price FROM baskets WHERE username = ? AND product_id = ?`, username, productID).Scan(&existing) if existing.ID != 0 { return tx.Raw(` UPDATE baskets SET quantity = ?, price = ?, created_at = CURRENT_TIMESTAMP WHERE id = ? RETURNING id, username, product_id, quantity, price, created_at`, existing.Quantity+quantity, existing.Price+priceResult.Price, existing.ID).Scan(&basket).Error } return tx.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, priceResult.Price).Scan(&basket).Error }) if err != nil { return nil, err } return &basket, nil } // DeleteProductFromBasket supprime un produit spécifique du panier et restitue le stock. func (d *Database) DeleteProductFromBasket(basketID int) error { 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 = ?`, basketID).Scan(&item).Error; err != nil { return fmt.Errorf("produit non trouvé dans le panier") } if item.ProductID == 0 { return fmt.Errorf("produit non trouvé dans le panier") } if err := tx.Exec(`UPDATE products SET stock = stock + ? WHERE id = ?`, item.Quantity, item.ProductID).Error; err != nil { return fmt.Errorf("erreur restitution stock: %w", err) } result := tx.Exec(`DELETE FROM baskets WHERE id = ?`, basketID) if result.Error != nil { return fmt.Errorf("erreur lors de la suppression du produit: %w", result.Error) } if result.RowsAffected == 0 { return fmt.Errorf("produit non trouvé dans le panier") } return nil }) } // ClearBasket vide complètement le panier d'un utilisateur et restitue les stocks. func (d *Database) ClearBasket(username string) error { return d.GDB.Transaction(func(tx *gorm.DB) error { if err := tx.Exec(` UPDATE products p SET stock = stock + b.quantity FROM baskets b WHERE b.username = ? AND b.product_id = p.id`, username).Error; err != nil { return fmt.Errorf("erreur restitution stock: %w", err) } if err := tx.Exec(`DELETE FROM baskets WHERE username = ?`, username).Error; err != nil { return fmt.Errorf("erreur lors du vidage du panier: %w", err) } return nil }) } // ClearBasketOnCheckout vide le panier après commande validée SANS restituer le stock. func (d *Database) ClearBasketOnCheckout(username string) error { return d.GDB.Exec(`DELETE FROM baskets WHERE username = ?`, username).Error } 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 if err != nil { return "", err } if username == "" { return "", fmt.Errorf("article non trouvé") } return username, nil } func (d *Database) GetBasketItems(username string) ([]map[string]any, error) { var items []map[string]any if err := d.GDB.Raw(`SELECT product_id, quantity::float8 as quantity, price::float8 as price FROM baskets WHERE username = ?`, username).Scan(&items).Error; err != nil { return nil, err } return items, nil }