fix: relancer les sources vides après purge
This commit is contained in:
@@ -30,6 +30,7 @@ import {
|
||||
createSourceFile,
|
||||
getSourceFileByContentHash,
|
||||
getSourceFileById,
|
||||
countInvoicesBySourceFileId,
|
||||
updateSourceFile,
|
||||
getUserSettings,
|
||||
upsertUserSettings,
|
||||
@@ -102,7 +103,8 @@ import fsSync from "fs";
|
||||
import pathSync from "path";
|
||||
import { extractInvoicesWithMistral, generateMetadataJSON } from "./invoiceExtractor";
|
||||
import { calculateFileSha256 } from "./fileFingerprint";
|
||||
import { localStoragePut, generateStorageKey } from "./localStorage";
|
||||
import { localStoragePut, localStorageExists, generateStorageKey } from "./localStorage";
|
||||
import { shouldReprocessEmptySource } from "@shared/sourceFileReimport";
|
||||
import { testReferentialIaConnection } from "./referentialIa";
|
||||
import { testSftpConnection, exportInvoiceToSftp, getUserSftpConfig } from "./sftpExport";
|
||||
import { drawBapCartouche } from "./bapCartouche";
|
||||
@@ -206,37 +208,62 @@ export const appRouter = router({
|
||||
// Il reste fiable même si le nom du fichier ou le compte utilisateur diffère.
|
||||
const contentHash = calculateFileSha256(fileBuffer);
|
||||
const existingSource = await getSourceFileByContentHash(contentHash);
|
||||
let sourceFile;
|
||||
let sourceFileKey: string;
|
||||
let sourceFileUrl: string;
|
||||
let reprocessed = false;
|
||||
|
||||
if (existingSource) {
|
||||
throw new TRPCError({
|
||||
code: "CONFLICT",
|
||||
message: `Ce PDF a déjà été importé (${existingSource.fileName}).`,
|
||||
const invoiceCount = await countInvoicesBySourceFileId(existingSource.id);
|
||||
if (!shouldReprocessEmptySource({
|
||||
sourceUserId: existingSource.userId,
|
||||
requestingUserId: userId,
|
||||
invoiceCount,
|
||||
})) {
|
||||
throw new TRPCError({
|
||||
code: "CONFLICT",
|
||||
message: `Ce PDF a déjà été importé (${existingSource.fileName}).`,
|
||||
});
|
||||
}
|
||||
|
||||
// Une purge peut supprimer les factures tout en conservant la source et son empreinte.
|
||||
// On relance alors l'analyse depuis la source existante plutôt que de contourner l'anti-doublon.
|
||||
sourceFile = existingSource;
|
||||
sourceFileKey = existingSource.fileKey;
|
||||
sourceFileUrl = existingSource.fileUrl;
|
||||
reprocessed = true;
|
||||
if (!await localStorageExists(sourceFileKey)) {
|
||||
await localStoragePut(sourceFileKey, fileBuffer, "application/pdf");
|
||||
}
|
||||
await updateSourceFile(sourceFile.id, {
|
||||
processingStatus: "processing",
|
||||
totalInvoicesDetected: 0,
|
||||
processingProgress: "Nouvelle analyse après purge...",
|
||||
});
|
||||
} else {
|
||||
// Store source file
|
||||
sourceFileKey = generateStorageKey(userId, input.fileName);
|
||||
console.log(`[Upload] Generated storage key: ${sourceFileKey}`);
|
||||
|
||||
try {
|
||||
const result = await localStoragePut(sourceFileKey, fileBuffer, "application/pdf");
|
||||
sourceFileUrl = result.url;
|
||||
console.log(`[Upload] File stored successfully at: ${sourceFileUrl}`);
|
||||
} catch (error) {
|
||||
console.error(`[Upload] FAILED to store file:`, error);
|
||||
throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: "Failed to store PDF file" });
|
||||
}
|
||||
|
||||
sourceFile = await createSourceFile({
|
||||
userId,
|
||||
fileName: input.fileName,
|
||||
fileKey: sourceFileKey,
|
||||
fileUrl: sourceFileUrl,
|
||||
contentHash,
|
||||
processingStatus: "processing",
|
||||
});
|
||||
}
|
||||
|
||||
// Store source file
|
||||
const sourceFileKey = generateStorageKey(userId, input.fileName);
|
||||
console.log(`[Upload] Generated storage key: ${sourceFileKey}`);
|
||||
|
||||
let sourceFileUrl: string;
|
||||
try {
|
||||
const result = await localStoragePut(sourceFileKey, fileBuffer, "application/pdf");
|
||||
sourceFileUrl = result.url;
|
||||
console.log(`[Upload] File stored successfully at: ${sourceFileUrl}`);
|
||||
} catch (error) {
|
||||
console.error(`[Upload] FAILED to store file:`, error);
|
||||
throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: "Failed to store PDF file" });
|
||||
}
|
||||
|
||||
// Create source file record
|
||||
const sourceFile = await createSourceFile({
|
||||
userId,
|
||||
fileName: input.fileName,
|
||||
fileKey: sourceFileKey,
|
||||
fileUrl: sourceFileUrl,
|
||||
contentHash,
|
||||
processingStatus: "processing",
|
||||
});
|
||||
|
||||
// Start extraction process (async - don't wait)
|
||||
(async () => {
|
||||
try {
|
||||
@@ -439,7 +466,7 @@ export const appRouter = router({
|
||||
}
|
||||
})();
|
||||
|
||||
return { sourceFileId: sourceFile.id };
|
||||
return { sourceFileId: sourceFile.id, reprocessed };
|
||||
}),
|
||||
|
||||
list: protectedProcedure.query(async ({ ctx }) => {
|
||||
|
||||
Reference in New Issue
Block a user