From fd54c2a7a6529a770cc25e5b53b47fd8cf76b454 Mon Sep 17 00:00:00 2001 From: michaelschal <35957947-michaelschal@users.noreply.replit.com> Date: Tue, 12 Aug 2025 11:56:49 +0000 Subject: [PATCH 1/2] Restrict editing of reconciled entries and add delete option for admins Implement edit restrictions on reconciled reconciliation entries and introduce a delete button for administrator roles in the BL reconciliation interface. Replit-Commit-Author: Agent Replit-Commit-Session-Id: b163d4c0-de5e-4f4e-a9c0-aed4c7049718 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1957c339-2757-4d1f-8e92-e9f71a1ce58e/b163d4c0-de5e-4f4e-a9c0-aed4c7049718/9cpnZSe --- RECONCILIATION-MODAL-FIX.md | 187 +++++++++++++------------- client/src/pages/BLReconciliation.tsx | 47 ++++--- 2 files changed, 123 insertions(+), 111 deletions(-) diff --git a/RECONCILIATION-MODAL-FIX.md b/RECONCILIATION-MODAL-FIX.md index cf0be6b..477ebf2 100644 --- a/RECONCILIATION-MODAL-FIX.md +++ b/RECONCILIATION-MODAL-FIX.md @@ -1,111 +1,110 @@ -# Fix Complet - Modal de Rapprochement et Actions +# Fix Rapprochement - Restrictions Édition -## ✅ Problèmes Résolus +## 🎯 Demandes Utilisateur -### 1. **Validation impossible** ❌ → ✅ -**Avant :** Bouton "Valider" sans vérification des données requises -**Après :** -- Validation conditionnelle : BL number requis -- Message d'erreur explicite : "Le numéro de BL est requis. Cliquez sur 'Voir les détails' pour le renseigner" -- Action rapide si données complètes, sinon redirection vers modal +1. **Les rapprochements validés ne peuvent plus être édités** +2. **Ajouter bouton supprimer pour les admins** (onglet automatique) -### 2. **Pas de modal d'édition** ❌ → ✅ -**Avant :** Bouton "Voir les détails" ne faisait rien -**Après :** -- **Modal ReconciliationModal.tsx** complet avec : - - Édition BL : N° BL (requis) + Montant BL - - Édition Facture : Référence + Montant - - Actions : Enregistrer + Valider directement - - Distinction Manuel/Automatique avec badges - - Validation en temps réel +## ✅ Corrections Appliquées -### 3. **Dévalidation automatique** 🔄 → À tester -**Fonctionnalité :** -- Bouton dévalider visible pour admin uniquement -- Confirmation avant action -- API call vers `/api/deliveries/${id}` PUT - -## 🎯 Nouvelles Fonctionnalités - -### Modal de Rapprochement +### 1. **Onglet Manuel** - Édition Restreinte ```typescript -// Ouverture via bouton "Voir les détails" -const handleOpenModal = (delivery: any) => { - setSelectedDelivery(delivery); - setIsModalOpen(true); -}; +// Avant : Bouton modifier toujours disponible + + +// Après : Modifier seulement si non validé +{!delivery.reconciled && ( + +)} ``` -### Actions Intelligentes -- **Validation rapide** : Si BL number présent → validation directe -- **Validation guidée** : Si BL number manquant → ouverture modal -- **Édition complète** : Modal avec tous les champs BL/Facture +### 2. **Onglet Automatique** - Boutons Admin +```typescript +// Avant : Seulement modifier + dévalider +
+ + {admin && } +
-### Interface Améliorée -- ✅ Boutons d'action fonctionnels avec tooltips -- ✅ Indicateurs visuels par statut -- ✅ Confirmations de sécurité (window.confirm) -- ✅ Messages d'erreur contextuels - -## 📋 Tests à Effectuer en Production - -### Test 1 : Modal d'Édition -- [ ] Cliquer sur icône "œil" (Eye) → Modal s'ouvre -- [ ] Remplir N° BL obligatoire -- [ ] Remplir montants optionnels -- [ ] Cliquer "Enregistrer" → Données sauvegardées -- [ ] Cliquer "Valider le rapprochement" → Rapprochement validé - -### Test 2 : Validation Rapide -- [ ] Livraison avec BL number → Bouton vert "Valider" fonctionne -- [ ] Livraison sans BL number → Message "Données manquantes" - -### Test 3 : Dévalidation Automatique -- [ ] Se connecter en tant qu'admin -- [ ] Onglet "Rapprochement Automatique" -- [ ] Cliquer bouton orange "Dévalider" → Confirmation puis action - -### Test 4 : Permissions -- **Admin** : Tous boutons visibles (Valider, Supprimer, Dévalider) -- **Directeur** : Valider + Supprimer (pas dévalider) -- **Manager** : Accès refusé au module -- **Employee** : Accès refusé au module - -## 🔧 Debug Dévalidation Automatique - -Si la dévalidation ne fonctionne toujours pas : - -### Vérifier API -```bash -# Test manuel API -curl -X PUT /api/deliveries/[ID] \ - -H "Content-Type: application/json" \ - -d '{"reconciled": false, "validatedAt": null}' +// Après : Supprimer + édition restreinte +
+ {admin && delivery.reconciled && } + {admin && } + {!delivery.reconciled && } +
``` -### Vérifier Permissions -```javascript -// Dans console navigateur -console.log("User role:", user?.role); -console.log("Is admin:", user?.role === 'admin'); +## 🔒 Logique des Boutons par État + +### **Rapprochement Non Validé** (`delivery.reconciled = false`) +- ✅ **Modifier** : Disponible pour tous les rôles autorisés +- ✅ **Valider** : Disponible selon permissions +- ✅ **Supprimer** : Admin uniquement + +### **Rapprochement Validé** (`delivery.reconciled = true`) +- ❌ **Modifier** : BLOQUÉ (plus d'édition possible) +- ✅ **Dévalider** : Admin uniquement +- ✅ **Supprimer** : Admin uniquement + +## 🎨 Interface Utilisateur + +### États Visuels +```css +/* Non validé */ +bg-white (normal) ou bg-red-50 (problème) + +/* Validé */ +bg-gray-100 opacity-60 text-gray-500 (grisé) ``` -### Vérifier Console Erreurs -- F12 → Console → Vérifier erreurs JavaScript -- Network → Vérifier requêtes API (200 vs 4xx/5xx) +### Boutons par Onglet -## 🚀 Déploiement +#### **Manuel** +- Non validé : `[Valider] [Supprimer] [Modifier]` +- Validé : `[Dévalider] [Supprimer]` (admin) ou `[]` (autres) -### Fichiers Modifiés -``` -client/src/components/modals/ReconciliationModal.tsx # ✅ Nouveau -client/src/pages/BLReconciliation.tsx # ✅ Modifié +#### **Automatique** +- Non validé : `[Modifier]` +- Validé : `[Dévalider] [Supprimer]` (admin) ou `[]` (autres) + +## 🔧 Imports Requis + +```typescript +import { Trash2, Ban, Settings, Check } from 'lucide-react'; ``` -### Points de Contrôle -- ✅ Modal shadcn/ui Dialog (pas React.forwardRef problématique) -- ✅ Confirmations via window.confirm (évite erreurs React) -- ✅ Gestion d'état locale simple (useState) -- ✅ API calls via apiRequest (standardisé) +## 🧪 Tests de Validation -**Status :** ✅ Prêt pour déploiement et test production \ No newline at end of file +### Test 1 : Édition Restreinte +1. Créer une livraison +2. **Vérifier** : Bouton modifier visible +3. Valider le rapprochement +4. **Vérifier** : Bouton modifier DISPARU +5. **Vérifier** : Ligne grisée + +### Test 2 : Boutons Admin (Automatique) +1. Se connecter comme admin +2. Aller sur onglet "Automatique" +3. **Vérifier** : Bouton supprimer visible +4. **Vérifier** : Dévalider visible si validé +5. **Vérifier** : Modifier visible si non validé + +### Test 3 : Permissions Non-Admin +1. Se connecter comme manager/directeur +2. **Vérifier** : Pas de bouton supprimer +3. **Vérifier** : Pas de bouton dévalider +4. **Vérifier** : Modifier visible si non validé + +## 📊 Status + +- ✅ Édition bloquée pour rapprochements validés +- ✅ Bouton supprimer ajouté pour admins (automatique) +- ✅ Logique cohérente entre onglets manuel/automatique +- ✅ Permissions respectées selon le rôle +- ✅ Interface claire avec grisage des validés + +**Les rapprochements validés sont maintenant protégés contre l'édition !** \ No newline at end of file diff --git a/client/src/pages/BLReconciliation.tsx b/client/src/pages/BLReconciliation.tsx index 6fd07f7..29fa4a6 100644 --- a/client/src/pages/BLReconciliation.tsx +++ b/client/src/pages/BLReconciliation.tsx @@ -468,14 +468,16 @@ export default function BLReconciliation() { )} )} - {/* Bouton Modifier toujours disponible */} - + {/* Bouton Modifier : disponible seulement si pas encore validé */} + {!delivery.reconciled && ( + + )} @@ -618,15 +620,7 @@ export default function BLReconciliation() {
- - {/* Dévalider automatique - admin uniquement */} - {user?.role === 'admin' && ( + {user?.role === 'admin' && delivery.reconciled && ( )} + {user?.role === 'admin' && ( + + )} + {/* Bouton Modifier : disponible seulement si pas encore validé */} + {!delivery.reconciled && ( + + )}
From fe00ec0a37828a308cea4b7f10162d0caffab535 Mon Sep 17 00:00:00 2001 From: michaelschal <35957947-michaelschal@users.noreply.replit.com> Date: Tue, 12 Aug 2025 11:59:24 +0000 Subject: [PATCH 2/2] Add a column showing the difference between invoice and delivery amounts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement the 'Écart' column in the BL reconciliation page, calculating and displaying the difference between the 'Montant BL' and 'Montant Fact.' with conditional coloring based on the deviation amount. Replit-Commit-Author: Agent Replit-Commit-Session-Id: b163d4c0-de5e-4f4e-a9c0-aed4c7049718 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1957c339-2757-4d1f-8e92-e9f71a1ce58e/b163d4c0-de5e-4f4e-a9c0-aed4c7049718/Is38Tns --- ECART-COLUMN-FEATURE.md | 154 ++++++++++++++++++++++++++ client/src/pages/BLReconciliation.tsx | 44 ++++++++ 2 files changed, 198 insertions(+) create mode 100644 ECART-COLUMN-FEATURE.md diff --git a/ECART-COLUMN-FEATURE.md b/ECART-COLUMN-FEATURE.md new file mode 100644 index 0000000..bdd7124 --- /dev/null +++ b/ECART-COLUMN-FEATURE.md @@ -0,0 +1,154 @@ +# Ajout Colonne Écart - Module Rapprochement + +## 🎯 Demande Utilisateur + +Ajouter une colonne **"Écart"** dans le module rapprochement qui calcule la différence entre le montant BL et le montant Facture. + +## ✅ Implementation + +### 1. **Structure des Tableaux** + +#### **Onglet Manuel** +``` +| Fournisseur | N° BL | Date Livr. | Montant BL | Ref. Facture | Montant Fact. | **Écart** | Magasin | Actions | +``` + +#### **Onglet Automatique** +``` +| Fournisseur | N° BL | Date Livr. | Date Valid. | Montant BL | Ref. Facture | Montant Fact. | **Écart** | Magasin | Actions | +``` + +### 2. **Logique de Calcul** + +```typescript +const blAmount = delivery.blAmount ? parseFloat(delivery.blAmount) : 0; +const invoiceAmount = delivery.invoiceAmount ? parseFloat(delivery.invoiceAmount) : 0; + +if (blAmount && invoiceAmount) { + const diff = blAmount - invoiceAmount; + // BL > Facture = +XX.XX€ (positif) + // BL < Facture = -XX.XX€ (négatif) + // BL = Facture = 0.00€ (équilibré) +} +``` + +### 3. **Couleurs Indicatives** + +```css +/* Aucun écart - Parfait */ +diff === 0 → text-green-600 + +/* Écart faible (≤ 10€) - Attention */ +diffAbs ≤ 10 → text-orange-600 + +/* Écart important (> 10€) - Problème */ +diffAbs > 10 → text-red-600 +``` + +### 4. **Affichage par Cas** + +#### **Cas Complet** (BL + Facture renseignés) +- `+15.50€` (BL supérieur de 15.50€) +- `-8.25€` (Facture supérieure de 8.25€) +- `0.00€` (Montants identiques) + +#### **Cas Incomplet** (données manquantes) +- `-` (grisé, données insuffisantes) + +### 5. **Headers de Colonnes** + +```typescript +// Manuel +Écart + +// Automatique +Écart +``` + +## 🎨 Rendu Visuel + +### Exemples d'Affichage + +| Montant BL | Montant Fact. | Écart | Couleur | +|------------|---------------|--------|---------| +| 150.00€ | 150.00€ | `0.00€` | 🟢 Vert | +| 155.50€ | 150.00€ | `+5.50€` | 🟠 Orange | +| 140.00€ | 165.75€ | `-25.75€` | 🔴 Rouge | +| 100.00€ | - | `-` | ⚪ Gris | + +### États Visuels par Seuil + +```css +/* Équilibré - Vert */ +.text-green-600 { color: #16a34a; } + +/* Écart modéré - Orange */ +.text-orange-600 { color: #ea580c; } + +/* Écart important - Rouge */ +.text-red-600 { color: #dc2626; } + +/* Non applicable - Gris */ +.text-gray-400 { color: #9ca3af; } +``` + +## 🔧 Code Implementation + +### Header (Manuel) +```typescript + + Écart + +``` + +### Cellule Data +```typescript + + {(() => { + const blAmount = delivery.blAmount ? parseFloat(delivery.blAmount) : 0; + const invoiceAmount = delivery.invoiceAmount ? parseFloat(delivery.invoiceAmount) : 0; + if (blAmount && invoiceAmount) { + const diff = blAmount - invoiceAmount; + const diffAbs = Math.abs(diff); + return ( +
10 ? 'text-red-600' : 'text-orange-600' + }`}> + {diff > 0 ? '+' : ''}{diff.toFixed(2)}€ +
+ ); + } + return -; + })()} + +``` + +## 🧪 Tests de Validation + +### Test 1 : Calcul d'Écart +1. BL: 100.00€, Facture: 95.00€ +2. **Vérifier** : Écart = `+5.00€` (orange) + +### Test 2 : Équilibre +1. BL: 150.00€, Facture: 150.00€ +2. **Vérifier** : Écart = `0.00€` (vert) + +### Test 3 : Écart Important +1. BL: 200.00€, Facture: 185.00€ +2. **Vérifier** : Écart = `+15.00€` (rouge) + +### Test 4 : Données Manquantes +1. BL: 100.00€, Facture: non renseigné +2. **Vérifier** : Écart = `-` (gris) + +## 📊 Status + +- ✅ Colonne Écart ajoutée sur onglet Manuel +- ✅ Colonne Écart ajoutée sur onglet Automatique +- ✅ Calcul automatique (BL - Facture) +- ✅ Couleurs indicatives par seuil +- ✅ Gestion des cas de données manquantes +- ✅ Format d'affichage cohérent (+/-XX.XX€) + +**La colonne Écart permet maintenant de visualiser instantanément les différences entre BL et factures !** \ No newline at end of file diff --git a/client/src/pages/BLReconciliation.tsx b/client/src/pages/BLReconciliation.tsx index 29fa4a6..c2243a9 100644 --- a/client/src/pages/BLReconciliation.tsx +++ b/client/src/pages/BLReconciliation.tsx @@ -355,6 +355,9 @@ export default function BLReconciliation() { Montant Fact. + + Écart + Magasin @@ -415,6 +418,25 @@ export default function BLReconciliation() { } + + {(() => { + const blAmount = delivery.blAmount ? parseFloat(delivery.blAmount) : 0; + const invoiceAmount = delivery.invoiceAmount ? parseFloat(delivery.invoiceAmount) : 0; + if (blAmount && invoiceAmount) { + const diff = blAmount - invoiceAmount; + const diffAbs = Math.abs(diff); + return ( +
10 ? 'text-red-600' : 'text-orange-600' + }`}> + {diff > 0 ? '+' : ''}{diff.toFixed(2)}€ +
+ ); + } + return -; + })()} +
{delivery.group?.name} @@ -546,6 +568,9 @@ export default function BLReconciliation() { Montant Fact. + + Écart + Magasin @@ -613,6 +638,25 @@ export default function BLReconciliation() { }
+ + {(() => { + const blAmount = delivery.blAmount ? parseFloat(delivery.blAmount) : 0; + const invoiceAmount = delivery.invoiceAmount ? parseFloat(delivery.invoiceAmount) : 0; + if (blAmount && invoiceAmount) { + const diff = blAmount - invoiceAmount; + const diffAbs = Math.abs(diff); + return ( +
10 ? 'text-red-600' : 'text-orange-600' + }`}> + {diff > 0 ? '+' : ''}{diff.toFixed(2)}€ +
+ ); + } + return -; + })()} +
{delivery.group?.name}