From 78d41738a515dfa7713d19315ce01bde094acf7c Mon Sep 17 00:00:00 2001 From: michaelschal <35957947-michaelschal@users.noreply.replit.com> Date: Tue, 23 Sep 2025 13:36:37 +0000 Subject: [PATCH] Improve task reconciliation by separating validated and unvalidated deliveries Refactors the BLReconciliation page to distinguish between manually reconciled and validated deliveries, updates the "Verify All Invoices" logic to only process unvalidated items, and simplifies the filtering to rely solely on the search term. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 1e4433b5-47ab-464c-b663-fea2e53367dd Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1957c339-2757-4d1f-8e92-e9f71a1ce58e/1e4433b5-47ab-464c-b663-fea2e53367dd/awJgdDR --- .replit | 4 + client/src/pages/BLReconciliation.tsx | 384 ++++++++++++-------------- 2 files changed, 187 insertions(+), 201 deletions(-) diff --git a/.replit b/.replit index fff634c..1c5ab1f 100644 --- a/.replit +++ b/.replit @@ -19,6 +19,10 @@ externalPort = 80 localPort = 33873 externalPort = 3003 +[[ports]] +localPort = 38213 +externalPort = 5000 + [[ports]] localPort = 38343 externalPort = 3000 diff --git a/client/src/pages/BLReconciliation.tsx b/client/src/pages/BLReconciliation.tsx index ae36b7e..6e07047 100644 --- a/client/src/pages/BLReconciliation.tsx +++ b/client/src/pages/BLReconciliation.tsx @@ -52,7 +52,6 @@ export default function BLReconciliation() { const [searchTerm, setSearchTerm] = useState(""); const [selectedDelivery, setSelectedDelivery] = useState(null); const [isModalOpen, setIsModalOpen] = useState(false); - const [filterStatus, setFilterStatus] = useState<"all" | "validated" | "not_validated">("all"); // État pour le modal d'envoi de facture const [showInvoiceModal, setShowInvoiceModal] = useState(false); @@ -190,7 +189,7 @@ export default function BLReconciliation() { // Fonction pour vérifier toutes les factures avec un bouton const handleVerifyAllInvoices = () => { - const deliveriesToVerify = manualReconciliationDeliveries.filter(delivery => + const deliveriesToVerify = manualNotValidatedDeliveries.filter((delivery: any) => (delivery.invoiceReference?.trim() || delivery.blNumber?.trim()) && (delivery.group?.nocodbTableName || delivery.group?.nocodbConfigId || delivery.group?.webhookUrl) ); @@ -203,7 +202,7 @@ export default function BLReconciliation() { return; } - deliveriesToVerify.forEach((delivery, index) => { + deliveriesToVerify.forEach((delivery: any, index: number) => { // Délai échelonné pour éviter la surcharge setTimeout(() => { handleVerifyInvoice(delivery, true); // Force refresh pour toutes @@ -310,15 +309,16 @@ export default function BLReconciliation() { }); }, [deliveriesWithBL, suppliers, verificationResults, verifyingDeliveries]); - // Séparer les livraisons par mode de rapprochement - const manualReconciliationDeliveries = deliveriesWithBL.filter((delivery: any) => { + // Séparer les livraisons : non validées manuelles et toutes les validées + const manualNotValidatedDeliveries = deliveriesWithBL.filter((delivery: any) => { const supplier = suppliers.find(s => s.id === delivery.supplierId); - return supplier?.automaticReconciliation !== true; + const isManual = supplier?.automaticReconciliation !== true; + const isNotValidated = delivery.reconciled !== true && delivery.reconciled !== 1; + return isManual && isNotValidated; }); - const automaticReconciliationDeliveries = deliveriesWithBL.filter((delivery: any) => { - const supplier = suppliers.find(s => s.id === delivery.supplierId); - return supplier?.automaticReconciliation === true; + const allValidatedDeliveries = deliveriesWithBL.filter((delivery: any) => { + return delivery.reconciled === true || delivery.reconciled === 1; }); // Fonctions de gestion @@ -626,45 +626,23 @@ export default function BLReconciliation() { } }; - // Filtrage des livraisons par recherche et statut de validation + // Filtrage des livraisons par recherche uniquement const filterDeliveries = (deliveries: any[]) => { + if (!searchTerm) return deliveries; + + const searchLower = searchTerm.toLowerCase(); return deliveries.filter((delivery: any) => { - // Conversion sûre de reconciled - gestion de tous les cas possibles - const isReconciled = - delivery.reconciled === true || - delivery.reconciled === 1 || - delivery.reconciled === "t" || - delivery.reconciled === "true" || - (typeof delivery.reconciled === 'string' && delivery.reconciled.toLowerCase() === 'true'); - - // Vérifier aussi si une facture a été trouvée ET validée automatiquement - // (certaines livraisons ont une coche verte mais reconciled = false) - const hasVerifiedInvoice = verificationResults[delivery.id]?.exists === true; - const isValidated = isReconciled || (hasVerifiedInvoice && verificationResults[delivery.id]?.reconciled === true); - - // Filtre par statut validé - if (filterStatus === "validated") { - // Afficher seulement les livraisons vraiment validées (reconciled = true) - return isReconciled; - } - - if (filterStatus === "not_validated") { - // Afficher seulement les livraisons non validées (reconciled = false) - return !isReconciled; - } - - // Filtre par recherche - const searchLower = searchTerm.toLowerCase(); return ( delivery.supplier?.name?.toLowerCase().includes(searchLower) || delivery.blNumber?.toLowerCase().includes(searchLower) || - delivery.invoiceReference?.toLowerCase().includes(searchLower) + delivery.invoiceReference?.toLowerCase().includes(searchLower) || + delivery.group?.name?.toLowerCase().includes(searchLower) ); }); }; - const filteredManualDeliveries = filterDeliveries(manualReconciliationDeliveries); - const filteredAutomaticDeliveries = filterDeliveries(automaticReconciliationDeliveries); + const filteredManualDeliveries = filterDeliveries(manualNotValidatedDeliveries); + const filteredValidatedDeliveries = filterDeliveries(allValidatedDeliveries); // Pagination pour les rapprochements manuels const { @@ -677,16 +655,16 @@ export default function BLReconciliation() { totalItems: manualTotalItems } = usePagination(filteredManualDeliveries, 20); - // Pagination pour les rapprochements automatiques + // Pagination pour les livraisons validées const { - currentPage: autoCurrentPage, - setCurrentPage: setAutoCurrentPage, - itemsPerPage: autoItemsPerPage, - setItemsPerPage: setAutoItemsPerPage, - totalPages: autoTotalPages, - paginatedData: paginatedAutoDeliveries, - totalItems: autoTotalItems - } = usePagination(filteredAutomaticDeliveries, 20); + currentPage: validatedCurrentPage, + setCurrentPage: setValidatedCurrentPage, + itemsPerPage: validatedItemsPerPage, + setItemsPerPage: setValidatedItemsPerPage, + totalPages: validatedTotalPages, + paginatedData: paginatedValidatedDeliveries, + totalItems: validatedTotalItems + } = usePagination(filteredValidatedDeliveries, 20); const canModify = user?.role === 'directeur' || user?.role === 'admin'; @@ -710,10 +688,10 @@ export default function BLReconciliation() {
- {manualReconciliationDeliveries.length} manuels + {manualNotValidatedDeliveries.length} à traiter - - {automaticReconciliationDeliveries.length} automatiques + + {allValidatedDeliveries.length} validées
- {/* Filters */} + {/* Barre de recherche */}
-
-
-
- - setSearchTerm(e.target.value)} - className="pl-10 border border-gray-300 shadow-sm w-full" - /> -
-
-
- -
+
+ + setSearchTerm(e.target.value)} + className="pl-10 border border-gray-300 shadow-sm w-full" + />
@@ -1098,15 +1047,15 @@ export default function BLReconciliation() { )} - + {/* Message d'information */} -
+
- +
-

