182 lines
11 KiB
PHP
182 lines
11 KiB
PHP
window.viewAndPrintA4Invoice = function(data, autoPrint = true) {
|
|
if (!data) return;
|
|
// Reuse view logic
|
|
const invoiceDisplayNo = data.document_no || data.transaction_no || ((data.type === 'purchase' ? 'PUR-' : 'INV-') + data.id.toString().padStart(5, '0'));
|
|
document.getElementById('invNumber').textContent = invoiceDisplayNo;
|
|
document.getElementById('invDate').textContent = data.invoice_date;
|
|
document.getElementById('invPaymentType').textContent = data.payment_type ? data.payment_type.toUpperCase() : 'CASH';
|
|
document.getElementById('invCustomerName').textContent = data.customer_name || '---';
|
|
|
|
const phoneEl = document.getElementById('invCustomerPhone');
|
|
const phoneContainer = document.getElementById('invCustomerPhoneContainer');
|
|
if (data.customer_phone) {
|
|
phoneEl.textContent = data.customer_phone;
|
|
phoneContainer.style.display = 'block';
|
|
} else {
|
|
phoneContainer.style.display = 'none';
|
|
}
|
|
|
|
const taxIdEl = document.getElementById('invCustomerTaxId');
|
|
const taxIdContainer = document.getElementById('invCustomerTaxIdContainer');
|
|
if (data.customer_tax_id) {
|
|
taxIdEl.textContent = data.customer_tax_id;
|
|
taxIdContainer.style.display = 'block';
|
|
} else {
|
|
taxIdContainer.style.display = 'none';
|
|
}
|
|
|
|
document.getElementById('invAmountInWords').textContent = data.total_in_words || '';
|
|
|
|
const invOutletEl = document.getElementById('invOutletName');
|
|
if (invOutletEl) {
|
|
invOutletEl.textContent = data.outlet_name ? (data.outlet_name) : '';
|
|
invOutletEl.style.display = data.outlet_name ? 'block' : 'none';
|
|
}
|
|
|
|
document.getElementById('invPartyLabel').textContent = data.type === 'sale' ? 'Bill To / فاتورة إلى' : 'Bill From / فاتورة من';
|
|
document.getElementById('invPartyLabel').setAttribute('data-en', data.type === 'sale' ? 'Bill To' : 'Bill From');
|
|
document.getElementById('invPartyLabel').setAttribute('data-ar', data.type === 'sale' ? 'فاتورة إلى' : 'فاتورة من');
|
|
document.getElementById('invoiceTypeLabel').textContent = data.type;
|
|
document.getElementById('invoiceTypeLabel').className = 'badge text-uppercase ' + (data.type === 'sale' ? 'bg-success' : 'bg-warning');
|
|
|
|
const statusLabel = document.getElementById('invoiceStatusLabel');
|
|
let statusClass = 'bg-secondary';
|
|
let statusEn = data.status ? (data.status.charAt(0).toUpperCase() + data.status.slice(1)) : '---';
|
|
if (data.status === 'paid') statusClass = 'bg-success';
|
|
else if (data.status === 'unpaid') statusClass = 'bg-danger';
|
|
else if (data.status === 'partially_paid') {
|
|
statusClass = 'bg-warning text-dark';
|
|
statusEn = 'Partially Paid';
|
|
}
|
|
|
|
statusLabel.textContent = statusEn;
|
|
statusLabel.className = 'badge text-uppercase ' + statusClass;
|
|
|
|
const body = document.getElementById('invItemsBody');
|
|
body.innerHTML = '';
|
|
if (data.items) {
|
|
data.items.forEach(item => {
|
|
const tr = document.createElement('tr');
|
|
tr.innerHTML = `
|
|
<td>${item.name_en} / ${item.name_ar}</td>
|
|
<td class="text-center">${formatQuantity(item.quantity)}</td>
|
|
<td class="text-end"><small><?= __('currency') ?></small> ${parseFloat(item.unit_price).toFixed(3)}</td>
|
|
<td class="text-end">${parseFloat(item.vat_rate || 0).toFixed(2)}%</td>
|
|
<td class="text-end"><small><?= __('currency') ?></small> ${parseFloat(item.total_price).toFixed(3)}</td>
|
|
`;
|
|
body.appendChild(tr);
|
|
});
|
|
}
|
|
const vatVal = parseFloat(data.vat_amount || 0);
|
|
const totalVal = parseFloat(data.total_amount || 0);
|
|
const grandTotalValue = (parseFloat(data.total_with_vat) || (totalVal + vatVal));
|
|
|
|
if (document.getElementById('invSubtotal')) document.getElementById('invSubtotal').innerHTML = '<small><?= __('currency') ?></small> ' + (grandTotalValue - vatVal).toFixed(3);
|
|
if (document.getElementById('invVatAmount')) document.getElementById('invVatAmount').innerHTML = '<small><?= __('currency') ?></small> ' + vatVal.toFixed(2);
|
|
if (document.getElementById('invGrandTotal')) document.getElementById('invGrandTotal').innerHTML = '<small><?= __('currency') ?></small> ' + grandTotalValue.toFixed(3);
|
|
|
|
if (document.getElementById('invPaidInfo')) document.getElementById('invPaidInfo').innerHTML = '<small><?= __('currency') ?></small> ' + parseFloat(data.paid_amount || 0).toFixed(3);
|
|
const balance = grandTotalValue - parseFloat(data.paid_amount || 0);
|
|
if (document.getElementById('invBalanceInfo')) document.getElementById('invBalanceInfo').innerHTML = '<small><?= __('currency') ?></small> ' + balance.toFixed(3);
|
|
|
|
// Generate QR Code for Zakat, Tax and Customs Authority (ZATCA) style or simple formal
|
|
const companyName = <?= json_encode($data['settings']['company_name'] ?? 'Accounting System') ?>;
|
|
const vatNo = <?= json_encode($data['settings']['vat_number'] ?? '') ?>;
|
|
const qrData = `Seller: ${companyName}\nVAT: ${vatNo}\nInvoice: ${invoiceDisplayNo}\nDate: ${data.invoice_date}\nTotal: ${grandTotalValue.toFixed(3)}`;
|
|
const qrUrl = `https://api.qrserver.com/v1/create-qr-code/?size=100x100&data=${encodeURIComponent(qrData)}`;
|
|
if (document.getElementById('invQrCode')) {
|
|
document.getElementById('invQrCode').innerHTML = `<img src="${qrUrl}" alt="QR Code" style="width: 100px; height: 100px;" class="border p-1 bg-white">`;
|
|
}
|
|
|
|
const viewModal = bootstrap.Modal.getOrCreateInstance(document.getElementById('viewInvoiceModal'));
|
|
viewModal.show();
|
|
|
|
if (autoPrint) {
|
|
setTimeout(() => { window.print(); }, 1000);
|
|
}
|
|
|
|
fetch(`index.php?action=get_payments&invoice_id=${data.id}`)
|
|
.then(res => res.json())
|
|
.then(payments => {
|
|
const paymentsBody = document.getElementById('invPaymentsBody');
|
|
const paymentsSection = document.getElementById('invPaymentsSection');
|
|
if (paymentsBody) paymentsBody.innerHTML = '';
|
|
if (payments && payments.length > 0) {
|
|
if (paymentsBody) {
|
|
payments.forEach(p => {
|
|
const tr = document.createElement('tr');
|
|
tr.innerHTML = `<td>${p.payment_date}</td><td>${p.payment_method}</td><td class="text-end fw-bold">OMR ${parseFloat(p.amount).toFixed(3)}</td>`;
|
|
paymentsBody.appendChild(tr);
|
|
});
|
|
}
|
|
if (paymentsSection) paymentsSection.style.display = 'block';
|
|
} else {
|
|
if (paymentsSection) paymentsSection.style.display = 'none';
|
|
}
|
|
}).catch(err => console.error('Error fetching payments:', err));
|
|
};
|
|
|
|
<?php
|
|
$autoInvoicePayload = null;
|
|
if (
|
|
isset($_SESSION['trigger_invoice_modal'], $_SESSION['show_invoice_id'], $_SESSION['show_invoice_page']) &&
|
|
in_array($page, ['sales', 'purchases'], true) &&
|
|
$_SESSION['show_invoice_page'] === $page
|
|
) {
|
|
$autoInvoiceId = (int)$_SESSION['show_invoice_id'];
|
|
$autoInvoiceType = $page === 'purchases' ? 'purchase' : 'sale';
|
|
unset($_SESSION['trigger_invoice_modal'], $_SESSION['show_invoice_id'], $_SESSION['show_invoice_page']);
|
|
|
|
try {
|
|
$autoTable = $autoInvoiceType === 'purchase' ? 'purchases' : 'invoices';
|
|
$autoPartyTable = $autoInvoiceType === 'purchase' ? 'suppliers' : 'customers';
|
|
$autoPartyCol = $autoInvoiceType === 'purchase' ? 'supplier_id' : 'customer_id';
|
|
$autoTaxColumn = entity_tax_column($autoPartyTable);
|
|
$autoTaxSelect = $autoTaxColumn !== null ? "c.$autoTaxColumn AS customer_tax_id" : "'' AS customer_tax_id";
|
|
$autoOutletSelect = "'' AS outlet_name";
|
|
$autoOutletJoin = '';
|
|
|
|
if (db_column_exists($autoTable, 'outlet_id') && db_table_exists('outlets')) {
|
|
$autoOutletSelect = 'o.name AS outlet_name';
|
|
$autoOutletJoin = 'LEFT JOIN outlets o ON doc.outlet_id = o.id';
|
|
}
|
|
|
|
$autoStmt = db()->prepare("SELECT doc.*, c.name AS customer_name, c.phone AS customer_phone, $autoTaxSelect, $autoOutletSelect
|
|
FROM $autoTable doc
|
|
LEFT JOIN $autoPartyTable c ON doc.$autoPartyCol = c.id
|
|
$autoOutletJoin
|
|
WHERE doc.id = ?
|
|
LIMIT 1");
|
|
$autoStmt->execute([$autoInvoiceId]);
|
|
$autoInvoicePayload = $autoStmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if ($autoInvoicePayload) {
|
|
$autoItemSql = $autoInvoiceType === 'purchase'
|
|
? "SELECT pi.*, i.name_en, i.name_ar, i.vat_rate FROM purchase_items pi LEFT JOIN stock_items i ON pi.item_id = i.id WHERE pi.purchase_id = ?"
|
|
: "SELECT ii.*, i.name_en, i.name_ar, i.vat_rate FROM invoice_items ii LEFT JOIN stock_items i ON ii.item_id = i.id WHERE ii.invoice_id = ?";
|
|
$autoItemsStmt = db()->prepare($autoItemSql);
|
|
$autoItemsStmt->execute([$autoInvoiceId]);
|
|
$autoInvoicePayload['items'] = $autoItemsStmt->fetchAll(PDO::FETCH_ASSOC);
|
|
$autoInvoicePayload['type'] = $autoInvoiceType;
|
|
$autoInvoicePayload['total_with_vat'] = (float)($autoInvoicePayload['total_with_vat'] ?? (($autoInvoicePayload['total_amount'] ?? 0) + ($autoInvoicePayload['vat_amount'] ?? 0)));
|
|
$autoInvoicePayload['paid_amount'] = (float)($autoInvoicePayload['paid_amount'] ?? 0);
|
|
$autoInvoicePayload['total_in_words'] = numberToWordsOMR($autoInvoicePayload['total_with_vat']);
|
|
$autoTransactionNo = trim((string)($autoInvoicePayload['transaction_no'] ?? ''));
|
|
$autoPrefix = $autoInvoiceType === 'purchase' ? 'PUR' : 'INV';
|
|
$autoInvoicePayload['document_no'] = ($autoInvoiceType === 'sale' && $autoTransactionNo !== '')
|
|
? $autoTransactionNo
|
|
: $autoPrefix . '-' . str_pad((string)$autoInvoicePayload['id'], 5, '0', STR_PAD_LEFT);
|
|
}
|
|
} catch (Throwable $e) {
|
|
$autoInvoicePayload = null;
|
|
}
|
|
}
|
|
?>
|
|
<?php if (!empty($autoInvoicePayload)): ?>
|
|
setTimeout(() => {
|
|
if (window.viewAndPrintA4Invoice) {
|
|
window.viewAndPrintA4Invoice(<?= json_encode($autoInvoicePayload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>, true);
|
|
}
|
|
}, 300);
|
|
<?php endif; ?>
|