163 lines
4.6 KiB
Go
163 lines
4.6 KiB
Go
// ============================================
|
|
// db/cancel_sanctions_db.go
|
|
// GESTION DES SANCTIONS ÉVOLUTIVES
|
|
// ============================================
|
|
|
|
package db
|
|
|
|
import (
|
|
"fmt"
|
|
"gestion/models"
|
|
"log"
|
|
"sort"
|
|
)
|
|
|
|
// GetClientCancellationsCount récupère le nombre d'annulations tardives d'un client
|
|
func (d *Database) GetClientCancellationsCount(username string) (int, error) {
|
|
var count int
|
|
query := `SELECT COALESCE(cancellations_count, 0) FROM clients WHERE username = $1`
|
|
|
|
err := d.QueryRow(query, username).Scan(&count)
|
|
if err != nil {
|
|
log.Printf("❌ [GetCancellationsCount] Erreur: %v", err)
|
|
return 0, fmt.Errorf("erreur récupération compteur: %w", err)
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
// IncrementClientCancellationsCount incrémente le compteur d'annulations
|
|
func (d *Database) IncrementClientCancellationsCount(username string) error {
|
|
query := `UPDATE clients
|
|
SET cancellations_count = COALESCE(cancellations_count, 0) + 1,
|
|
updated_at = CURRENT_TIMESTAMP
|
|
WHERE username = $1`
|
|
|
|
result, err := d.Exec(query, username)
|
|
if err != nil {
|
|
log.Printf("❌ [IncrementCancellations] Erreur: %v", err)
|
|
return fmt.Errorf("erreur incrémentation: %w", err)
|
|
}
|
|
|
|
rowsAffected, err := result.RowsAffected()
|
|
if err != nil {
|
|
return fmt.Errorf("erreur vérification: %w", err)
|
|
}
|
|
if rowsAffected == 0 {
|
|
return fmt.Errorf("client non trouvé")
|
|
}
|
|
|
|
cacheKey := fmt.Sprintf("client:%s", username)
|
|
Redis.Del(RedisCtx, cacheKey)
|
|
|
|
return nil
|
|
}
|
|
|
|
// penaltyForCount retourne le montant du palier applicable pour un nombre d'annulations donné
|
|
func penaltyForCount(count int, tiers []models.PenaltyTier) int {
|
|
if len(tiers) == 0 {
|
|
return 0
|
|
}
|
|
sorted := make([]models.PenaltyTier, len(tiers))
|
|
copy(sorted, tiers)
|
|
sort.Slice(sorted, func(i, j int) bool {
|
|
return sorted[i].MinCancel > sorted[j].MinCancel
|
|
})
|
|
for _, t := range sorted {
|
|
if count >= t.MinCancel {
|
|
return t.Amount
|
|
}
|
|
}
|
|
return sorted[len(sorted)-1].Amount
|
|
}
|
|
|
|
// CalculateCancellationPenalty calcule la pénalité selon l'historique et le barème configuré
|
|
func (d *Database) CalculateCancellationPenalty(username string) (int, error) {
|
|
count, err := d.GetClientCancellationsCount(username)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
settings, err := d.GetSettings()
|
|
if err != nil {
|
|
log.Printf("⚠️ [CalculatePenalty] Impossible de charger les settings, barème par défaut: %v", err)
|
|
settings = DefaultSettings()
|
|
}
|
|
|
|
penalty := penaltyForCount(count, settings.PenaltyTiers)
|
|
|
|
log.Printf("💰 [CalculatePenalty] Client %s - Annulations: %d → Pénalité: %d points",
|
|
username, count, penalty)
|
|
|
|
return penalty, nil
|
|
}
|
|
|
|
// ApplyCancellationPenalty applique une pénalité et incrémente le compteur d'annulations
|
|
func (d *Database) ApplyCancellationPenalty(username string) (int, error) {
|
|
penalty, err := d.CalculateCancellationPenalty(username)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
log.Printf("⚠️ [ApplyCancellationPenalty] Client %s - Pénalité calculée: %d points", username, penalty)
|
|
|
|
if err := d.IncrementClientCancellationsCount(username); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
query := `UPDATE clients
|
|
SET amende = $1,
|
|
updated_at = CURRENT_TIMESTAMP
|
|
WHERE username = $2`
|
|
|
|
result, err := d.Exec(query, float64(penalty), username)
|
|
if err != nil {
|
|
log.Printf("❌ [ApplyCancellationPenalty] Erreur UPDATE: %v", err)
|
|
return 0, fmt.Errorf("erreur application pénalité: %w", err)
|
|
}
|
|
|
|
rowsAffected, err := result.RowsAffected()
|
|
if err != nil {
|
|
return 0, fmt.Errorf("erreur vérification: %w", err)
|
|
}
|
|
if rowsAffected == 0 {
|
|
return 0, fmt.Errorf("client non trouvé")
|
|
}
|
|
|
|
log.Printf("✅ [ApplyCancellationPenalty] Amende %d appliquée à %s", penalty, username)
|
|
|
|
cacheKey := fmt.Sprintf("client:%s", username)
|
|
Redis.Del(RedisCtx, cacheKey)
|
|
|
|
return penalty, nil
|
|
}
|
|
|
|
// GetClientCancellationHistory récupère l'historique d'annulations d'un client
|
|
func (d *Database) GetClientCancellationHistory(username string) (map[string]any, error) {
|
|
nextPenalty, err := d.CalculateCancellationPenalty(username)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
count, err := d.GetClientCancellationsCount(username)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
settings, _ := d.GetSettings()
|
|
|
|
client, err := d.GetClientByUsername(username)
|
|
var currentAmende float64
|
|
if err == nil {
|
|
currentAmende = client.Amende
|
|
}
|
|
|
|
return map[string]any{
|
|
"cancellations_count": count,
|
|
"current_amende": currentAmende,
|
|
"next_penalty": nextPenalty,
|
|
"penalty_tiers": settings.PenaltyTiers,
|
|
"warning": "Une amende sera appliquée lors de la prochaine annulation tardive",
|
|
}, nil
|
|
}
|