Files
projet_gestion_commande/backend/gestion/db/db_delivery.go
T
2026-03-27 22:23:46 +01:00

303 lines
8.9 KiB
Go

package db
import (
"database/sql"
"fmt"
"log"
"slices"
"time"
)
// GetAvailableDeliveryPersons récupère tous les livreurs disponibles
func (d *Database) GetAvailableDeliveryPersons() ([]map[string]any, error) {
query := `SELECT id, username, total, livraison
FROM users
WHERE role = 'livreur'
ORDER BY username`
rows, err := d.Query(query)
if err != nil {
return nil, fmt.Errorf("erreur lors de la récupération des livreurs: %w", err)
}
defer rows.Close()
var livreurs []map[string]any
for rows.Next() {
var id int
var username string
var total, livraison float64
err := rows.Scan(&id, &username, &total, &livraison)
if err != nil {
return nil, fmt.Errorf("erreur lors du scan du livreur: %w", err)
}
livreur := map[string]any{
"id": id,
"username": username,
"total": total,
"livraison": livraison,
}
livreurs = append(livreurs, livreur)
}
return livreurs, nil
}
// Admin appelle cette fonction pour assigner un livreur
func (d *Database) AssignDeliveryPerson(commandID int, livreurUsername string) error {
log.Printf("📦 [AssignDeliveryPerson] START - commandID=%d, livreur=%s", commandID, livreurUsername)
tx, err := d.Begin()
if err != nil {
log.Printf("❌ Erreur démarrage transaction: %v", err)
return fmt.Errorf("erreur démarrage transaction: %w", err)
}
defer tx.Rollback()
var role string
checkQuery := `SELECT role FROM users WHERE username = $1 FOR UPDATE`
err = tx.QueryRow(checkQuery, livreurUsername).Scan(&role)
if err == sql.ErrNoRows {
log.Printf("❌ Livreur '%s' non trouvé", livreurUsername)
return fmt.Errorf("livreur non trouvé")
}
if err != nil {
log.Printf("❌ Erreur vérification livreur: %v", err)
return fmt.Errorf("erreur lors de la vérification du livreur: %w", err)
}
if role != "livreur" {
log.Printf("❌ L'utilisateur '%s' n'est pas un livreur (role=%s)", livreurUsername, role)
return fmt.Errorf("l'utilisateur n'est pas un livreur")
}
var currentStatus string
var currentLivreur sql.NullString
statusQuery := `SELECT status, livreur_assign
FROM commandes
WHERE id = $1
FOR UPDATE`
err = tx.QueryRow(statusQuery, commandID).Scan(&currentStatus, &currentLivreur)
if err == sql.ErrNoRows {
log.Printf("❌ Commande %d non trouvée", commandID)
return fmt.Errorf("commande non trouvée")
}
if err != nil {
log.Printf("❌ Erreur vérification commande: %v", err)
return fmt.Errorf("erreur lors de la vérification de la commande: %w", err)
}
validStatusesForAssignment := []string{"pending", "assigned"}
isValidStatus := slices.Contains(validStatusesForAssignment, currentStatus)
if !isValidStatus {
log.Printf("❌ Statut invalide pour assignation: %s", currentStatus)
return fmt.Errorf("commande en statut '%s', impossible d'assigner un livreur", currentStatus)
}
updateQuery := `UPDATE commandes
SET livreur_assign = $1,
status = 'assigned',
updated_at = CURRENT_TIMESTAMP
WHERE id = $2
AND status IN ('pending', 'assigned')`
result, err := tx.Exec(updateQuery, livreurUsername, commandID)
if err != nil {
log.Printf("❌ Erreur UPDATE: %v", err)
return fmt.Errorf("erreur lors de l'assignation du livreur: %w", err)
}
rowsAffected, err := result.RowsAffected()
if err != nil {
log.Printf("❌ Erreur RowsAffected: %v", err)
return fmt.Errorf("erreur lors de la vérification: %w", err)
}
if rowsAffected == 0 {
log.Printf("❌ Impossible d'assigner: conditions non remplies")
return fmt.Errorf("impossible d'assigner la commande (déjà assignée ou statut changé)")
}
logQuery := `INSERT INTO command_logs (command_id, status, message, author, created_at)
VALUES ($1, $2, $3, $4, CURRENT_TIMESTAMP)`
_, err = tx.Exec(logQuery, commandID, "assigned",
fmt.Sprintf("Livraison assignée au livreur %s", livreurUsername),
"admin")
if err != nil {
log.Printf("⚠️ Erreur ajout log: %v", err)
// Non bloquant
}
err = tx.Commit()
if err != nil {
log.Printf("❌ Erreur COMMIT: %v", err)
return fmt.Errorf("erreur commit transaction: %w", err)
}
return nil
}
// GetDeliveryPersonCommands récupère les commandes assignées à un livreur
func (d *Database) GetDeliveryPersonCommands(livreurUsername string, status string) ([]map[string]any, error) {
query := `SELECT id, username, status, adresse, total_prix, livreur_assign, created_at, updated_at
FROM commandes
WHERE livreur_assign = $1`
args := []any{livreurUsername}
if status != "" {
query += " AND status = $2"
args = append(args, status)
}
query += " ORDER BY created_at DESC"
rows, err := d.Query(query, args...)
if err != nil {
return nil, fmt.Errorf("erreur lors de la récupération des commandes: %w", err)
}
defer rows.Close()
var commands []map[string]any
for rows.Next() {
var id int
var username, status, adresse string
var livreurAssign sql.NullString
var totalPrix float64
var createdAt, updatedAt time.Time
err := rows.Scan(&id, &username, &status, &adresse, &totalPrix, &livreurAssign, &createdAt, &updatedAt)
if err != nil {
return nil, fmt.Errorf("erreur lors du scan: %w", err)
}
command := map[string]any{
"id": id,
"username": username,
"status": status,
"adresse": adresse,
"total_prix": totalPrix,
"livreur_assign": livreurAssign.String,
"created_at": createdAt,
"updated_at": updatedAt,
}
commands = append(commands, command)
}
return commands, nil
}
func (d *Database) IncrementLivreurDeliveryCount(livreurUsername string) error {
query := `UPDATE users
SET livraison = livraison + 1,
total = total + 1,
updated_at = CURRENT_TIMESTAMP
WHERE username = $1 AND role = 'livreur'`
result, err := d.Exec(query, livreurUsername)
if err != nil {
return fmt.Errorf("erreur lors de l'incrémentation des livraisons: %w", err)
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return fmt.Errorf("erreur lors de la vérification: %w", err)
}
if rowsAffected == 0 {
return fmt.Errorf("livreur non trouvé")
}
return nil
}
func (d *Database) ApproveDelivery(commandID int, clientUsername string) error {
tx, err := d.Begin()
if err != nil {
log.Printf("❌ Erreur démarrage transaction: %v", err)
return fmt.Errorf("erreur démarrage transaction: %w", err)
}
defer tx.Rollback()
var commandUsername, currentStatus string
var livreurAssign sql.NullString
checkQuery := `SELECT username, status, livreur_assign
FROM commandes
WHERE id = $1
FOR UPDATE`
err = tx.QueryRow(checkQuery, commandID).Scan(&commandUsername, &currentStatus, &livreurAssign)
if err == sql.ErrNoRows {
return fmt.Errorf("commande non trouvée")
}
if err != nil {
return fmt.Errorf("erreur lors de la vérification de la commande: %w", err)
}
if commandUsername != clientUsername {
return fmt.Errorf("cette commande ne vous appartient pas")
}
if currentStatus != "livre" {
return fmt.Errorf("cette commande n'est pas encore livrée (statut actuel: %s)", currentStatus)
}
updateQuery := `UPDATE commandes
SET status = 'approved',
updated_at = CURRENT_TIMESTAMP
WHERE id = $1
AND status = 'livre'
AND username = $2`
result, err := tx.Exec(updateQuery, commandID, clientUsername)
if err != nil {
return fmt.Errorf("erreur lors de l'approbation de la livraison: %w", err)
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return fmt.Errorf("erreur lors de la vérification: %w", err)
}
if rowsAffected == 0 {
return fmt.Errorf("impossible d'approuver: statut changé ou commande introuvable")
}
if livreurAssign.Valid && livreurAssign.String != "" {
incrementQuery := `UPDATE users
SET livraison = livraison + 1,
total = total + 1,
updated_at = CURRENT_TIMESTAMP
WHERE username = $1 AND role = 'livreur'`
result, err := tx.Exec(incrementQuery, livreurAssign.String)
if err != nil {
log.Printf("⚠️ Erreur incrémentation livreur: %v", err)
} else {
rows, _ := result.RowsAffected()
if rows > 0 {
log.Printf(" ✅ Compteur livreur incrémenté: %s", livreurAssign.String)
}
}
}
logQuery := `INSERT INTO command_logs (command_id, status, message, author, created_at)
VALUES ($1, $2, $3, $4, CURRENT_TIMESTAMP)`
_, err = tx.Exec(logQuery, commandID, "approved",
fmt.Sprintf("Livraison approuvée par le client %s", clientUsername),
clientUsername)
if err != nil {
log.Printf("⚠️ Erreur ajout log: %v", err)
}
err = tx.Commit()
if err != nil {
log.Printf("❌ Erreur COMMIT: %v", err)
return fmt.Errorf("erreur commit transaction: %w", err)
}
return nil
}