beginTransaction(); // 1. Fetch Invoice & Company $stmt = $db->prepare(" SELECT i.*, c.name as company_name, c.tax_identification_number as company_tin, c.address as company_address, c.jofotara_client_id_encrypted, c.jofotara_secret_key_encrypted FROM invoices i JOIN companies c ON i.company_id = c.id WHERE i.id = ? FOR UPDATE "); $stmt->execute([$id]); $invoice = $stmt->fetch(); if (!$invoice) json_error('Invoice not found', 404); if ($invoice['status'] === 'approved') json_error('Already approved', 400); // 2. Fetch Line Items $stmtLines = $db->prepare("SELECT * FROM invoice_lines WHERE invoice_id = ?"); $stmtLines->execute([$id]); $invoice['items'] = $stmtLines->fetchAll(); // 3. Decrypt Company Keys for JoFotara $clientId = \App\Core\Encryption::decrypt($invoice['jofotara_client_id_encrypted'] ?? ''); $secretKey = \App\Core\Encryption::decrypt($invoice['jofotara_secret_key_encrypted'] ?? ''); $jofotara = new JoFotara(); $apiResponse = ['success' => false]; $xmlContent = null; // 4. Try JoFotara Submission if credentials exist if ($clientId && $secretKey) { $companyData = [ 'name' => $invoice['company_name'], 'tax_identification_number' => $invoice['company_tin'], 'address' => $invoice['company_address'] ]; // Decrypt Buyer Info for XML $invoice['buyer_name'] = \App\Core\Encryption::decrypt($invoice['buyer_name'] ?? '') ?: ($invoice['buyer_name'] ?? ''); $invoice['buyer_tin'] = \App\Core\Encryption::decrypt($invoice['buyer_tin'] ?? '') ?: ($invoice['buyer_tin'] ?? ''); $xmlContent = $jofotara->generateXML($invoice, $companyData); $apiResponse = $jofotara->submitInvoice($xmlContent, $clientId, $secretKey); } // 5. Fallback: Generate Local QR if API failed or no credentials $qrCode = $apiResponse['qrCode'] ?? $jofotara->generateQRCode([ 'supplier_name' => $invoice['company_name'], 'supplier_tin' => $invoice['company_tin'], 'invoice_date' => $invoice['invoice_date'], 'grand_total' => $invoice['grand_total'], 'tax_amount' => $invoice['tax_amount'] ]); // 6. Record Submission (Audit Log) $submissionId = \App\Core\Database::generateUuid(); $stmtSub = $db->prepare(" INSERT INTO jofotara_submissions (id, invoice_id, company_id, tenant_id, xml_payload, xml_hash, jofotara_uuid, qr_code_raw, response_code, response_body, status, submitted_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW()) "); $status = $apiResponse['success'] ? 'accepted' : 'error'; $stmtSub->execute([ $submissionId, $id, $invoice['company_id'], $invoice['tenant_id'], $xmlContent, $xmlContent ? hash('sha256', $xmlContent) : null, $apiResponse['uuid'] ?? null, $qrCode, $apiResponse['_http_code'] ?? '0', json_encode($apiResponse['raw'] ?? ['info' => 'Local approval / No credentials']), $status ]); // 7. Update Invoice $updateStmt = $db->prepare(" UPDATE invoices SET status = 'approved', jofotara_uuid = ?, qr_code = ?, updated_at = NOW() WHERE id = ? "); $updateStmt->execute([$apiResponse['uuid'] ?? null, $qrCode, $id]); $db->commit(); json_success([ 'message' => $apiResponse['success'] ? 'تم الاعتماد والإرسال إلى جوفوترة بنجاح' : 'تم الاعتماد محلياً (نظام جوفوترة غير متصل)', 'uuid' => $apiResponse['uuid'] ?? null, 'qr_code' => $qrCode, 'is_api_success' => $apiResponse['success'] ]); AuditLogger::log('invoice.approved', 'invoice', $id, [ 'old_status' => $invoice['status'], ], [ 'new_status' => 'approved', 'jofotara_uuid' => $apiResponse['uuid'] ?? null, 'api_success' => $apiResponse['success'], ], $decoded); } catch (\Exception $e) { if ($db->inTransaction()) $db->rollBack(); error_log("JoFotara Approve Error: " . $e->getMessage()); json_error('خطأ غير متوقع: ' . $e->getMessage(), 500); }