Checkpoint: Ajout du système de connecteurs web : table webImportSources, CRUD tRPC, page WebImportSources.tsx, endpoint /api/web-import/push-invoice, script cron SFR (scripts/web-import/sfr-connector.mjs)

This commit is contained in:
Manus
2026-07-30 13:53:07 +00:00
parent bcb307bde1
commit 711ce6b83a
13 changed files with 3314 additions and 2 deletions

View File

@@ -224,6 +224,56 @@ async function startServer() {
}
});
// ============= WEB IMPORT SOURCES - Endpoint pour script cron externe =============
app.post("/api/web-import/push-invoice", async (req, res) => {
try {
const { apiToken, fileName, fileBase64, mimeType } = req.body;
if (!apiToken || !fileName || !fileBase64) {
res.status(400).json({ error: "apiToken, fileName et fileBase64 sont requis" });
return;
}
const { getWebImportSourceByToken, getImportSettingsByUser, createInvoice, findDuplicateInvoice, isInvoiceBlacklisted, updateWebImportSourceStatus, createSourceFile } = await import('../db');
const source = await getWebImportSourceByToken(apiToken);
if (!source) {
res.status(401).json({ error: "Token invalide" });
return;
}
const pdfBuffer = Buffer.from(fileBase64, 'base64');
const fileMime = mimeType || 'application/pdf';
// Stocker le fichier source en DB
const sourceFile = await createSourceFile({
userId: source.userId,
fileName,
fileKey: `web-import/${source.userId}/${Date.now()}-${fileName}`,
fileUrl: '',
});
const importSettings = await getImportSettingsByUser(source.userId);
const aiSettings = {
aiProvider: importSettings?.aiProvider || 'manus',
mistralApiKey: importSettings?.mistralApiKey || undefined,
manusForgeApiUrl: importSettings?.manusForgeApiUrl || undefined,
manusForgeApiKey: importSettings?.manusForgeApiKey || undefined,
};
const { extractInvoicesWithMistral } = await import('../invoiceExtractor');
const extractResult = await extractInvoicesWithMistral(pdfBuffer, source.userId, sourceFile.id, 'mistral-large-latest', undefined, aiSettings);
let imported = 0;
let duplicates = 0;
for (const inv of extractResult.invoices || []) {
const blacklisted = await isInvoiceBlacklisted(inv.invoiceNumber || null, source.userId);
if (blacklisted) { duplicates++; continue; }
const dup = await findDuplicateInvoice(inv.invoiceNumber || null, String(inv.totalAmount ?? ''), source.userId);
if (dup) { duplicates++; continue; }
await createInvoice({ ...inv, userId: source.userId, sourceFileId: sourceFile.id } as any);
imported++;
}
await updateWebImportSourceStatus(source.id, 'success', imported, true);
res.json({ success: true, imported, duplicates, total: (extractResult.invoices || []).length });
} catch (err: any) {
console.error('[WebImport] Erreur push-invoice:', err.message);
res.status(500).json({ error: err.message });
}
});
// tRPC API
app.use(
"/api/trpc",