prepare(" SELECT i.*, c.name as company_name FROM invoices i JOIN companies c ON i.company_id = c.id WHERE i.id = ? "); $stmt->execute([$id]); } else { $stmt = $db->prepare(" SELECT i.*, c.name as company_name FROM invoices i JOIN companies c ON i.company_id = c.id WHERE i.id = ? AND i.tenant_id = ? "); $stmt->execute([$id, $tenantId]); } $invoice = $stmt->fetch(); if (!$invoice) json_error('Invoice not found or access denied', 404); // 2. Fetch Line Items $stmtLines = $db->prepare("SELECT * FROM invoice_lines WHERE invoice_id = ? ORDER BY line_number ASC"); $stmtLines->execute([$id]); $invoice['items'] = $stmtLines->fetchAll(); // 3. Decrypt all encrypted fields — robust: if decryption fails, keep original value $dec = function($val) { if (empty($val)) return ''; $result = \App\Core\Encryption::decrypt((string)$val); return ($result !== false && $result !== null) ? $result : (string)$val; }; $invoice['supplier_tin'] = $dec($invoice['supplier_tin']); $invoice['supplier_name'] = $dec($invoice['supplier_name']); $invoice['supplier_address'] = $dec($invoice['supplier_address']); $invoice['buyer_tin'] = $dec($invoice['buyer_tin']); $invoice['buyer_name'] = $dec($invoice['buyer_name']); $invoice['buyer_national_id'] = $dec($invoice['buyer_national_id']); // company_name is stored plaintext in the companies table — no decryption needed // $invoice['company_name'] is already plaintext from the JOIN // 3.5 Parse Validation Warnings if (isset($invoice['validation_warnings']) && $invoice['validation_warnings']) { $invoice['validation_warnings'] = json_decode($invoice['validation_warnings'], true); } else { $invoice['validation_warnings'] = []; } // 4. Fetch JoFotara Submission Data (latest accepted submission) $stmtSub = $db->prepare(" SELECT jofotara_uuid, submitted_at, qr_code_raw, response_body FROM jofotara_submissions WHERE invoice_id = ? AND status = 'accepted' ORDER BY created_at DESC LIMIT 1 "); $stmtSub->execute([$id]); $submission = $stmtSub->fetch(); if ($submission) { $invoice['jofotara'] = [ 'uuid' => $submission['jofotara_uuid'], 'submitted_at' => $submission['submitted_at'], 'qr_image_uri' => $submission['qr_code_raw'] ? 'data:image/png;base64,' . $submission['qr_code_raw'] : null, 'has_xml' => true, ]; } else { $invoice['jofotara'] = null; } // 5. Build the secure file URL using the invoice ID (file.php fetches path from DB) $invoice['file_url'] = '/index.php?route=v1/invoices/file&id=' . urlencode($id); // 6. Include local QR code from invoices table if available // (This is used as a fallback in shell.php if jofotara object is missing) json_success($invoice); } catch (\Exception $e) { error_log("Invoice View Error: " . $e->getMessage()); json_error('Server error during invoice retrieval', 500); }