Mode rapprochement automatique

-

- Les livraisons de fournisseurs en mode automatique sont validées automatiquement lorsqu'elles ont le statut "delivered" et un numéro de BL. +

Livraisons validées

+

+ Cette section regroupe toutes les livraisons validées (manuellement ou automatiquement). {(permissions.canEdit('reconciliation') || permissions.canValidate('reconciliation')) ? ( " Vous pouvez dévalider ces rapprochements si nécessaire." ) : ( @@ -1117,14 +1066,14 @@ export default function BLReconciliation() {

- {filteredAutomaticDeliveries.length === 0 ? ( + {filteredValidatedDeliveries.length === 0 ? (
- +

- Aucun rapprochement automatique trouvé + Aucune livraison validée trouvée

- Les livraisons de fournisseurs en mode automatique apparaîtront ici. + Les livraisons validées apparaîtront ici.

) : ( @@ -1133,22 +1082,21 @@ export default function BLReconciliation() { {/* Pagination du haut */}
- +
+ + + - {paginatedAutoDeliveries.map((delivery: any) => ( - - - + + + + + + + + + - - - - - - ))} + + + + ); + })}
Fournisseur - AUTO N° BL @@ -1157,7 +1105,16 @@ export default function BLReconciliation() { Date Livr. - Date Valid. + Ref. Facture + + Montant BL + + Montant Fact. + + Écart Magasin @@ -1168,91 +1125,116 @@ export default function BLReconciliation() {
-
- {delivery.supplier?.name} -
-
-
- {delivery.blNumber || ( - { + const supplier = suppliers.find(s => s.id === delivery.supplierId); + const isAutomatic = supplier?.automaticReconciliation === true; + const ecart = delivery.blAmount && delivery.invoiceAmount ? + ((parseFloat(delivery.invoiceAmount) - parseFloat(delivery.blAmount)) / parseFloat(delivery.blAmount) * 100).toFixed(1) : + null; + + return ( +
+
+
+ {delivery.supplier?.name} +
+ {isAutomatic && ( + AUTO + )} +
+
+
+ {delivery.blNumber || ( + Non renseigné + )} +
+
+
+ {safeFormat(delivery.scheduledDate, 'dd/MM/yy')} +
+
+
+ {delivery.invoiceReference || ( + Non renseignée + )} +
+
+
+ {delivery.blAmount ? + `${parseFloat(delivery.blAmount).toFixed(2)}€` : + Non renseigné + } +
+
+
+ {delivery.invoiceAmount ? + `${parseFloat(delivery.invoiceAmount).toFixed(2)}€` : + Non renseigné + } +
+
+ {ecart !== null ? ( + 5 ? "destructive" : "secondary"} + className="text-xs" + > + {parseFloat(ecart) > 0 ? '+' : ''}{ecart}% + + ) : ( + - + )} + +
+ {delivery.group?.name} +
+
+
+ + {(permissions.canEdit('reconciliation') || permissions.canValidate('reconciliation')) && ( + + )} + {permissions.canDelete('reconciliation') && ( + + )} +
-
-
- {safeFormat(delivery.scheduledDate, 'dd/MM/yy')} -
-
-
- {delivery.validatedAt ? - safeFormat(delivery.validatedAt, 'dd/MM/yy HH:mm') : - Non validé - } -
-
-
- {delivery.group?.name} -
-
-
- {shouldShowInvoiceButton(delivery) && ( - - )} - - {(permissions.canEdit('reconciliation') || permissions.canValidate('reconciliation')) && ( - - )} - {permissions.canDelete('reconciliation') && ( - - )} - -
-
@@ -1260,12 +1242,12 @@ export default function BLReconciliation() { {/* Pagination du bas */}