289 lines
9.4 KiB
PHP
289 lines
9.4 KiB
PHP
<?php
|
|
require_once __DIR__ . '/includes/app.php';
|
|
$user = require_permission('sales', 'show');
|
|
$id = (int) ($_GET['id'] ?? 0);
|
|
$sale = null;
|
|
$dbError = null;
|
|
if ($id > 0) {
|
|
try {
|
|
$sale = fetch_sale($id);
|
|
} catch (Throwable $e) {
|
|
$dbError = $e->getMessage();
|
|
}
|
|
}
|
|
|
|
if (!$sale) {
|
|
die("Sale not found.");
|
|
}
|
|
|
|
// Receipt Configuration
|
|
$storeName = current_lang() === 'ar' ? get_setting('company_name_ar', 'حلوى الريامي') : get_setting('company_name_en', 'Al Riyami Sweets');
|
|
$storeAddress = get_setting('company_address', '');
|
|
$vatNo = get_setting('company_vat_number', '300123456789012');
|
|
$registerNo = 'REG-01';
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="<?= current_lang() ?>" dir="<?= current_lang() === 'ar' ? 'rtl' : 'ltr' ?>">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title><?= h(tr('إيصال', 'Receipt')) ?> #<?= h($sale['receipt_no']) ?></title>
|
|
<style>
|
|
/* 80mm Receipt Styles */
|
|
body {
|
|
font-family: 'Courier New', Courier, monospace;
|
|
font-size: 13px;
|
|
color: #000;
|
|
background: #f8f9fa;
|
|
margin: 0;
|
|
padding: 20px;
|
|
display: flex;
|
|
justify-content: center;
|
|
}
|
|
.receipt-container {
|
|
width: 80mm;
|
|
max-width: 100%;
|
|
background: #fff;
|
|
padding: 15px;
|
|
box-shadow: 0 0 10px rgba(0,0,0,0.1);
|
|
}
|
|
@media print {
|
|
body {
|
|
background: #fff;
|
|
padding: 0;
|
|
margin: 0;
|
|
}
|
|
.receipt-container {
|
|
box-shadow: none;
|
|
width: 100%;
|
|
padding: 10px;
|
|
}
|
|
.no-print {
|
|
display: none !important;
|
|
}
|
|
@page {
|
|
margin: 0;
|
|
size: 80mm 297mm; /* standard 80mm paper roll size */
|
|
}
|
|
}
|
|
.text-center { text-align: center; }
|
|
.text-right { text-align: right; }
|
|
.text-left { text-align: left; }
|
|
.font-bold { font-weight: bold; }
|
|
|
|
.logo-area {
|
|
margin-bottom: 10px;
|
|
}
|
|
.logo-area img {
|
|
max-width: 60px;
|
|
filter: grayscale(100%);
|
|
}
|
|
|
|
.header-info { margin-bottom: 15px; line-height: 1.4; }
|
|
.header-info div { margin-bottom: 2px; }
|
|
|
|
.divider {
|
|
border-bottom: 1px dashed #000;
|
|
margin: 10px 0;
|
|
}
|
|
|
|
.sale-info {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
margin-bottom: 3px;
|
|
}
|
|
|
|
table.items {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin-top: 10px;
|
|
}
|
|
table.items th, table.items td {
|
|
padding: 4px 0;
|
|
vertical-align: top;
|
|
}
|
|
table.items th {
|
|
border-bottom: 1px dashed #000;
|
|
font-weight: bold;
|
|
}
|
|
.col-qty { width: 15%; text-align: center; }
|
|
.col-price { width: 25%; text-align: <?= current_lang() === 'ar' ? 'left' : 'right' ?>; }
|
|
.col-total { width: 25%; text-align: <?= current_lang() === 'ar' ? 'left' : 'right' ?>; font-weight: bold; }
|
|
.col-name { width: 35%; }
|
|
|
|
.totals-area {
|
|
margin-top: 10px;
|
|
}
|
|
.totals-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
font-size: 14px;
|
|
margin-bottom: 4px;
|
|
}
|
|
.totals-row.grand-total {
|
|
font-size: 18px;
|
|
font-weight: bold;
|
|
border-top: 1px dashed #000;
|
|
border-bottom: 1px dashed #000;
|
|
padding: 8px 0;
|
|
margin-top: 5px;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.footer-msg {
|
|
text-align: center;
|
|
margin-top: 15px;
|
|
font-size: 12px;
|
|
line-height: 1.4;
|
|
}
|
|
.barcode {
|
|
text-align: center;
|
|
margin-top: 10px;
|
|
font-family: 'Libre Barcode 39', cursive;
|
|
font-size: 40px;
|
|
}
|
|
|
|
/* Interactive actions */
|
|
.print-actions {
|
|
position: fixed;
|
|
bottom: 20px;
|
|
right: 20px;
|
|
display: flex;
|
|
gap: 10px;
|
|
}
|
|
.btn {
|
|
background: #0d6efd;
|
|
color: #fff;
|
|
border: none;
|
|
padding: 10px 20px;
|
|
border-radius: 5px;
|
|
cursor: pointer;
|
|
font-family: Arial, sans-serif;
|
|
font-size: 14px;
|
|
text-decoration: none;
|
|
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
|
}
|
|
.btn-secondary { background: #6c757d; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="receipt-container">
|
|
|
|
<!-- Logo -->
|
|
<div class="text-center logo-area">
|
|
<!-- SVG Placeholder Logo -->
|
|
<?php if (get_setting('company_logo')): ?>
|
|
<img src="<?= h(get_setting('company_logo')) ?>" alt="Logo" style="max-height: 80px; max-width: 150px;">
|
|
<?php else: ?>
|
|
<svg width="60" height="60" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<rect width="100" height="100" rx="20" fill="#000"/>
|
|
<path d="M50 20 L80 80 L20 80 Z" fill="#fff"/>
|
|
</svg>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<!-- Store Info -->
|
|
<div class="text-center header-info">
|
|
<div class="font-bold" style="font-size: 16px;"><?= h($storeName) ?></div>
|
|
<div><?= h($storeAddress) ?></div>
|
|
<div>VAT: <?= h($vatNo) ?></div>
|
|
<div><?= h(tr('هاتف', 'Tel')) ?>: <?= h(get_setting('company_phone', '')) ?></div>
|
|
</div>
|
|
|
|
<div class="divider"></div>
|
|
|
|
<!-- Receipt Meta -->
|
|
<div class="sale-info">
|
|
<span><?= h(tr('رقم الفاتورة', 'Receipt No')) ?>:</span>
|
|
<span class="font-bold"><?= h($sale['receipt_no']) ?></span>
|
|
</div>
|
|
<div class="sale-info">
|
|
<span><?= h(tr('التاريخ', 'Date')) ?>:</span>
|
|
<span><?= h(date('Y-m-d H:i', strtotime((string)$sale['sale_date']))) ?></span>
|
|
</div>
|
|
<div class="sale-info">
|
|
<span><?= h(tr('الكاشير', 'Cashier')) ?>:</span>
|
|
<span><?= h($sale['cashier_name']) ?> (<?= h($registerNo) ?>)</span>
|
|
</div>
|
|
<?php if(!empty($sale['customer_name'])): ?>
|
|
<div class="sale-info">
|
|
<span><?= h(tr('العميل', 'Customer')) ?>:</span>
|
|
<span><?= h($sale['customer_name']) ?></span>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<div class="divider"></div>
|
|
|
|
<!-- Items -->
|
|
<table class="items">
|
|
<thead>
|
|
<tr>
|
|
<th class="text-<?= current_lang() === 'ar' ? 'right' : 'left' ?> col-name"><?= h(tr('الصنف', 'Item')) ?></th>
|
|
<th class="col-qty"><?= h(tr('كمية', 'Qty')) ?></th>
|
|
<th class="col-price"><?= h(tr('سعر', 'Price')) ?></th>
|
|
<th class="col-total"><?= h(tr('إجمالي', 'Total')) ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($sale['items'] as $item):
|
|
$name = current_lang() === 'ar' ? ($item['name_ar'] ?? $item['sku']) : ($item['name_en'] ?? $item['sku']);
|
|
?>
|
|
<tr>
|
|
<td class="col-name"><?= h($name) ?></td>
|
|
<td class="col-qty"><?= h($item['qty']) ?></td>
|
|
<td class="col-price"><?= number_format((float)$item['price'], 3) ?></td>
|
|
<td class="col-total"><?= number_format((float)$item['line_total'], 3) ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
|
|
<div class="divider"></div>
|
|
|
|
<!-- Totals -->
|
|
<div class="totals-area">
|
|
<div class="totals-row">
|
|
<span><?= h(tr('المجموع الفرعي', 'Subtotal')) ?></span>
|
|
<span><?= number_format((float)$sale['subtotal'], 3) ?></span>
|
|
</div>
|
|
<div class="totals-row">
|
|
<span><?= h(tr('ضريبة القيمة المضافة (مشمولة)', 'VAT (Inclusive)')) ?></span>
|
|
<span><?= number_format((float)($sale['vat_amount'] ?? 0), 3) ?></span>
|
|
</div>
|
|
<div class="totals-row grand-total">
|
|
<span><?= h(tr('الإجمالي', 'Total')) ?></span>
|
|
<span><?= number_format((float)$sale['total_amount'], 3) ?> <?= h(tr('ر.ع', 'OMR')) ?></span>
|
|
</div>
|
|
<div class="totals-row">
|
|
<span><?= h(tr('طريقة الدفع', 'Payment Method')) ?></span>
|
|
<span><?= h(ucfirst((string)$sale['payment_method'])) ?></span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<div class="footer-msg">
|
|
<p class="font-bold"><?= h(tr('شكراً لتسوقكم معنا!', 'Thank you for shopping with us!')) ?></p>
|
|
<p><?= h(tr('البضاعة المباعة ترد وتستبدل خلال 14 يوماً من تاريخ الشراء', 'Items can be returned or exchanged within 14 days of purchase.')) ?></p>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- Print Actions -->
|
|
<div class="print-actions no-print">
|
|
<a href="pos.php" class="btn btn-secondary"><?= h(tr('رجوع لـ POS', 'Back to POS')) ?></a>
|
|
<button onclick="window.print()" class="btn"><?= h(tr('طباعة الآن', 'Print Now')) ?></button>
|
|
</div>
|
|
|
|
<script>
|
|
// Auto print when page loads
|
|
window.onload = function() {
|
|
setTimeout(() => {
|
|
window.print();
|
|
}, 500);
|
|
};
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|