Update: 2026-05-05 01:31:02

This commit is contained in:
Hamza-Ayed
2026-05-05 01:31:02 +03:00
parent 2f6a08800d
commit dcbf8bd04f
2 changed files with 22 additions and 19 deletions

View File

@@ -80,29 +80,29 @@ if (move_uploaded_file($_FILES['invoice']['tmp_name'], $targetFile)) {
json_success(['id' => $db->lastInsertId()], 'تم رفع الفاتورة ولكن فشل استخراج البيانات تلقائياً'); json_success(['id' => $db->lastInsertId()], 'تم رفع الفاتورة ولكن فشل استخراج البيانات تلقائياً');
} }
// 5.5 Duplicate Prevention Check
$supplierTin = $extracted['supplier']['tin'] ?? '';
$invoiceNum = $extracted['invoice_number'] ?? '';
$invoiceDate = $extracted['invoice_date'] ?? '';
// Only hash if we have the critical data to avoid false duplicate collisions
$invoiceHash = null;
if ($supplierTin && $invoiceNum && $invoiceDate) {
$rawHashString = $companyId . '_' . $supplierTin . '_' . $invoiceNum . '_' . $invoiceDate;
$invoiceHash = hash('sha256', strtolower($rawHashString));
$checkStmt = $db->prepare("SELECT id FROM invoices WHERE company_id = ? AND invoice_hash = ? AND deleted_at IS NULL");
$checkStmt->execute([$companyId, $invoiceHash]);
if ($checkStmt->fetch()) {
json_error('هذه الفاتورة تم رفعها مسبقاً لهذه الشركة (رقم الفاتورة مكرر لنفس المورد والتاريخ).', 409);
}
}
// 6. Save Extracted Data with Encryption // 6. Save Extracted Data with Encryption
try { try {
$db->beginTransaction(); $db->beginTransaction();
$invoiceId = bin2hex(random_bytes(16)); // Generate UUID (simple version for now or use a lib) // 5.5 Duplicate Prevention Check (Now inside transaction for safety)
$supplierTin = $extracted['supplier']['tin'] ?? '';
$invoiceNum = $extracted['invoice_number'] ?? '';
$invoiceDate = $extracted['invoice_date'] ?? '';
$invoiceHash = null;
if ($supplierTin && $invoiceNum && $invoiceDate) {
$rawHashString = $companyId . '_' . $supplierTin . '_' . $invoiceNum . '_' . $invoiceDate;
$invoiceHash = hash('sha256', strtolower($rawHashString));
$checkStmt = $db->prepare("SELECT id FROM invoices WHERE company_id = ? AND invoice_hash = ? AND deleted_at IS NULL");
$checkStmt->execute([$companyId, $invoiceHash]);
if ($checkStmt->fetch()) {
$db->rollBack();
json_error('هذه الفاتورة تم رفعها مسبقاً لهذه الشركة (رقم الفاتورة مكرر لنفس المورد والتاريخ).', 409);
}
}
$invoiceId = bin2hex(random_bytes(16)); // Generate UUID
// Let's use a standard UUID format if possible, but MySQL CHAR(36) accepts anything. // Let's use a standard UUID format if possible, but MySQL CHAR(36) accepts anything.
// Actually, let's just use the DB's UUID() function but FETCH it back or generate it here. // Actually, let's just use the DB's UUID() function but FETCH it back or generate it here.
// I'll use a better UUID generator logic. // I'll use a better UUID generator logic.

View File

@@ -23,6 +23,9 @@ $migrations = [
// 2. Add validation_warnings for AI Pre-Audit // 2. Add validation_warnings for AI Pre-Audit
'add_validation_warnings' => "ALTER TABLE invoices ADD COLUMN validation_warnings JSON NULL", 'add_validation_warnings' => "ALTER TABLE invoices ADD COLUMN validation_warnings JSON NULL",
// 2.5 Add deleted_at for soft delete (Missing in Phase 1 for this table)
'add_invoices_soft_delete' => "ALTER TABLE invoices ADD COLUMN deleted_at DATETIME NULL DEFAULT NULL",
// 3. Create Unique Index to prevent duplicates within the same tenant & company // 3. Create Unique Index to prevent duplicates within the same tenant & company
// Using a regular index for now, application logic will handle uniqueness to allow nulls // Using a regular index for now, application logic will handle uniqueness to allow nulls
'add_hash_index' => "CREATE INDEX idx_invoice_hash ON invoices(tenant_id, company_id, invoice_hash)", 'add_hash_index' => "CREATE INDEX idx_invoice_hash ON invoices(tenant_id, company_id, invoice_hash)",