Checkpoint: Correction robuste des doublons de factures : empreinte SHA-256 unique des PDF sources, détection globale avant import manuel/email/dossier/web, verrou contre les vérifications IMAP concurrentes, attente réelle de fin de traitement avant marquage lu, migration et tests de non-régression.
This commit is contained in:
2
drizzle/0037_goofy_quentin_quire.sql
Normal file
2
drizzle/0037_goofy_quentin_quire.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `sourceFiles` ADD `contentHash` varchar(64);--> statement-breakpoint
|
||||
ALTER TABLE `sourceFiles` ADD CONSTRAINT `source_file_content_hash_unique` UNIQUE(`contentHash`);
|
||||
2372
drizzle/meta/0037_snapshot.json
Normal file
2372
drizzle/meta/0037_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -260,6 +260,13 @@
|
||||
"when": 1785419093588,
|
||||
"tag": "0036_broken_rattler",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 37,
|
||||
"version": "5",
|
||||
"when": 1787394418464,
|
||||
"tag": "0037_goofy_quentin_quire",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -36,12 +36,16 @@ export const sourceFiles = mysqlTable("sourceFiles", {
|
||||
fileName: varchar("fileName", { length: 255 }).notNull(),
|
||||
fileKey: text("fileKey").notNull(), // Local storage key with YYYY-MM prefix
|
||||
fileUrl: text("fileUrl").notNull(), // Public URL
|
||||
/** Empreinte du PDF source, globale à l'application pour bloquer tout réimport identique. */
|
||||
contentHash: varchar("contentHash", { length: 64 }),
|
||||
totalInvoicesDetected: int("totalInvoicesDetected").default(0).notNull(),
|
||||
processingStatus: mysqlEnum("processingStatus", ["processing", "completed", "error"]).default("processing").notNull(),
|
||||
processingProgress: varchar("processingProgress", { length: 255 }), // Progress message (e.g., "Extraction 3/9 factures...")
|
||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
||||
});
|
||||
}, (table) => ({
|
||||
contentHashIdx: uniqueIndex("source_file_content_hash_unique").on(table.contentHash),
|
||||
}));
|
||||
|
||||
export type SourceFile = typeof sourceFiles.$inferSelect;
|
||||
export type InsertSourceFile = typeof sourceFiles.$inferInsert;
|
||||
|
||||
Reference in New Issue
Block a user