217 lines
8.7 KiB
PHP
217 lines
8.7 KiB
PHP
<?php
|
|
session_start();
|
|
require_once __DIR__ . '/db/config.php';
|
|
require_once __DIR__ . '/includes/lang.php';
|
|
|
|
if (($_SESSION['role'] ?? 'cashier') === 'limited_viewer') { die('Access Denied'); }
|
|
|
|
$order_id = $_GET['id'] ?? null;
|
|
if (!$order_id) {
|
|
die("Order ID is required");
|
|
}
|
|
|
|
// Fetch Global Company Info
|
|
$stmt = db()->query("SELECT * FROM companies LIMIT 1");
|
|
$company = $stmt->fetch();
|
|
|
|
// Fetch Order Details with Customer and Branch info
|
|
$stmt = db()->prepare("SELECT o.*,
|
|
c.name_en as customer_name_en, c.name_ar as customer_name_ar, c.phone as customer_phone,
|
|
b.name_en as branch_name_en, b.name_ar as branch_name_ar, b.address_en as branch_address_en, b.address_ar as branch_address_ar, b.phone as branch_phone
|
|
FROM orders o
|
|
LEFT JOIN customers c ON o.customer_id = c.id
|
|
LEFT JOIN branches b ON o.branch_id = b.id
|
|
WHERE o.id = ?");
|
|
$stmt->execute([$order_id]);
|
|
$order = $stmt->fetch();
|
|
|
|
if (!$order) {
|
|
die("Order not found");
|
|
}
|
|
|
|
// Fetch items for this order
|
|
$stmt = db()->prepare("SELECT oi.*, i.name_en, i.name_ar, s.name_en as service_en, s.name_ar as service_ar
|
|
FROM order_items oi
|
|
JOIN items i ON oi.item_id = i.id
|
|
JOIN services s ON oi.service_id = s.id
|
|
WHERE oi.order_id = ?");
|
|
$stmt->execute([$order_id]);
|
|
$items = $stmt->fetchAll();
|
|
|
|
$lang = $_SESSION['lang'] ?? 'en';
|
|
|
|
function format_currency($amount) {
|
|
return number_format($amount, decimals()) . ' ' . currency();
|
|
}
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="<?= $lang ?>" dir="<?= is_arabic() ? 'rtl' : 'ltr' ?>">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title><?= __('thermal_receipt') ?> #<?= $order['order_number'] ?? $order['id'] ?></title>
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;600&family=IBM+Plex+Sans+Arabic:wght@400;600&display=swap" rel="stylesheet">
|
|
<style>
|
|
body {
|
|
font-family: 'IBM Plex Sans', 'IBM Plex Sans Arabic', sans-serif;
|
|
background: #f8f9fa;
|
|
color: #333;
|
|
-webkit-print-color-adjust: exact;
|
|
}
|
|
.receipt-container {
|
|
width: 80mm;
|
|
background: white;
|
|
margin: 20px auto;
|
|
padding: 10px;
|
|
box-shadow: 0 0 10px rgba(0,0,0,0.1);
|
|
}
|
|
@media print {
|
|
body { background: white; margin: 0; padding: 0; width: 80mm; }
|
|
.receipt-container { margin: 0; box-shadow: none; width: 80mm; padding: 0; }
|
|
.no-print { display: none; }
|
|
}
|
|
.header { text-align: center; border-bottom: 1px dashed #ccc; padding-bottom: 10px; margin-bottom: 10px; }
|
|
.item-row { display: flex; justify-content: space-between; margin-bottom: 5px; font-size: 0.9rem; }
|
|
.item-name { flex-grow: 1; }
|
|
.item-price { text-align: right; margin-left: 10px; }
|
|
.item-service { font-size: 0.75rem; color: #666; }
|
|
.totals { border-top: 1px dashed #ccc; padding-top: 10px; margin-top: 10px; }
|
|
.total-row { display: flex; justify-content: space-between; font-weight: 600; font-size: 1rem; }
|
|
.info-row { font-size: 0.8rem; margin-bottom: 3px; display: flex; justify-content: space-between; }
|
|
.barcode { text-align: center; margin-top: 15px; }
|
|
.arabic-text { font-family: 'IBM Plex Sans Arabic', sans-serif; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="no-print text-center my-3">
|
|
<button onclick="window.print()" class="btn btn-primary btn-sm px-4"><?= __('print_receipt') ?></button>
|
|
<a href="pos.php" class="btn btn-outline-secondary btn-sm ms-2"><?= __('back_to_pos') ?></a>
|
|
</div>
|
|
|
|
<div class="receipt-container">
|
|
<div class="header">
|
|
<?php if (!empty($company['logo'])): ?>
|
|
<img src="<?= htmlspecialchars($company['logo']) ?>" alt="Logo" style="max-height: 80px; max-width: 100%; margin-bottom: 10px;">
|
|
<?php endif; ?>
|
|
<h5 class="fw-bold m-0"><?= htmlspecialchars($company['name_en'] ?? 'Laundry POS') ?></h5>
|
|
<?php if (!empty($company['name_ar'])): ?>
|
|
<div class="arabic-text small"><?= htmlspecialchars($company['name_ar']) ?></div>
|
|
<?php endif; ?>
|
|
<div class="small mt-1"><?= htmlspecialchars($order['branch_name_en']) ?> / <span class="arabic-text"><?= htmlspecialchars($order['branch_name_ar']) ?></span></div>
|
|
<div class="small"><?= htmlspecialchars($order['branch_phone']) ?></div>
|
|
<?php if (!empty($company['ctr_no'])): ?>
|
|
<div class="small"><?= __('ctr_no') ?>: <?= htmlspecialchars($company['ctr_no']) ?></div>
|
|
<?php endif; ?>
|
|
<?php if (!empty($company['vat_no'])): ?>
|
|
<div class="small"><?= __('vat_no') ?>: <?= htmlspecialchars($company['vat_no']) ?></div>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<div class="info-row">
|
|
<span><?= __('date') ?>:</span>
|
|
<span><?= date('Y-m-d H:i', strtotime($order['created_at'])) ?></span>
|
|
</div>
|
|
<div class="info-row">
|
|
<span><?= __('order_no') ?>:</span>
|
|
<span class="fw-bold"><?= $order['order_number'] ?? $order['id'] ?></span>
|
|
</div>
|
|
<div class="info-row">
|
|
<span><?= __('customer') ?>:</span>
|
|
<span><?= $order['customer_name_en'] ?></span>
|
|
</div>
|
|
<div class="info-row">
|
|
<span><?= __('phone') ?>:</span>
|
|
<span><?= $order['customer_phone'] ?></span>
|
|
</div>
|
|
|
|
<div class="mt-3 border-top pt-2">
|
|
<?php foreach($items as $item):
|
|
?>
|
|
<div class="mb-2">
|
|
<div class="item-row">
|
|
<div class="item-name"><?= $item['name_en'] ?> / <span class="arabic-text"><?= $item['name_ar'] ?></span> x <?= $item['quantity'] ?></div>
|
|
<div class="item-price"><?= format_currency($item['subtotal']) ?></div>
|
|
</div>
|
|
<div class="item-service"><?= $item['service_en'] ?> / <span class="arabic-text"><?= $item['service_ar'] ?></span></div>
|
|
</div>
|
|
<?php endforeach;
|
|
?>
|
|
</div>
|
|
|
|
<?php
|
|
$calculated_subtotal = 0;
|
|
foreach($items as $item) {
|
|
$calculated_subtotal += $item['subtotal'];
|
|
}
|
|
?>
|
|
<div class="totals">
|
|
<div class="info-row">
|
|
<span><?= __('subtotal') ?>:</span>
|
|
<span><?= format_currency($calculated_subtotal) ?></span>
|
|
</div>
|
|
<?php if ($order['loyalty_discount'] > 0):
|
|
?>
|
|
<div class="info-row">
|
|
<span><?= __('loyalty_discount') ?>:</span>
|
|
<span>-<?= format_currency($order['loyalty_discount']) ?></span>
|
|
</div>
|
|
<?php endif;
|
|
?>
|
|
<div class="info-row">
|
|
<span><?= __('vat') ?>:</span>
|
|
<span><?= format_currency($order['vat_total'] ?? 0) ?></span>
|
|
</div>
|
|
<div class="total-row mt-2">
|
|
<span><?= __('total') ?>:</span>
|
|
<span><?= format_currency($order['total_price']) ?></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4 text-center small">
|
|
<div>Thank you for choosing us!</div>
|
|
<div class="arabic-text">شكراً لاختياركم لنا!</div>
|
|
</div>
|
|
|
|
<div class="mt-3 text-center">
|
|
<div class="small fw-bold mb-1">Rate Us / <span class="arabic-text">قيمنا</span></div>
|
|
<div id="qrcode" class="d-flex justify-content-center"></div>
|
|
</div>
|
|
|
|
<div class="barcode">
|
|
<svg id="barcode"></svg>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/jsbarcode@3.11.0/dist/JsBarcode.all.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
|
|
<script>
|
|
JsBarcode("#barcode", "<?= $order['order_number'] ?? $order['id'] ?>", {
|
|
format: "CODE128",
|
|
lineColor: "#000",
|
|
width: 1.5,
|
|
height: 40,
|
|
displayValue: false
|
|
});
|
|
|
|
<?php
|
|
$scheme = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') ? "https" : "http";
|
|
$host = $_SERVER['HTTP_HOST'];
|
|
$base_dir = rtrim(dirname($_SERVER['SCRIPT_NAME']), '/');
|
|
$rate_url = $scheme . "://" . $host . $base_dir . "/rate.php?branch_id=" . ($order['branch_id'] ?? 1);
|
|
?>
|
|
new QRCode(document.getElementById("qrcode"), {
|
|
text: "<?= $rate_url ?>",
|
|
width: 80,
|
|
height: 80,
|
|
colorDark : "#000000",
|
|
colorLight : "#ffffff",
|
|
correctLevel : QRCode.CorrectLevel.M
|
|
});
|
|
</script>
|
|
<script>
|
|
window.onload = function() { setTimeout(() => window.print(), 500); };
|
|
</script>
|
|
</body>
|
|
</html>
|