Checkpoint: Ajout complet du champ "Destinataire" (recipientName) dans toute l'application : schéma DB (invoices.recipientName + userSettings.recipientKeywords), extraction IA (prompt LLM + interface), services d'import (email, dossier, upload manuel), interface utilisateur (liste des factures, détail, paramètres mots-clés), règles d'automatisme et configuration des champs LLM obligatoires.

This commit is contained in:
Manus
2026-04-12 05:06:06 -04:00
parent d8d2ef14da
commit 604426523d
14 changed files with 1560 additions and 7 deletions

View File

@@ -237,6 +237,7 @@ export default function AutomationRules() {
const fieldOptions = [
{ value: "supplierName", label: "Fournisseur" },
{ value: "recipientName", label: "Destinataire" },
{ value: "invoiceNumber", label: "N° Facture" },
{ value: "totalAmount", label: "Montant" },
{ value: "invoiceDate", label: "Date facture" },

View File

@@ -28,6 +28,7 @@ export default function InvoiceDetail() {
deliveryNoteNumber: "",
orderNumber: "",
totalAmount: "",
recipientName: "",
serviceConcerne: "",
typeAchat: "",
ventilationComptable: "",
@@ -45,6 +46,7 @@ export default function InvoiceDetail() {
deliveryNoteNumber: invoice.deliveryNoteNumber || "",
orderNumber: invoice.orderNumber || "",
totalAmount: invoice.totalAmount ? invoice.totalAmount.toString() : "",
recipientName: (invoice as any).recipientName || "",
serviceConcerne: invoice.serviceConcerne || "",
typeAchat: invoice.typeAchat || "",
ventilationComptable: invoice.ventilationComptable || "",
@@ -87,6 +89,7 @@ export default function InvoiceDetail() {
deliveryNoteNumber: formData.deliveryNoteNumber || undefined,
orderNumber: formData.orderNumber || undefined,
totalAmount: formData.totalAmount ? formData.totalAmount : undefined,
recipientName: formData.recipientName || undefined,
serviceConcerne: formData.serviceConcerne || undefined,
typeAchat: (formData.typeAchat as "CAPEX" | "OPEX" | "") || undefined,
ventilationComptable: formData.ventilationComptable || undefined,
@@ -330,6 +333,20 @@ export default function InvoiceDetail() {
</div>
)}
</div>
<div>
<Label htmlFor="recipientName">Destinataire</Label>
{isEditing ? (
<Input
id="recipientName"
value={formData.recipientName}
onChange={(e) => setFormData({ ...formData, recipientName: e.target.value })}
placeholder="Nom du destinataire"
/>
) : (
<div className="text-sm mt-1">{(invoice as any).recipientName || "-"}</div>
)}
</div>
</CardContent>
</Card>

View File

@@ -60,15 +60,16 @@ export default function Invoices() {
// Generate Excel file
const worksheet = XLSX.utils.json_to_sheet(data.invoices.map(inv => ({
'Fournisseur': inv.supplierName,
'N\u00b0 Facture': inv.invoiceNumber,
'Destinataire': (inv as any).recipientName,
'N° Facture': inv.invoiceNumber,
'Date': inv.invoiceDate,
'N\u00b0 Bon de livraison': inv.deliveryNoteNumber,
'N\u00b0 Commande': inv.orderNumber,
'N° Bon de livraison': inv.deliveryNoteNumber,
'N° Commande': inv.orderNumber,
'Montant': inv.totalAmount,
'Score': inv.qualityScore,
'Statut export': inv.exportStatus,
'Export\u00e9 le': inv.exportedAt,
'Cr\u00e9\u00e9 le': inv.createdAt,
'Exporté le': inv.exportedAt,
'Créé le': inv.createdAt,
})));
const workbook = XLSX.utils.book_new();
@@ -398,6 +399,7 @@ export default function Invoices() {
/>
</TableHead>
<TableHead>Fournisseur</TableHead>
<TableHead>Destinataire</TableHead>
<TableHead>N° Facture</TableHead>
<TableHead>Date</TableHead>
<TableHead>Montant</TableHead>
@@ -426,6 +428,7 @@ export default function Invoices() {
{invoice.supplierName || "Inconnu"}
</button>
</TableCell>
<TableCell>{(invoice as any).recipientName || "-"}</TableCell>
<TableCell>{invoice.invoiceNumber || "-"}</TableCell>
<TableCell>
{invoice.invoiceDate

View File

@@ -664,6 +664,7 @@ export default function Settings() {
const [supplierKeywords, setSupplierKeywords] = useState("");
const [totalAmountKeywords, setTotalAmountKeywords] = useState("");
const [subscriptionKeywords, setSubscriptionKeywords] = useState("");
const [recipientKeywords, setRecipientKeywords] = useState("");
const [sftpHost, setSftpHost] = useState("");
const [sftpPort, setSftpPort] = useState(22);
const [sftpUsername, setSftpUsername] = useState("");
@@ -681,6 +682,7 @@ export default function Settings() {
setSupplierKeywords(settings.supplierKeywords || "");
setTotalAmountKeywords(settings.totalAmountKeywords || "");
setSubscriptionKeywords(settings.subscriptionKeywords || "");
setRecipientKeywords((settings as any).recipientKeywords || "");
setSftpHost(settings.sftpHost || "");
setSftpPort(settings.sftpPort || 22);
setSftpUsername(settings.sftpUsername || "");
@@ -723,6 +725,7 @@ export default function Settings() {
supplierKeywords,
totalAmountKeywords,
subscriptionKeywords,
recipientKeywords,
sftpHost,
sftpPort,
sftpUsername,
@@ -986,6 +989,24 @@ export default function Settings() {
Les factures contenant ces mots-clés seront automatiquement marquées comme abonnement
</p>
</div>
<div className="space-y-3">
<Label htmlFor="recipientKeywords" className="text-base font-semibold">
Destinataire
</Label>
<Textarea
id="recipientKeywords"
value={recipientKeywords}
onChange={(e) => setRecipientKeywords(e.target.value)}
placeholder="Destinataire, Client, Adressé à, Bill to, Ship to"
rows={2}
className="resize-none"
/>
<p className="text-sm text-muted-foreground flex items-center gap-2">
<AlertCircle className="w-4 h-4" />
Mots-clés pour identifier le destinataire/client de la facture
</p>
</div>
</div>
</CardContent>
</Card>