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/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..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} @@ -468,14 +490,16 @@ export default function BLReconciliation() { )} )} - {/* Bouton Modifier toujours disponible */} - + {/* Bouton Modifier : disponible seulement si pas encore validé */} + {!delivery.reconciled && ( + + )}
@@ -544,6 +568,9 @@ export default function BLReconciliation() { Montant Fact. + + Écart + Magasin @@ -611,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} @@ -618,15 +664,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 && ( + + )}