chore: update id order
This commit is contained in:
+195
-318
@@ -1,117 +1,100 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"gestion/models"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"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) {
|
||||
// Rechercher le produit par son nom et catégorie (case-insensitive)
|
||||
var productID int
|
||||
productQuery := `SELECT id FROM products WHERE LOWER(name) = LOWER($1) AND LOWER(category) = LOWER($2)`
|
||||
err := d.QueryRow(productQuery, nameProduct, category).Scan(&productID)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, fmt.Errorf("produit '%s' non trouvé dans la catégorie '%s'", nameProduct, category)
|
||||
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
|
||||
|
||||
// Récupérer le prix correct selon la quantité
|
||||
price, err := d.GetProductPrice(nameProduct, category, quantity)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("erreur récupération prix: %w", err)
|
||||
}
|
||||
|
||||
// Vérifier si le produit existe déjà dans le panier
|
||||
var existingID int
|
||||
var existingQuantity, existingPrice float64
|
||||
checkQuery := `SELECT id, quantity, price FROM baskets WHERE username = $1 AND product_id = $2`
|
||||
err = d.QueryRow(checkQuery, username, productID).Scan(&existingID, &existingQuantity, &existingPrice)
|
||||
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)
|
||||
|
||||
if err == nil {
|
||||
// Produit déjà dans le panier : cumuler quantité et prix total de la ligne
|
||||
newQuantity := existingQuantity + quantity
|
||||
newPrice := existingPrice + price
|
||||
updateQuery := `UPDATE baskets SET quantity = $1, price = $2, created_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $3 RETURNING id, username, product_id, quantity, price, created_at`
|
||||
|
||||
var basket models.Panier
|
||||
err = d.QueryRow(updateQuery, newQuantity, newPrice, existingID).Scan(
|
||||
&basket.ID,
|
||||
&basket.Username,
|
||||
&basket.ProductID,
|
||||
&basket.Quantity,
|
||||
&basket.Price,
|
||||
&basket.CreatedAt,
|
||||
)
|
||||
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)
|
||||
}
|
||||
return &basket, nil
|
||||
} 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)
|
||||
}
|
||||
}
|
||||
|
||||
// Produit non présent : l'ajouter
|
||||
insertQuery := `INSERT INTO baskets (username, product_id, quantity, price, created_at)
|
||||
VALUES ($1, $2, $3, $4, CURRENT_TIMESTAMP)
|
||||
RETURNING id, username, product_id, quantity, price, created_at`
|
||||
|
||||
var basket models.Panier
|
||||
err = d.QueryRow(insertQuery, username, productID, quantity, price).Scan(
|
||||
&basket.ID,
|
||||
&basket.Username,
|
||||
&basket.ProductID,
|
||||
&basket.Quantity,
|
||||
&basket.Price,
|
||||
&basket.CreatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("erreur lors de l'ajout au panier: %w", err)
|
||||
}
|
||||
|
||||
return &basket, nil
|
||||
}
|
||||
|
||||
// GetProductPriceByID récupère le prix d'un produit par son ID et quantité (NUMERIC exact)
|
||||
// GetProductPriceByID récupère le prix d'un produit par son ID et quantité
|
||||
func (d *Database) GetProductPriceByID(productID int, quantity float64) (float64, error) {
|
||||
var price float64
|
||||
|
||||
// Comparaison NUMERIC précise : évite les problèmes float64 vs NUMERIC(10,3)
|
||||
exactQuery := `
|
||||
SELECT price FROM product_prices
|
||||
WHERE product_id = $1 AND quantity = ROUND($2::NUMERIC, 3)
|
||||
LIMIT 1
|
||||
`
|
||||
err := d.QueryRow(exactQuery, productID, quantity).Scan(&price)
|
||||
if err == nil {
|
||||
return price, nil
|
||||
var result struct {
|
||||
Price float64 `gorm:"column:price"`
|
||||
}
|
||||
|
||||
// Fallback : palier inférieur le plus proche
|
||||
tierQuery := `
|
||||
err := d.GDB.Raw(`
|
||||
SELECT price FROM product_prices
|
||||
WHERE product_id = $1 AND quantity <= ROUND($2::NUMERIC, 3)
|
||||
ORDER BY quantity DESC LIMIT 1
|
||||
`
|
||||
err = d.QueryRow(tierQuery, productID, quantity).Scan(&price)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("aucun prix trouvé pour product_id=%d qty=%.3f: %w", productID, quantity, err)
|
||||
WHERE product_id = ? AND quantity = ROUND(?::NUMERIC, 3)
|
||||
LIMIT 1`, productID, quantity).Scan(&result).Error
|
||||
if err == nil && result.Price > 0 {
|
||||
return result.Price, nil
|
||||
}
|
||||
return price, nil
|
||||
|
||||
err = d.GDB.Raw(`
|
||||
SELECT price FROM product_prices
|
||||
WHERE product_id = ? AND quantity <= ROUND(?::NUMERIC, 3)
|
||||
ORDER BY quantity DESC LIMIT 1`, productID, quantity).Scan(&result).Error
|
||||
if err != nil || result.Price == 0 {
|
||||
return 0, fmt.Errorf("aucun prix trouvé pour product_id=%d qty=%.3f", productID, quantity)
|
||||
}
|
||||
return result.Price, nil
|
||||
}
|
||||
|
||||
// GetProductStockByID récupère le stock d'un produit par son ID
|
||||
func (d *Database) GetProductStockByID(productID int) (float64, error) {
|
||||
var stock float64
|
||||
err := d.QueryRow(`SELECT stock FROM products WHERE id = $1`, productID).Scan(&stock)
|
||||
var result struct {
|
||||
Stock float64 `gorm:"column:stock"`
|
||||
}
|
||||
err := d.GDB.Raw(`SELECT stock FROM products WHERE id = ?`, productID).Scan(&result).Error
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("produit %d non trouvé: %w", productID, err)
|
||||
}
|
||||
return stock, nil
|
||||
return result.Stock, nil
|
||||
}
|
||||
|
||||
// AddProductInBasketByID ajoute un produit au panier en utilisant son ID directement
|
||||
@@ -121,81 +104,76 @@ func (d *Database) AddProductInBasketByID(username string, productID int, quanti
|
||||
return nil, fmt.Errorf("erreur récupération prix: %w", err)
|
||||
}
|
||||
|
||||
var existingID int
|
||||
var existingQuantity, existingPrice float64
|
||||
checkQuery := `SELECT id, quantity, price FROM baskets WHERE username = $1 AND product_id = $2`
|
||||
err = d.QueryRow(checkQuery, username, productID).Scan(&existingID, &existingQuantity, &existingPrice)
|
||||
|
||||
if err == nil {
|
||||
newQuantity := existingQuantity + quantity
|
||||
newPrice := existingPrice + price
|
||||
updateQuery := `UPDATE baskets SET quantity = $1, price = $2, created_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $3 RETURNING id, username, product_id, quantity, price, created_at`
|
||||
var basket models.Panier
|
||||
err = d.QueryRow(updateQuery, newQuantity, newPrice, existingID).Scan(
|
||||
&basket.ID, &basket.Username, &basket.ProductID, &basket.Quantity, &basket.Price, &basket.CreatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("erreur lors de la mise à jour du panier: %w", err)
|
||||
}
|
||||
return &basket, nil
|
||||
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)
|
||||
|
||||
insertQuery := `INSERT INTO baskets (username, product_id, quantity, price, created_at)
|
||||
VALUES ($1, $2, $3, $4, CURRENT_TIMESTAMP)
|
||||
RETURNING id, username, product_id, quantity, price, created_at`
|
||||
var basket models.Panier
|
||||
err = d.QueryRow(insertQuery, username, productID, quantity, price).Scan(
|
||||
&basket.ID, &basket.Username, &basket.ProductID, &basket.Quantity, &basket.Price, &basket.CreatedAt,
|
||||
)
|
||||
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
|
||||
} 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 nil, fmt.Errorf("erreur 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 price float64
|
||||
|
||||
query := `
|
||||
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($1)
|
||||
AND LOWER(p.category) = LOWER($2)
|
||||
AND pp.quantity <= $3
|
||||
WHERE LOWER(p.name) = LOWER(?)
|
||||
AND LOWER(p.category) = LOWER(?)
|
||||
AND pp.quantity <= ?
|
||||
ORDER BY pp.quantity DESC
|
||||
LIMIT 1
|
||||
`
|
||||
|
||||
err := d.QueryRow(query, name, category, quantity).Scan(&price)
|
||||
if err != nil {
|
||||
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 price, nil
|
||||
return result.Price, nil
|
||||
}
|
||||
|
||||
func (d *Database) GetProductStock(name, category string) (float64, error) {
|
||||
var stock float64
|
||||
query := `SELECT stock FROM products WHERE LOWER(name) = LOWER($1) AND LOWER(category) = LOWER($2)`
|
||||
err := d.QueryRow(query, name, category).Scan(&stock)
|
||||
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 stock, nil
|
||||
return result.Stock, nil
|
||||
}
|
||||
|
||||
func (d *Database) DecrementProductStock(name, category string, quantity float64) error {
|
||||
query := `UPDATE products SET stock = stock - $1 WHERE LOWER(name) = LOWER($2) AND LOWER(category) = LOWER($3) AND stock >= $1`
|
||||
result, err := d.Exec(query, quantity, name, category)
|
||||
if err != nil {
|
||||
return fmt.Errorf("erreur mise à jour stock: %w", err)
|
||||
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)
|
||||
}
|
||||
|
||||
rows, _ := result.RowsAffected()
|
||||
if rows == 0 {
|
||||
if result.RowsAffected == 0 {
|
||||
return fmt.Errorf("stock insuffisant pour le produit")
|
||||
}
|
||||
return nil
|
||||
@@ -203,164 +181,105 @@ func (d *Database) DecrementProductStock(name, category string, quantity float64
|
||||
|
||||
// GetAllProductsInBasket récupère tous les produits du panier d'un utilisateur
|
||||
func (d *Database) GetAllProductsInBasket(username string) ([]models.Panier, error) {
|
||||
query := `SELECT b.id, b.username, b.product_id, b.quantity, b.price, b.created_at,
|
||||
p.name, p.category, p.description
|
||||
FROM baskets b
|
||||
INNER JOIN products p ON b.product_id = p.id
|
||||
WHERE b.username = $1
|
||||
ORDER BY b.created_at DESC`
|
||||
|
||||
rows, err := d.Query(query, username)
|
||||
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)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var baskets []models.Panier
|
||||
for rows.Next() {
|
||||
var basket models.Panier
|
||||
|
||||
err := rows.Scan(
|
||||
&basket.ID,
|
||||
&basket.Username,
|
||||
&basket.ProductID, // ✔ FIX MAJEUR
|
||||
&basket.Quantity,
|
||||
&basket.Price,
|
||||
&basket.CreatedAt,
|
||||
&basket.ProductName,
|
||||
&basket.Category,
|
||||
&basket.Description,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("erreur lors du scan du panier: %w", err)
|
||||
}
|
||||
|
||||
baskets = append(baskets, basket)
|
||||
}
|
||||
|
||||
if err = rows.Err(); err != nil {
|
||||
return nil, fmt.Errorf("erreur lors de l'itération des résultats: %w", err)
|
||||
}
|
||||
|
||||
return baskets, nil
|
||||
}
|
||||
|
||||
// DecrementProductStockByID décrémente le stock d'un produit par son ID de manière sécurisée (évite race condition)
|
||||
// DecrementProductStockByID décrémente le stock d'un produit par son ID
|
||||
func (d *Database) DecrementProductStockByID(productID int, quantity float64) error {
|
||||
query := `
|
||||
UPDATE products
|
||||
SET stock = stock - $1
|
||||
WHERE id = $2
|
||||
AND stock >= $1
|
||||
`
|
||||
result, err := d.Exec(query, quantity, productID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("erreur lors de la mise à jour du stock: %w", err)
|
||||
result := d.GDB.Exec(`
|
||||
UPDATE products SET stock = stock - ?
|
||||
WHERE id = ? AND stock >= ?`, quantity, productID, quantity)
|
||||
if result.Error != nil {
|
||||
return fmt.Errorf("erreur lors de la mise à jour du stock: %w", result.Error)
|
||||
}
|
||||
|
||||
rowsAffected, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return fmt.Errorf("erreur lors de la vérification du stock affecté: %w", err)
|
||||
}
|
||||
|
||||
if rowsAffected == 0 {
|
||||
if result.RowsAffected == 0 {
|
||||
return fmt.Errorf("stock insuffisant pour le produit %d", productID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteProductFromBasket supprime un produit spécifique du panier et restitue le stock.
|
||||
func (d *Database) DeleteProductFromBasket(basketID int) error {
|
||||
tx, err := d.Begin()
|
||||
if err != nil {
|
||||
return fmt.Errorf("erreur transaction: %w", err)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
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")
|
||||
}
|
||||
|
||||
var productID int
|
||||
var quantity float64
|
||||
err = tx.QueryRow(
|
||||
`SELECT product_id, quantity FROM baskets WHERE id = $1`,
|
||||
basketID,
|
||||
).Scan(&productID, &quantity)
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
_, err = tx.Exec(
|
||||
`UPDATE products SET stock = stock + $1 WHERE id = $2`,
|
||||
quantity, productID,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("erreur restitution stock: %w", err)
|
||||
}
|
||||
|
||||
result, err := tx.Exec(`DELETE FROM baskets WHERE id = $1`, basketID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("erreur lors de la suppression du produit: %w", err)
|
||||
}
|
||||
rows, _ := result.RowsAffected()
|
||||
if rows == 0 {
|
||||
return fmt.Errorf("produit non trouvé dans le panier")
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
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 {
|
||||
tx, err := d.Begin()
|
||||
if err != nil {
|
||||
return fmt.Errorf("erreur transaction: %w", err)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
_, err = tx.Exec(`
|
||||
UPDATE products p
|
||||
SET stock = stock + b.quantity
|
||||
FROM baskets b
|
||||
WHERE b.username = $1 AND b.product_id = p.id
|
||||
`, username)
|
||||
if err != nil {
|
||||
return fmt.Errorf("erreur restitution stock: %w", err)
|
||||
}
|
||||
|
||||
_, err = tx.Exec(`DELETE FROM baskets WHERE username = $1`, username)
|
||||
if err != nil {
|
||||
return fmt.Errorf("erreur lors du vidage du panier: %w", err)
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
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
|
||||
})
|
||||
}
|
||||
|
||||
// GetBasketTotal calcule le montant total du panier d'un utilisateur
|
||||
// price dans baskets = prix total de la ligne (cumul des ajouts)
|
||||
func (d *Database) GetBasketTotal(username string) (float64, error) {
|
||||
query := `SELECT COALESCE(SUM(price), 0) as total
|
||||
FROM baskets
|
||||
WHERE username = $1`
|
||||
|
||||
var total float64
|
||||
err := d.QueryRow(query, username).Scan(&total)
|
||||
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 total, nil
|
||||
return result.Total, nil
|
||||
}
|
||||
|
||||
// GetBasketItemCount compte le nombre d'items dans le panier
|
||||
func (d *Database) GetBasketItemCount(username string) (int, error) {
|
||||
query := `SELECT COUNT(*) FROM baskets WHERE username = $1`
|
||||
|
||||
var count int
|
||||
err := d.QueryRow(query, username).Scan(&count)
|
||||
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 count, nil
|
||||
return result.Count, nil
|
||||
}
|
||||
|
||||
// UpdateBasketItemQuantity met à jour la quantité d'un item du panier
|
||||
@@ -368,70 +287,43 @@ func (d *Database) UpdateBasketItemQuantity(basketID int, quantity float64) erro
|
||||
if quantity <= 0 {
|
||||
return fmt.Errorf("la quantité doit être supérieure à 0")
|
||||
}
|
||||
|
||||
query := `UPDATE baskets SET quantity = $1, created_at = CURRENT_TIMESTAMP WHERE id = $2`
|
||||
result, err := d.Exec(query, quantity, basketID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("erreur lors de la mise à jour de la quantité: %w", err)
|
||||
result := d.GDB.Exec(`UPDATE baskets SET quantity = ?, created_at = CURRENT_TIMESTAMP WHERE id = ?`,
|
||||
quantity, basketID)
|
||||
if result.Error != nil {
|
||||
return fmt.Errorf("erreur lors de la mise à jour de la quantité: %w", result.Error)
|
||||
}
|
||||
|
||||
rowsAffected, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return fmt.Errorf("erreur lors de la vérification des lignes affectées: %w", err)
|
||||
}
|
||||
|
||||
if rowsAffected == 0 {
|
||||
if result.RowsAffected == 0 {
|
||||
return fmt.Errorf("produit non trouvé dans le panier")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExtendBasketReservations prolonge les réservations
|
||||
func (d *Database) ExtendBasketReservations(username string) error {
|
||||
query := `SELECT product_id, quantity FROM baskets WHERE username = $1`
|
||||
rows, err := d.Query(query, username)
|
||||
if err != nil {
|
||||
var items []struct {
|
||||
ProductID int `gorm:"column:product_id"`
|
||||
Quantity float64 `gorm:"column:quantity"`
|
||||
}
|
||||
if err := d.GDB.Raw(`SELECT product_id, quantity FROM baskets WHERE username = ?`, username).Scan(&items).Error; err != nil {
|
||||
return fmt.Errorf("erreur récupération panier: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
type Item struct {
|
||||
ProductID int
|
||||
Quantity int
|
||||
}
|
||||
|
||||
var items []Item
|
||||
for rows.Next() {
|
||||
var item Item
|
||||
if err := rows.Scan(&item.ProductID, &item.Quantity); err != nil {
|
||||
return fmt.Errorf("erreur scan: %w", err)
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
// Vérifier stock disponible pour chaque item
|
||||
for _, item := range items {
|
||||
var stock int
|
||||
err := d.QueryRow(`SELECT stock FROM products WHERE id = $1`, item.ProductID).Scan(&stock)
|
||||
if err != nil {
|
||||
var stockResult struct {
|
||||
Stock float64 `gorm:"column:stock"`
|
||||
}
|
||||
if err := d.GDB.Raw(`SELECT stock FROM products WHERE id = ?`, item.ProductID).Scan(&stockResult).Error; err != nil {
|
||||
return fmt.Errorf("produit %d non trouvé: %w", item.ProductID, err)
|
||||
}
|
||||
|
||||
if stock < item.Quantity {
|
||||
return fmt.Errorf("stock insuffisant pour le produit %d (demandé: %d, disponible: %d)",
|
||||
item.ProductID, item.Quantity, stock)
|
||||
if stockResult.Stock < item.Quantity {
|
||||
return fmt.Errorf("stock insuffisant pour le produit %d (demandé: %g, disponible: %g)",
|
||||
item.ProductID, item.Quantity, stockResult.Stock)
|
||||
}
|
||||
}
|
||||
|
||||
// Prolonger les réservations de 15 minutes
|
||||
newReservation := time.Now().Add(15 * time.Minute)
|
||||
updateQuery := `UPDATE baskets
|
||||
SET reserved_until = $1
|
||||
WHERE username = $2`
|
||||
|
||||
_, err = d.Exec(updateQuery, newReservation, username)
|
||||
if err != nil {
|
||||
if err := d.GDB.Exec(`UPDATE baskets SET reserved_until = ? WHERE username = ?`,
|
||||
newReservation, username).Error; err != nil {
|
||||
return fmt.Errorf("erreur prolongation: %w", err)
|
||||
}
|
||||
|
||||
@@ -442,39 +334,24 @@ func (d *Database) ExtendBasketReservations(username string) error {
|
||||
|
||||
// CheckBasketReservations vérifie si les réservations sont expirées
|
||||
func (d *Database) CheckBasketReservations(username string) (bool, error) {
|
||||
query := `SELECT COUNT(*) FROM baskets
|
||||
WHERE username = $1
|
||||
AND (reserved_until IS NULL OR reserved_until < CURRENT_TIMESTAMP)`
|
||||
|
||||
var expiredCount int
|
||||
err := d.QueryRow(query, username).Scan(&expiredCount)
|
||||
var result struct {
|
||||
Count int `gorm:"column:count"`
|
||||
}
|
||||
err := d.GDB.Raw(`
|
||||
SELECT COUNT(*) as count FROM baskets
|
||||
WHERE username = ? AND (reserved_until IS NULL OR reserved_until < CURRENT_TIMESTAMP)`,
|
||||
username).Scan(&result).Error
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return expiredCount > 0, nil
|
||||
return result.Count > 0, nil
|
||||
}
|
||||
|
||||
func (d *Database) GetBasketItems(username string) ([]map[string]interface{}, error) {
|
||||
query := `SELECT product_id, quantity, price FROM baskets WHERE username = $1`
|
||||
rows, err := d.Query(query, username)
|
||||
if err != 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
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var items []map[string]interface{}
|
||||
for rows.Next() {
|
||||
var productID int
|
||||
var quantity, price float64
|
||||
if err := rows.Scan(&productID, &quantity, &price); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, map[string]interface{}{
|
||||
"product_id": productID,
|
||||
"quantity": quantity,
|
||||
"price": price,
|
||||
})
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user