🚀 Multi-invoice extraction and detailed validation feedback

This commit is contained in:
Hamza-Ayed
2026-04-19 16:13:09 +03:00
parent 6b9ce6e95b
commit 2e2d76c0a8
5 changed files with 121 additions and 55 deletions

View File

@@ -52,25 +52,44 @@ export class InvoiceProcessor {
* الخطوة الأولى: استخراج البيانات باستخدام AI
*/
@Process('extract-data')
async handleExtraction(job: Job<{ invoiceId: string; filePath: string; tenantId: string }>) {
const { invoiceId, filePath } = job.data;
async handleExtraction(job: Job<{ invoiceId: string; filePath: string; tenantId: string; companyId: string }>) {
const { invoiceId, filePath, tenantId, companyId } = job.data;
const storageRoot = this.configService.get<string>('STORAGE_PATH', './uploads');
try {
// 1. Update status to EXTRACTING
await this.invoiceRepository.update(invoiceId, { status: InvoiceStatus.EXTRACTING });
// 2. Extract data via Gemini
const data = await this.geminiExtractor.extractInvoiceData(filePath, storageRoot);
// 2. Extract data via Gemini (Now returns an array)
const invoicesData = await this.geminiExtractor.extractInvoiceData(filePath, storageRoot);
// 3. Save extracted data in a transaction
await this.saveExtractedData(invoiceId, data);
if (!invoicesData || invoicesData.length === 0) {
throw new Error('No invoices found in file');
}
this.logger.log(`Extraction successful for invoice ${invoiceId}`);
// 3. Process the first invoice (updates the current record)
await this.saveExtractedData(invoiceId, invoicesData[0]);
// 4. If multiple invoices found, create new records for others
if (invoicesData.length > 1) {
this.logger.log(`Found ${invoicesData.length} invoices in file ${filePath}. Creating additional records...`);
for (let i = 1; i < invoicesData.length; i++) {
const newInvoice = this.invoiceRepository.create({
tenant_id: tenantId,
company_id: companyId,
original_file_path: filePath,
status: InvoiceStatus.EXTRACTING,
});
const savedNew = await this.invoiceRepository.save(newInvoice);
await this.saveExtractedData(savedNew.id, invoicesData[i]);
}
}
this.logger.log(`Extraction successful for invoice(s) in ${filePath}`);
} catch (error) {
await this.invoiceRepository.update(invoiceId, {
status: InvoiceStatus.VALIDATION_FAILED,
// Optional: Save error message in a notes column
});
throw error;
}
@@ -90,6 +109,7 @@ export class InvoiceProcessor {
invoice_number: data.invoice_number,
invoice_date: data.invoice_date,
invoice_type: data.invoice_type || 'cash',
invoice_category: data.invoice_category || 'simplified',
supplier_name: data.supplier_name,
supplier_tin: data.supplier_tin,
buyer_name: data.buyer_name,
@@ -149,11 +169,14 @@ export class InvoiceProcessor {
const result = this.taxValidation.validateInvoice(invoice);
if (result.isValid) {
await this.invoiceRepository.update(invoiceId, { status: InvoiceStatus.VALIDATED });
await this.invoiceRepository.update(invoiceId, {
status: InvoiceStatus.VALIDATED,
validation_errors: null,
});
} else {
await this.invoiceRepository.update(invoiceId, {
status: InvoiceStatus.VALIDATION_FAILED,
// Optional: Save detailed error list
validation_errors: result.errors,
});
}
}