fix
This commit is contained in:
@@ -328,29 +328,43 @@ func (d *Database) DeleteCommandItem(commandID, itemID int) error {
|
|||||||
var cmdStatus string
|
var cmdStatus string
|
||||||
d.GDB.Raw(`SELECT status FROM commandes WHERE id = ?`, commandID).Scan(&cmdStatus)
|
d.GDB.Raw(`SELECT status FROM commandes WHERE id = ?`, commandID).Scan(&cmdStatus)
|
||||||
|
|
||||||
// Supprimer l'item
|
noRestoreStatuses := []string{"cancelled", "approved", "livre"}
|
||||||
if err := d.GDB.Exec(`DELETE FROM command_items WHERE id = ?`, itemID).Error; err != nil {
|
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)
|
log.Printf("❌ Erreur DELETE command_items: %v", err)
|
||||||
return fmt.Errorf("erreur suppression item: %w", err)
|
return fmt.Errorf("erreur suppression item: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recalculer le total de la commande
|
if err := tx.Exec(
|
||||||
if err := d.GDB.Exec(
|
|
||||||
`UPDATE commandes SET total_prix = GREATEST(0, total_prix - ?) WHERE id = ?`,
|
`UPDATE commandes SET total_prix = GREATEST(0, total_prix - ?) WHERE id = ?`,
|
||||||
result.Prix*result.Quantite, commandID,
|
result.Prix*result.Quantite, commandID,
|
||||||
).Error; err != nil {
|
).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
|
if restoreStock {
|
||||||
noRestoreStatuses := []string{"cancelled", "approved", "livre"}
|
if err := tx.Exec(
|
||||||
if result.ProductID != 0 && !slices.Contains(noRestoreStatuses, cmdStatus) {
|
`UPDATE products SET stock = stock + ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?`,
|
||||||
if err := d.GDB.Exec(`UPDATE products SET stock = stock + ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?`,
|
result.Quantite, result.ProductID,
|
||||||
result.Quantite, result.ProductID).Error; err != nil {
|
).Error; err != nil {
|
||||||
log.Printf("⚠️ [DeleteCommandItem] Erreur restauration stock: %v", err)
|
tx.Rollback()
|
||||||
} else {
|
log.Printf("❌ [DeleteCommandItem] Erreur restauration stock: %v", err)
|
||||||
log.Printf("✅ [DeleteCommandItem] Stock restauré: +%.3f pour produit %d", result.Quantite, result.ProductID)
|
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
|
return nil
|
||||||
|
|||||||
@@ -903,3 +903,13 @@ func (d *Database) ApproveDeliveryAtomicByStaff(commandID int, staffUsername str
|
|||||||
|
|
||||||
return totalPoints, pointCategory, clientUsernameOut, nil
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -263,6 +263,14 @@ func UpdateDeliveryStatus(c *gin.Context) {
|
|||||||
return
|
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
|
// ✅ SI PASSAGE EN "EN_ROUTE" → CALCULER ET DÉFINIR L'ETA
|
||||||
var etaMinutes int
|
var etaMinutes int
|
||||||
var etaMessage string
|
var etaMessage string
|
||||||
|
|||||||
@@ -443,6 +443,11 @@ export default function OrdersScreen() {
|
|||||||
color: colors.textSecondary,
|
color: colors.textSecondary,
|
||||||
fontSize: fontSize.xs,
|
fontSize: fontSize.xs,
|
||||||
},
|
},
|
||||||
|
livreurCancelBadge: {
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
marginBottom: spacing.xs,
|
||||||
|
},
|
||||||
proposedAddressBox: {
|
proposedAddressBox: {
|
||||||
backgroundColor: colors.bgPrimary,
|
backgroundColor: colors.bgPrimary,
|
||||||
borderRadius: borderRadius.sm,
|
borderRadius: borderRadius.sm,
|
||||||
@@ -662,8 +667,18 @@ export default function OrdersScreen() {
|
|||||||
{/* Raison annulation */}
|
{/* Raison annulation */}
|
||||||
{isCancelled && !!item.cancel_reason && (
|
{isCancelled && !!item.cancel_reason && (
|
||||||
<View style={styles.cancelReasonBox}>
|
<View style={styles.cancelReasonBox}>
|
||||||
|
{item.cancel_reason.startsWith("[Livreur:") && (
|
||||||
|
<View style={styles.livreurCancelBadge}>
|
||||||
|
<Ionicons name="bicycle-outline" size={12} color={colors.danger} />
|
||||||
|
<Text style={[styles.cancelReasonText, { color: colors.danger, fontWeight: "600" }]}>
|
||||||
|
{" "}Annulé par le livreur
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
<Text style={styles.cancelReasonText}>
|
<Text style={styles.cancelReasonText}>
|
||||||
Raison : {item.cancel_reason}
|
{item.cancel_reason.startsWith("[Livreur:")
|
||||||
|
? item.cancel_reason.replace(/^\[Livreur: [^\]]+\] /, "")
|
||||||
|
: item.cancel_reason}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
"backgroundColor": "#000000"
|
"backgroundColor": "#000000"
|
||||||
},
|
},
|
||||||
"edgeToEdgeEnabled": true,
|
"edgeToEdgeEnabled": true,
|
||||||
|
"softwareKeyboardLayoutMode": "pan",
|
||||||
"predictiveBackGestureEnabled": false,
|
"predictiveBackGestureEnabled": false,
|
||||||
"package": "com.uberstup.clientpanel",
|
"package": "com.uberstup.clientpanel",
|
||||||
"versionCode": 1,
|
"versionCode": 1,
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ export default function Modal({
|
|||||||
>
|
>
|
||||||
<KeyboardAvoidingView
|
<KeyboardAvoidingView
|
||||||
style={{ flex: 1 }}
|
style={{ flex: 1 }}
|
||||||
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
behavior="padding"
|
||||||
>
|
>
|
||||||
<View style={styles.overlay}>
|
<View style={styles.overlay}>
|
||||||
<Animated.View
|
<Animated.View
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export default function ChangePasswordScreen() {
|
|||||||
return (
|
return (
|
||||||
<KeyboardAvoidingView
|
<KeyboardAvoidingView
|
||||||
style={[styles.container, { backgroundColor: colors.bgPrimary }]}
|
style={[styles.container, { backgroundColor: colors.bgPrimary }]}
|
||||||
behavior="height"
|
behavior="padding"
|
||||||
>
|
>
|
||||||
<ScrollView
|
<ScrollView
|
||||||
contentContainerStyle={styles.scrollContent}
|
contentContainerStyle={styles.scrollContent}
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ const LoginClient = () => {
|
|||||||
return (
|
return (
|
||||||
<KeyboardAvoidingView
|
<KeyboardAvoidingView
|
||||||
style={[styles.container, { backgroundColor: colors.bgSecondary }]}
|
style={[styles.container, { backgroundColor: colors.bgSecondary }]}
|
||||||
behavior="height"
|
behavior="padding"
|
||||||
>
|
>
|
||||||
<ScrollView
|
<ScrollView
|
||||||
contentContainerStyle={styles.scrollContent}
|
contentContainerStyle={styles.scrollContent}
|
||||||
|
|||||||
@@ -657,9 +657,12 @@ export default function CheckoutScreen() {
|
|||||||
return (
|
return (
|
||||||
<KeyboardAvoidingView
|
<KeyboardAvoidingView
|
||||||
style={styles.container}
|
style={styles.container}
|
||||||
behavior={Platform.OS === "ios" ? "padding" : undefined}
|
behavior="padding"
|
||||||
>
|
>
|
||||||
<ScrollView contentContainerStyle={styles.content}>
|
<ScrollView
|
||||||
|
contentContainerStyle={styles.content}
|
||||||
|
keyboardShouldPersistTaps="handled"
|
||||||
|
>
|
||||||
{/* Résumé commande */}
|
{/* Résumé commande */}
|
||||||
<View style={styles.section}>
|
<View style={styles.section}>
|
||||||
<Text style={styles.sectionTitle}>
|
<Text style={styles.sectionTitle}>
|
||||||
|
|||||||
@@ -371,7 +371,7 @@ export default function ProfileScreen() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<KeyboardAvoidingView style={styles.container} behavior={Platform.OS === "ios" ? "padding" : undefined}>
|
<KeyboardAvoidingView style={styles.container} behavior="padding">
|
||||||
<ScrollView contentContainerStyle={styles.content} keyboardShouldPersistTaps="handled">
|
<ScrollView contentContainerStyle={styles.content} keyboardShouldPersistTaps="handled">
|
||||||
|
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
|
|||||||
Reference in New Issue
Block a user