Files
projet_gestion_commande/backend/gestion/db/db_referral.go
T
2026-03-12 21:59:18 +01:00

101 lines
2.8 KiB
Go

package db
import (
"database/sql"
"fmt"
)
// GetClientReferralBalance retourne le solde parrainage d'un client.
func (d *Database) GetClientReferralBalance(username string) (float64, error) {
var balance float64
err := d.QueryRow(
`SELECT referral_balance FROM clients WHERE username = $1`,
username,
).Scan(&balance)
if err == sql.ErrNoRows {
return 0, fmt.Errorf("client non trouvé")
}
return balance, err
}
// CreditClientReferral ajoute un montant au solde parrainage d'un client.
func (d *Database) CreditClientReferral(username string, amount float64) error {
if amount <= 0 {
return fmt.Errorf("le montant doit être positif")
}
res, err := d.Exec(
`UPDATE clients SET referral_balance = referral_balance + $1 WHERE username = $2`,
amount, username,
)
if err != nil {
return err
}
n, _ := res.RowsAffected()
if n == 0 {
return fmt.Errorf("client non trouvé")
}
return nil
}
// DebitReferralBalance déduit atomiquement le solde parrainage avant la création de commande.
// Gère sa propre transaction avec FOR UPDATE pour éviter le double-spend concurrent.
// Retourne une erreur si le solde est insuffisant.
func (d *Database) DebitReferralBalance(username string, amount float64) error {
if amount <= 0 {
return nil
}
tx, err := d.Begin()
if err != nil {
return fmt.Errorf("erreur transaction: %w", err)
}
var balance float64
if err := tx.QueryRow(
`SELECT referral_balance FROM clients WHERE username = $1 FOR UPDATE`,
username,
).Scan(&balance); err != nil {
tx.Rollback()
return fmt.Errorf("client non trouvé")
}
if balance < amount {
tx.Rollback()
return fmt.Errorf("solde parrainage insuffisant (disponible: %.2f€)", balance)
}
if _, err := tx.Exec(
`UPDATE clients SET referral_balance = referral_balance - $1 WHERE username = $2`,
amount, username,
); err != nil {
tx.Rollback()
return err
}
return tx.Commit()
}
// RestoreReferralBalance restaure le solde parrainage si la commande échoue après le débit.
func (d *Database) RestoreReferralBalance(username string, amount float64) error {
return d.CreditClientReferral(username, amount)
}
// UseClientReferralBalance déduit un montant du solde parrainage dans une transaction.
// Retourne une erreur si le solde est insuffisant.
func (d *Database) UseClientReferralBalance(tx *sql.Tx, username string, amount float64) error {
if amount <= 0 {
return nil
}
var balance float64
err := tx.QueryRow(
`SELECT referral_balance FROM clients WHERE username = $1 FOR UPDATE`,
username,
).Scan(&balance)
if err != nil {
return fmt.Errorf("client non trouvé")
}
if balance < amount {
return fmt.Errorf("solde parrainage insuffisant (disponible: %.2f€)", balance)
}
_, err = tx.Exec(
`UPDATE clients SET referral_balance = referral_balance - $1 WHERE username = $2`,
amount, username,
)
return err
}