diff --git a/backend/gestion/db/db_command_items.go b/backend/gestion/db/db_command_items.go
index b40004dc..bc321059 100644
--- a/backend/gestion/db/db_command_items.go
+++ b/backend/gestion/db/db_command_items.go
@@ -328,29 +328,43 @@ func (d *Database) DeleteCommandItem(commandID, itemID int) error {
var cmdStatus string
d.GDB.Raw(`SELECT status FROM commandes WHERE id = ?`, commandID).Scan(&cmdStatus)
- // Supprimer l'item
- if err := d.GDB.Exec(`DELETE FROM command_items WHERE id = ?`, itemID).Error; err != nil {
+ noRestoreStatuses := []string{"cancelled", "approved", "livre"}
+ restoreStock := result.ProductID != 0 && !slices.Contains(noRestoreStatuses, cmdStatus)
+
+ tx := d.GDB.Begin()
+ if tx.Error != nil {
+ return fmt.Errorf("erreur démarrage transaction: %w", tx.Error)
+ }
+
+ if err := tx.Exec(`DELETE FROM command_items WHERE id = ?`, itemID).Error; err != nil {
+ tx.Rollback()
log.Printf("❌ Erreur DELETE command_items: %v", err)
return fmt.Errorf("erreur suppression item: %w", err)
}
- // Recalculer le total de la commande
- if err := d.GDB.Exec(
+ if err := tx.Exec(
`UPDATE commandes SET total_prix = GREATEST(0, total_prix - ?) WHERE id = ?`,
result.Prix*result.Quantite, commandID,
).Error; err != nil {
- log.Printf("⚠️ [DeleteCommandItem] Erreur maj total commande: %v", err)
+ tx.Rollback()
+ log.Printf("❌ [DeleteCommandItem] Erreur maj total commande: %v", err)
+ return fmt.Errorf("erreur mise à jour total commande: %w", err)
}
- // Restaurer le stock si la commande n'est pas déjà terminée
- noRestoreStatuses := []string{"cancelled", "approved", "livre"}
- if result.ProductID != 0 && !slices.Contains(noRestoreStatuses, cmdStatus) {
- if err := d.GDB.Exec(`UPDATE products SET stock = stock + ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?`,
- result.Quantite, result.ProductID).Error; err != nil {
- log.Printf("⚠️ [DeleteCommandItem] Erreur restauration stock: %v", err)
- } else {
- log.Printf("✅ [DeleteCommandItem] Stock restauré: +%.3f pour produit %d", result.Quantite, result.ProductID)
+ if restoreStock {
+ if err := tx.Exec(
+ `UPDATE products SET stock = stock + ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?`,
+ result.Quantite, result.ProductID,
+ ).Error; err != nil {
+ tx.Rollback()
+ log.Printf("❌ [DeleteCommandItem] Erreur restauration stock: %v", err)
+ return fmt.Errorf("erreur restauration stock: %w", err)
}
+ log.Printf("✅ [DeleteCommandItem] Stock restauré: +%.3f pour produit %d", result.Quantite, result.ProductID)
+ }
+
+ if err := tx.Commit().Error; err != nil {
+ return fmt.Errorf("erreur commit transaction: %w", err)
}
return nil
diff --git a/backend/gestion/db/db_commands.go b/backend/gestion/db/db_commands.go
index 6952b8ed..f6911757 100644
--- a/backend/gestion/db/db_commands.go
+++ b/backend/gestion/db/db_commands.go
@@ -903,3 +903,13 @@ func (d *Database) ApproveDeliveryAtomicByStaff(commandID int, staffUsername str
return totalPoints, pointCategory, clientUsernameOut, nil
}
+
+func (d *Database) SetCommandCancelReason(commandID int, reason string) error {
+ if len(reason) > 500 {
+ reason = reason[:500]
+ }
+ return d.GDB.Exec(
+ `UPDATE commandes SET cancel_reason = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?`,
+ reason, commandID,
+ ).Error
+}
diff --git a/backend/gestion/handlers/deleviry.go b/backend/gestion/handlers/deleviry.go
index 4cf150a4..0e0091d2 100644
--- a/backend/gestion/handlers/deleviry.go
+++ b/backend/gestion/handlers/deleviry.go
@@ -263,6 +263,14 @@ func UpdateDeliveryStatus(c *gin.Context) {
return
}
+ if req.Status == "cancelled" {
+ cancelMsg := req.Notes
+ if cancelMsg == "" {
+ cancelMsg = "Annulé par le livreur"
+ }
+ database.SetCommandCancelReason(commandID, fmt.Sprintf("[Livreur: %s] %s", usernameStr, cancelMsg))
+ }
+
// ✅ SI PASSAGE EN "EN_ROUTE" → CALCULER ET DÉFINIR L'ETA
var etaMinutes int
var etaMessage string
diff --git a/frontend-admin/src/screens/admin/OrdersScreen.tsx b/frontend-admin/src/screens/admin/OrdersScreen.tsx
index d0b660d1..7ca2b0a3 100644
--- a/frontend-admin/src/screens/admin/OrdersScreen.tsx
+++ b/frontend-admin/src/screens/admin/OrdersScreen.tsx
@@ -443,6 +443,11 @@ export default function OrdersScreen() {
color: colors.textSecondary,
fontSize: fontSize.xs,
},
+ livreurCancelBadge: {
+ flexDirection: "row",
+ alignItems: "center",
+ marginBottom: spacing.xs,
+ },
proposedAddressBox: {
backgroundColor: colors.bgPrimary,
borderRadius: borderRadius.sm,
@@ -662,8 +667,18 @@ export default function OrdersScreen() {
{/* Raison annulation */}
{isCancelled && !!item.cancel_reason && (
+ {item.cancel_reason.startsWith("[Livreur:") && (
+
+
+
+ {" "}Annulé par le livreur
+
+
+ )}
- Raison : {item.cancel_reason}
+ {item.cancel_reason.startsWith("[Livreur:")
+ ? item.cancel_reason.replace(/^\[Livreur: [^\]]+\] /, "")
+ : item.cancel_reason}
)}
diff --git a/mobile/app.json b/mobile/app.json
index 32300143..7ed673a5 100644
--- a/mobile/app.json
+++ b/mobile/app.json
@@ -22,6 +22,7 @@
"backgroundColor": "#000000"
},
"edgeToEdgeEnabled": true,
+ "softwareKeyboardLayoutMode": "pan",
"predictiveBackGestureEnabled": false,
"package": "com.uberstup.clientpanel",
"versionCode": 1,
diff --git a/mobile/src/components/ui/Modal.tsx b/mobile/src/components/ui/Modal.tsx
index f0abc142..a2ee957b 100644
--- a/mobile/src/components/ui/Modal.tsx
+++ b/mobile/src/components/ui/Modal.tsx
@@ -65,7 +65,7 @@ export default function Modal({
>
{
return (
-
+
{/* Résumé commande */}
diff --git a/mobile/src/screens/client/ProfileScreen.tsx b/mobile/src/screens/client/ProfileScreen.tsx
index 49c84997..f20fb1e4 100644
--- a/mobile/src/screens/client/ProfileScreen.tsx
+++ b/mobile/src/screens/client/ProfileScreen.tsx
@@ -371,7 +371,7 @@ export default function ProfileScreen() {
}
return (
-
+
{/* Header */}