feat: use outlet information for printed bills and receipts

This commit is contained in:
Flatlogic Bot 2026-02-26 04:19:09 +00:00
parent 2151676734
commit 0a530f6c7b

View File

@ -419,10 +419,12 @@ if (isset($_GET['action']) || isset($_POST['action'])) {
if ($action === 'get_payment_details') {
header('Content-Type: application/json');
$payment_id = (int)$_GET['payment_id'];
$stmt = db()->prepare("SELECT p.*, i.customer_id, c.name as customer_name
$stmt = db()->prepare("SELECT p.*, i.customer_id, i.id as inv_id, c.name as customer_name,
o.name as outlet_name, o.address as outlet_address, o.phone as outlet_phone
FROM payments p
JOIN invoices i ON p.invoice_id = i.id
JOIN customers c ON i.customer_id = c.id
LEFT JOIN customers c ON i.customer_id = c.id
LEFT JOIN outlets o ON i.outlet_id = o.id
WHERE p.id = ?");
$stmt->execute([$payment_id]);
echo json_encode($stmt->fetch(PDO::FETCH_ASSOC));
@ -540,7 +542,22 @@ if (isset($_GET['action']) || isset($_POST['action'])) {
recordSaleJournal($transaction_id, $net_amount, date('Y-m-d'), $items_for_journal, $tax_amount);
$db->commit();
echo json_encode(['success' => true, 'invoice_id' => $transaction_id, 'transaction_no' => $transaction_no]);
$outlet = [];
if (!empty($_SESSION['outlet_id'])) {
$stmtO = $db->prepare("SELECT name, phone, address FROM outlets WHERE id = ?");
$stmtO->execute([$_SESSION['outlet_id']]);
$outlet = $stmtO->fetch(PDO::FETCH_ASSOC);
}
echo json_encode([
'success' => true,
'invoice_id' => $transaction_id,
'transaction_no' => $transaction_no,
'outlet_name' => $outlet['name'] ?? null,
'outlet_phone' => $outlet['phone'] ?? null,
'outlet_address' => $outlet['address'] ?? null
]);
} catch (Exception $e) {
$db->rollBack();
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
@ -3614,9 +3631,10 @@ switch ($page) {
$data['total_pages'] = ceil($total_records / $limit);
$data['current_page'] = $page_num;
$stmt = db()->prepare("SELECT q.*, c.name as customer_name
$stmt = db()->prepare("SELECT q.*, c.name as customer_name, o.name as outlet_name, o.address as outlet_address, o.phone as outlet_phone
FROM quotations q
JOIN customers c ON q.customer_id = c.id
LEFT JOIN outlets o ON q.outlet_id = o.id
WHERE $whereSql
ORDER BY q.id DESC
LIMIT $limit OFFSET $offset");
@ -3665,9 +3683,10 @@ switch ($page) {
$data['total_pages'] = ceil($total_records / $limit);
$data['current_page'] = $page_num;
$stmt = db()->prepare("SELECT q.*, s.name as supplier_name
$stmt = db()->prepare("SELECT q.*, s.name as supplier_name, o.name as outlet_name, o.address as outlet_address, o.phone as outlet_phone
FROM lpos q
JOIN suppliers s ON q.supplier_id = s.id
LEFT JOIN outlets o ON q.outlet_id = o.id
WHERE $whereSql
ORDER BY q.id DESC
LIMIT $limit OFFSET $offset");
@ -3736,9 +3755,10 @@ switch ($page) {
$data['total_pages'] = ceil($total_records / $limit);
$data['current_page'] = $page_num;
$stmt = db()->prepare("SELECT v.*, c.name as customer_name, c.tax_id as customer_tax_id, c.phone as customer_phone
$stmt = db()->prepare("SELECT v.*, c.name as customer_name, c.tax_id as customer_tax_id, c.phone as customer_phone, o.name as outlet_name, o.phone as outlet_phone, o.address as outlet_address
FROM $table v
LEFT JOIN $cust_supplier_table c ON v.$cust_supplier_col = c.id
LEFT JOIN outlets o ON v.outlet_id = o.id
WHERE $whereSql
ORDER BY v.id DESC LIMIT $limit OFFSET $offset");
$stmt->execute($params);
@ -6909,7 +6929,7 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
if (result.success) {
const payModal = bootstrap.Modal.getInstance(document.getElementById('posPaymentModal'));
if (payModal) payModal.hide();
this.showReceipt(result.invoice_id, discountAmount, loyaltyRedeemed, result.transaction_no);
this.showReceipt(result.invoice_id, discountAmount, loyaltyRedeemed, result.transaction_no, result.outlet_name, result.outlet_phone, result.outlet_address);
} else {
Swal.fire('Error', result.error, 'error');
btn.disabled = false;
@ -6922,7 +6942,7 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
btn.innerText = originalText;
}
},
showReceipt(invId, discountAmount, loyaltyRedeemed, transactionNo) {
showReceipt(invId, discountAmount, loyaltyRedeemed, transactionNo, outletName, outletPhone, outletAddress) {
const container = document.getElementById('posReceiptContent');
const customerSelect = document.getElementById('posCustomer');
const customerName = (customerSelect && customerSelect.selectedIndex >= 0 && customerSelect.value !== '') ? customerSelect.options[customerSelect.selectedIndex].text : '<?= $translations['ar']['walk_in_customer'] ?> / <?= $translations['en']['walk_in_customer'] ?>';
@ -6963,8 +6983,9 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
return sum + ((item.price * item.qty) * (vatRate / (100 + vatRate)));
}, 0);
const total = subtotal - discountAmount - loyaltyRedeemed;
const companyName = "<?= htmlspecialchars($data['settings']['company_name'] ?? 'Accounting System') ?>";
const companyPhone = "<?= htmlspecialchars($data['settings']['company_phone'] ?? '') ?>";
const companyName = outletName || "<?= htmlspecialchars($data['settings']['company_name'] ?? 'Accounting System') ?>";
const companyPhone = outletPhone || "<?= htmlspecialchars($data['settings']['company_phone'] ?? '') ?>";
const companyAddress = outletAddress ? outletAddress.replace(/\n/g, '<br>') : "<?= nl2br(htmlspecialchars($data['settings']['company_address'] ?? '')) ?>";
const companyVat = "<?= htmlspecialchars($data['settings']['vat_number'] ?? '') ?>";
const companyLogo = "<?= htmlspecialchars($data['settings']['company_logo'] ?? '') ?>";
@ -6973,6 +6994,7 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
<div class="center">
${companyLogo ? `<img src="${companyLogo}" alt="Logo" style="max-height: 60px; width: auto; margin-bottom: 10px; display: block; margin-left: auto; margin-right: auto;">` : ''}
<h5 class="mb-0 fw-bold">${companyName}</h5>
${companyAddress ? `<div>${companyAddress}</div>` : ''}
${companyPhone ? `<div>هاتف / Tel: ${companyPhone}</div>` : ''}
${companyVat ? `<div>الرقم الضريبي / VAT No: ${companyVat}</div>` : ''}
<div class="separator"></div>
@ -11869,6 +11891,14 @@ document.addEventListener('DOMContentLoaded', function() {
document.getElementById('receiptAmount').textContent = parseFloat(data.amount).toFixed(3);
document.getElementById('receiptAmountWords').textContent = data.amount_words;
const rcn = document.getElementById('receiptCompanyName');
if(rcn) rcn.textContent = data.outlet_name || "<?= htmlspecialchars($data['settings']['company_name'] ?? 'Accounting System') ?>";
const rca = document.getElementById('receiptCompanyAddress');
if(rca) {
rca.textContent = data.outlet_address || "<?= nl2br(htmlspecialchars($data['settings']['company_address'] ?? '')) ?>".replace(/<br\s*[\/]?>/gi, '\n');
rca.style.whiteSpace = 'pre-line';
}
// Update labels for Purchase vs Sale
const partyLabel = document.getElementById('receiptPartyLabel');
const againstLabel = document.getElementById('receiptAgainstLabel');
@ -12186,10 +12216,10 @@ document.addEventListener('DOMContentLoaded', function() {
<div class="row align-items-center mb-4">
<div class="col-6">
${logoUrl ? `<img src="${logoUrl}" alt="Logo" style="max-height: 80px;" class="mb-3">` : ''}
<h4 class="fw-bold mb-0">${companySettings.company_name || 'Your Company'}</h4>
<h4 class="fw-bold mb-0">${data.outlet_name || companySettings.company_name || 'Your Company'}</h4>
<p class="text-muted mb-0 small">
${companySettings.company_address || ''}<br>
Phone: ${companySettings.company_phone || ''} | Email: ${companySettings.company_email || ''}
${data.outlet_address ? data.outlet_address.replace(/\n/g, '<br>') : (companySettings.company_address || '').replace(/\n/g, '<br>')}<br>
Phone: ${data.outlet_phone || companySettings.company_phone || ''} | Email: ${companySettings.company_email || ''}
${companySettings.tax_number ? `<br>TRN: ${companySettings.tax_number}` : ''}
</p>
</div>
@ -12377,10 +12407,10 @@ document.addEventListener('DOMContentLoaded', function() {
// Company Logo and Header Construction
const logoUrl = companySettings.company_logo || '';
const logoImg = logoUrl ? `<img src="${logoUrl}" alt="Logo" class="invoice-logo mb-3">` : '';
const companyName = companySettings.company_name || 'Accounting System';
const companyAddress = (companySettings.company_address || '').replace(/\n/g, '<br>');
const companyName = data.outlet_name || companySettings.company_name || 'Accounting System';
const companyAddress = data.outlet_address ? data.outlet_address.replace(/\n/g, '<br>') : (companySettings.company_address || '').replace(/\n/g, '<br>');
const companyVat = companySettings.vat_number ? `<p class="text-muted small mb-0">VAT: ${companySettings.vat_number}</p>` : '';
const companyPhone = companySettings.company_phone ? `<p class="text-muted small mb-0">Tel: ${companySettings.company_phone}</p>` : '';
const companyPhone = data.outlet_phone ? `<p class="text-muted small mb-0">Tel: ${data.outlet_phone}</p>` : (companySettings.company_phone ? `<p class="text-muted small mb-0">Tel: ${companySettings.company_phone}</p>` : '');
// Quotation Header Construction
const quotDate = data.quotation_date;
@ -13839,12 +13869,10 @@ document.addEventListener('DOMContentLoaded', function() {
?>
<img src="<?= htmlspecialchars($logo) ?>" alt="Logo" class="invoice-logo mb-3">
<?php endif; ?>
<h3 class="mb-1 fw-bold"><?= htmlspecialchars($data['settings']['company_name'] ?? 'Accounting System') ?></h3>
<p class="text-muted small mb-0"><?= nl2br(htmlspecialchars($data['settings']['company_address'] ?? '')) ?></p>
<h3 class="mb-1 fw-bold" id="printCompanyName"><?= htmlspecialchars($data['settings']['company_name'] ?? 'Accounting System') ?></h3>
<p class="text-muted small mb-0" id="printCompanyAddress"><?= nl2br(htmlspecialchars($data['settings']['company_address'] ?? '')) ?></p>
<p class="text-muted small mb-0">VAT: <?= htmlspecialchars($data['settings']['vat_number'] ?? '') ?></p>
<?php if (!empty($data['settings']['company_phone'])): ?>
<p class="text-muted small mb-0">Tel: <?= htmlspecialchars($data['settings']['company_phone']) ?></p>
<?php endif; ?>
<p class="text-muted small mb-0" id="printCompanyPhoneContainer" style="<?= empty($data['settings']['company_phone']) ? 'display:none;' : '' ?>">Tel: <span id="printCompanyPhone"><?= htmlspecialchars($data['settings']['company_phone'] ?? '') ?></span></p>
</div>
<div class="col-6 text-end">
<h1 class="invoice-title fw-bold mb-0 text-uppercase">Tax Invoice / فاتورة ضريبية</h1>
@ -14037,8 +14065,8 @@ document.addEventListener('DOMContentLoaded', function() {
if ($logo): ?>
<img src="<?= htmlspecialchars($logo) ?>" alt="Logo" class="invoice-logo mb-3">
<?php endif; ?>
<h3 class="mb-1 fw-bold"><?= htmlspecialchars($data['settings']['company_name'] ?? 'Accounting System') ?></h3>
<p class="text-muted small mb-0"><?= nl2br(htmlspecialchars($data['settings']['company_address'] ?? '')) ?></p>
<h3 class="mb-1 fw-bold" id="receiptCompanyName"><?= htmlspecialchars($data['settings']['company_name'] ?? 'Accounting System') ?></h3>
<p class="text-muted small mb-0" id="receiptCompanyAddress"><?= nl2br(htmlspecialchars($data['settings']['company_address'] ?? '')) ?></p>
<hr class="my-4">
<h4 class="letter-spacing-2 fw-bold text-uppercase">Payment Receipt / سند قبض</h4>
</div>
@ -14665,6 +14693,17 @@ document.addEventListener('DOMContentLoaded', function() {
window.viewAndPrintA4Invoice = function(data, autoPrint = true) {
if (!data) return;
// Reuse view logic
document.getElementById('printCompanyName').textContent = data.outlet_name || "<?= htmlspecialchars($data['settings']['company_name'] ?? 'Accounting System') ?>";
document.getElementById('printCompanyAddress').textContent = data.outlet_address || "<?= nl2br(htmlspecialchars($data['settings']['company_address'] ?? '')) ?>".replace(/<br\s*[\/]?>/gi, '\n');
document.getElementById('printCompanyAddress').style.whiteSpace = 'pre-line';
const cPhone = data.outlet_phone || "<?= htmlspecialchars($data['settings']['company_phone'] ?? '') ?>";
if (cPhone) {
document.getElementById('printCompanyPhone').textContent = cPhone;
document.getElementById('printCompanyPhoneContainer').style.display = 'block';
} else {
document.getElementById('printCompanyPhoneContainer').style.display = 'none';
}
document.getElementById('invNumber').textContent = 'INV-' + data.id.toString().padStart(5, '0');
document.getElementById('invDate').textContent = data.invoice_date;
document.getElementById('invPaymentType').textContent = data.payment_type ? data.payment_type.toUpperCase() : 'CASH';
@ -14737,7 +14776,7 @@ document.addEventListener('DOMContentLoaded', function() {
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 companyName = data.outlet_name || <?= json_encode($data['settings']['company_name'] ?? 'Accounting System') ?>;
const vatNo = <?= json_encode($data['settings']['vat_number'] ?? '') ?>;
const qrData = `Seller: ${companyName}\nVAT: ${vatNo}\nInvoice: INV-${data.id.toString().padStart(5, '0')}\nDate: ${data.invoice_date}\nTotal: ${grandTotalValue.toFixed(3)}`;
const qrUrl = `https://api.qrserver.com/v1/create-qr-code/?size=100x100&data=${encodeURIComponent(qrData)}`;
@ -14795,8 +14834,9 @@ document.addEventListener('DOMContentLoaded', function() {
}, 0);
const subtotal = inv.items.reduce((sum, item) => sum + (item.unit_price * item.quantity), 0);
const companyName = "<?= htmlspecialchars($data['settings']['company_name'] ?? 'Accounting System') ?>";
const companyPhone = "<?= htmlspecialchars($data['settings']['company_phone'] ?? '') ?>";
const companyName = inv.outlet_name || "<?= htmlspecialchars($data['settings']['company_name'] ?? 'Accounting System') ?>";
const companyPhone = inv.outlet_phone || "<?= htmlspecialchars($data['settings']['company_phone'] ?? '') ?>";
const companyAddress = inv.outlet_address ? inv.outlet_address.replace(/\n/g, '<br>') : "<?= nl2br(htmlspecialchars($data['settings']['company_address'] ?? '')) ?>";
const companyVat = "<?= htmlspecialchars($data['settings']['vat_number'] ?? '') ?>";
const companyLogo = "<?= htmlspecialchars($data['settings']['company_logo'] ?? '') ?>";
@ -14805,6 +14845,7 @@ document.addEventListener('DOMContentLoaded', function() {
<div class="center">
${companyLogo ? `<img src="${companyLogo}" alt="Logo" style="max-height: 60px; width: auto; margin-bottom: 10px; display: block; margin-left: auto; margin-right: auto;">` : ''}
<h5 class="mb-0 fw-bold">${companyName}</h5>
${companyAddress ? `<div>${companyAddress}</div>` : ''}
${companyPhone ? `<div>Tel: ${companyPhone}</div>` : ''}
${companyVat ? `<div>VAT: ${companyVat}</div>` : ''}
<div class="separator"></div>