chore: build
Backend - Build & Lint / build (push) Failing after 31m35s

This commit is contained in:
2026-07-06 21:22:30 +02:00
parent 75a241dadb
commit 5cd8ada828
10 changed files with 664 additions and 177 deletions
+40
View File
@@ -325,3 +325,43 @@ func (d *Database) RestoreCommandStock(commandID int) error {
WHERE ci.command_id = ? AND ci.product_id = p.id`, commandID).Error
})
}
// CancelDeliveryByLivreurAtomic annule une commande côté livreur et restaure le stock
// de manière atomique (verrou FOR UPDATE + transition conditionnée à l'ancien statut).
// Idempotent : si la commande est déjà annulée, ne touche pas au stock et renvoie
// alreadyCancelled=true — évite un remboursement en double en cas de double appel
// (double-tap, retry réseau, ou commande déjà annulée par un autre canal).
func (d *Database) CancelDeliveryByLivreurAtomic(commandID int) (alreadyCancelled bool, prevStatus string, err error) {
err = d.GDB.Transaction(func(tx *gorm.DB) error {
if e := tx.Raw(`SELECT status FROM commandes WHERE id = ? FOR UPDATE`, commandID).Scan(&prevStatus).Error; e != nil {
return e
}
if prevStatus == "" {
return fmt.Errorf("commande non trouvée")
}
if prevStatus == "cancelled" {
alreadyCancelled = true
return nil
}
result := tx.Exec(`
UPDATE commandes SET status = 'cancelled', updated_at = CURRENT_TIMESTAMP
WHERE id = ? AND status = ?`, commandID, prevStatus)
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
return fmt.Errorf("commande déjà modifiée par une autre requête")
}
if e := tx.Exec(`
UPDATE products p
SET stock = stock + ci.quantite, updated_at = CURRENT_TIMESTAMP
FROM command_items ci
WHERE ci.command_id = ? AND ci.product_id = p.id`, commandID).Error; e != nil {
return fmt.Errorf("erreur remboursement stock: %w", e)
}
return nil
})
return
}