missing migrations

This commit is contained in:
Flatlogic Bot 2026-02-27 01:20:05 +00:00
parent ac32148f05
commit 8faf7adbb6
21 changed files with 1411 additions and 62 deletions

View File

@ -1,5 +1,6 @@
<?php <?php
require_once __DIR__ . "/../includes/functions.php"; require_once __DIR__ . "/../includes/functions.php";
require_once __DIR__ . "/../db/config.php";
require_permission("ads"); require_permission("ads");
require_once __DIR__ . '/../db/config.php'; require_once __DIR__ . '/../db/config.php';
$pdo = db(); $pdo = db();

View File

@ -1,5 +1,6 @@
<?php <?php
require_once __DIR__ . "/../includes/functions.php"; require_once __DIR__ . "/../includes/functions.php";
require_once __DIR__ . "/../db/config.php";
require_permission("areas_view"); require_permission("areas_view");
require_once __DIR__ . '/../db/config.php'; require_once __DIR__ . '/../db/config.php';
$pdo = db(); $pdo = db();

View File

@ -1,5 +1,6 @@
<?php <?php
require_once __DIR__ . "/../includes/functions.php"; require_once __DIR__ . "/../includes/functions.php";
require_once __DIR__ . "/../db/config.php";
require_permission("settings_view"); require_permission("settings_view");
require_once __DIR__ . '/../db/config.php'; require_once __DIR__ . '/../db/config.php';
$pdo = db(); $pdo = db();

View File

@ -1,5 +1,6 @@
<?php <?php
require_once __DIR__ . "/../includes/functions.php"; require_once __DIR__ . "/../includes/functions.php";
require_once __DIR__ . "/../db/config.php";
require_permission("settings_view"); require_permission("settings_view");
require_once __DIR__ . '/../db/config.php'; require_once __DIR__ . '/../db/config.php';
$pdo = db(); $pdo = db();

View File

@ -1,5 +1,6 @@
<?php <?php
require_once __DIR__ . "/../includes/functions.php"; require_once __DIR__ . "/../includes/functions.php";
require_once __DIR__ . "/../db/config.php";
require_permission("expense_categories_view"); require_permission("expense_categories_view");
require_once __DIR__ . '/../db/config.php'; require_once __DIR__ . '/../db/config.php';
$pdo = db(); $pdo = db();

View File

@ -1,5 +1,6 @@
<?php <?php
require_once __DIR__ . "/../includes/functions.php"; require_once __DIR__ . "/../includes/functions.php";
require_once __DIR__ . "/../db/config.php";
require_permission("settings_view"); require_permission("settings_view");
require_once __DIR__ . '/../db/config.php'; require_once __DIR__ . '/../db/config.php';
require_once __DIR__ . '/../includes/WablasService.php'; require_once __DIR__ . '/../includes/WablasService.php';

View File

@ -1,5 +1,6 @@
<?php <?php
require_once __DIR__ . "/../includes/functions.php"; require_once __DIR__ . "/../includes/functions.php";
require_once __DIR__ . "/../db/config.php";
require_permission("loyalty_view"); require_permission("loyalty_view");
require_once __DIR__ . '/../db/config.php'; require_once __DIR__ . '/../db/config.php';
$pdo = db(); $pdo = db();

View File

@ -48,6 +48,7 @@ foreach ($items as $item) {
$vat_or_discount = (float)$order['discount']; $vat_or_discount = (float)$order['discount'];
$company_settings = get_company_settings(); $company_settings = get_company_settings();
$vat_rate = (float)($company_settings['vat_rate'] ?? 0);
?> ?>
<style> <style>
@ -192,18 +193,14 @@ $company_settings = get_company_settings();
<tr> <tr>
<td colspan="3" class="text-end py-3 ps-4"> <td colspan="3" class="text-end py-3 ps-4">
<div class="text-muted mb-1">Subtotal</div> <div class="text-muted mb-1">Subtotal</div>
<?php if ($vat_or_discount != 0): ?> <div class="text-muted mb-1"><?= ($vat_or_discount >= 0) ? "VAT ($vat_rate%)" : 'Discount' ?></div>
<div class="text-muted mb-1"><?= $vat_or_discount > 0 ? 'VAT' : 'Discount' ?></div>
<?php endif; ?>
<h5 class="fw-bold mb-0 text-dark">Total Amount</h5> <h5 class="fw-bold mb-0 text-dark">Total Amount</h5>
</td> </td>
<td class="text-end py-3 pe-4"> <td class="text-end py-3 pe-4">
<div class="mb-1"><?= format_currency($subtotal) ?></div> <div class="mb-1"><?= format_currency($subtotal) ?></div>
<?php if ($vat_or_discount != 0): ?>
<div class="mb-1 <?= $vat_or_discount < 0 ? 'text-danger' : 'text-primary' ?>"> <div class="mb-1 <?= $vat_or_discount < 0 ? 'text-danger' : 'text-primary' ?>">
<?= ($vat_or_discount > 0 ? '+' : '') . format_currency($vat_or_discount) ?> <?= ($vat_or_discount > 0 ? '+' : '') . format_currency($vat_or_discount) ?>
</div> </div>
<?php endif; ?>
<h5 class="fw-bold mb-0 text-primary"><?= format_currency($order['total_amount']) ?></h5> <h5 class="fw-bold mb-0 text-primary"><?= format_currency($order['total_amount']) ?></h5>
</td> </td>
</tr> </tr>
@ -429,6 +426,7 @@ function printThermalReceipt() {
const subtotal = data.total - data.vat; const subtotal = data.total - data.vat;
const logoHtml = COMPANY_SETTINGS.logo_url ? `<img src="${BASE_URL}${COMPANY_SETTINGS.logo_url}" style="max-height: 80px; max-width: 150px; margin-bottom: 10px;">` : ''; const logoHtml = COMPANY_SETTINGS.logo_url ? `<img src="${BASE_URL}${COMPANY_SETTINGS.logo_url}" style="max-height: 80px; max-width: 150px; margin-bottom: 10px;">` : '';
const vatRate = COMPANY_SETTINGS.vat_rate || 0;
const html = ` const html = `
<html dir="ltr"> <html dir="ltr">
@ -523,11 +521,10 @@ function printThermalReceipt() {
<td>Subtotal / ${tr['Subtotal']}</td> <td>Subtotal / ${tr['Subtotal']}</td>
<td style="text-align: right">${formatCurrency(subtotal)}</td> <td style="text-align: right">${formatCurrency(subtotal)}</td>
</tr> </tr>
${Math.abs(data.vat) > 0 ? `
<tr> <tr>
<td>${data.vat < 0 ? 'Discount' : 'VAT'} / ${tr['VAT']}</td> <td>${data.vat < 0 ? 'Discount' : 'VAT (' + vatRate + '%)'} / ${tr['VAT']}</td>
<td style="text-align: right">${data.vat < 0 ? '-' : '+'}${formatCurrency(Math.abs(data.vat))}</td> <td style="text-align: right">${data.vat < 0 ? '-' : '+'}${formatCurrency(Math.abs(data.vat))}</td>
</tr>` : ''} </tr>
<tr style="font-weight: bold; font-size: 18px;"> <tr style="font-weight: bold; font-size: 18px;">
<td style="padding-top: 10px;">TOTAL / ${tr['TOTAL']}</td> <td style="padding-top: 10px;">TOTAL / ${tr['TOTAL']}</td>
<td style="text-align: right; padding-top: 10px;">${formatCurrency(data.total)}</td> <td style="text-align: right; padding-top: 10px;">${formatCurrency(data.total)}</td>

View File

@ -1,5 +1,6 @@
<?php <?php
require_once __DIR__ . "/../includes/functions.php"; require_once __DIR__ . "/../includes/functions.php";
require_once __DIR__ . "/../db/config.php";
require_permission("outlets_view"); require_permission("outlets_view");
require_once __DIR__ . '/../db/config.php'; require_once __DIR__ . '/../db/config.php';
$pdo = db(); $pdo = db();

View File

@ -1,5 +1,6 @@
<?php <?php
require_once __DIR__ . "/../includes/functions.php"; require_once __DIR__ . "/../includes/functions.php";
require_once __DIR__ . "/../db/config.php";
require_permission("payment_types_view"); require_permission("payment_types_view");
require_once __DIR__ . '/../db/config.php'; require_once __DIR__ . '/../db/config.php';
$pdo = db(); $pdo = db();

View File

@ -1,5 +1,6 @@
<?php <?php
require_once __DIR__ . "/../includes/functions.php"; require_once __DIR__ . "/../includes/functions.php";
require_once __DIR__ . "/../db/config.php";
require_permission("purchases_view"); require_permission("purchases_view");
require_once __DIR__ . '/../db/config.php'; require_once __DIR__ . '/../db/config.php';
$pdo = db(); $pdo = db();

View File

@ -1,5 +1,6 @@
<?php <?php
require_once __DIR__ . "/../includes/functions.php"; require_once __DIR__ . "/../includes/functions.php";
require_once __DIR__ . "/../db/config.php";
require_permission("ratings_view"); require_permission("ratings_view");
require_once __DIR__ . '/../db/config.php'; require_once __DIR__ . '/../db/config.php';
$pdo = db(); $pdo = db();

View File

@ -1,5 +1,6 @@
<?php <?php
require_once __DIR__ . "/../includes/functions.php"; require_once __DIR__ . "/../includes/functions.php";
require_once __DIR__ . "/../db/config.php";
require_permission("suppliers_view"); require_permission("suppliers_view");
require_once __DIR__ . '/../db/config.php'; require_once __DIR__ . '/../db/config.php';
$pdo = db(); $pdo = db();

View File

@ -1,7 +1,7 @@
<?php <?php
require_once __DIR__ . '/../db/config.php';
require_once __DIR__ . "/../includes/functions.php"; require_once __DIR__ . "/../includes/functions.php";
require_permission("tables_view"); require_permission("tables_view");
require_once __DIR__ . '/../db/config.php';
$pdo = db(); $pdo = db();
$message = ''; $message = '';
@ -206,7 +206,7 @@ $baseUrl = $protocol . $host . $project_root;
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary">Save Table</button> <button type="submit" class="btn btn-primary">Save Table</button>
</div> </div>
</form> </form>
@ -217,76 +217,96 @@ $baseUrl = $protocol . $host . $project_root;
<!-- QR Modal --> <!-- QR Modal -->
<div class="modal fade" id="qrModal" tabindex="-1" aria-hidden="true"> <div class="modal fade" id="qrModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-sm"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title">Table QR Code</h5> <h5 class="modal-title">Table QR Code</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div> </div>
<div class="modal-body text-center" id="printableQR"> <div class="modal-body text-center p-5">
<h4 class="fw-bold mb-3" id="qrTableNumber">Table</h4> <h4 id="qrTableNumber" class="mb-4 fw-bold"></h4>
<div id="qrContainer" class="mb-3"> <div id="qrcode" class="mb-4 d-flex justify-content-center"></div>
<!-- QR Image will be loaded here --> <p class="text-muted small">Scan this QR to order from this table</p>
</div> <div class="d-grid gap-2">
<p class="small text-muted mb-0">Scan to Order</p> <button type="button" class="btn btn-outline-primary" onclick="downloadQR()">
<div class="mt-2 small text-break text-muted" id="qrLink" style="font-size: 0.7rem;"></div> <i class="bi bi-download"></i> Download QR
</div> </button>
<div class="modal-footer justify-content-center"> <button type="button" class="btn btn-outline-secondary" onclick="printQR()">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" onclick="printQR()">
<i class="bi bi-printer"></i> Print <i class="bi bi-printer"></i> Print
</button> </button>
</div> </div>
</div> </div>
</div> </div>
</div>
</div> </div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
<script> <script>
let qrGenerator = null;
const baseUrl = '<?= $baseUrl ?>';
function prepareAddForm() { function prepareAddForm() {
document.getElementById('tableModalTitle').innerText = 'Add New Table'; document.getElementById('tableModalTitle').innerText = 'Add New Table';
document.getElementById('tableAction').value = 'add_table'; document.getElementById('tableAction').value = 'add_table';
document.getElementById('tableForm').reset();
document.getElementById('tableId').value = ''; document.getElementById('tableId').value = '';
document.getElementById('tableNumber').value = '';
document.getElementById('tableAreaId').value = '';
document.getElementById('tableCapacity').value = '2';
document.getElementById('tableStatus').value = 'available';
} }
function prepareEditForm(table) { function prepareEditForm(table) {
if (!table) return;
document.getElementById('tableModalTitle').innerText = 'Edit Table'; document.getElementById('tableModalTitle').innerText = 'Edit Table';
document.getElementById('tableAction').value = 'edit_table'; document.getElementById('tableAction').value = 'edit_table';
document.getElementById('tableId').value = table.id; document.getElementById('tableId').value = table.id;
document.getElementById('tableNumber').value = table.table_number || ''; document.getElementById('tableNumber').value = table.table_number || '';
document.getElementById('tableAreaId').value = table.area_id || ''; document.getElementById('tableAreaId').value = table.area_id || '';
document.getElementById('tableCapacity').value = table.capacity || 2; document.getElementById('tableCapacity').value = table.capacity || '2';
document.getElementById('tableStatus').value = table.status || 'available'; document.getElementById('tableStatus').value = table.status || 'available';
} }
function showTableQR(id, number) { function showTableQR(id, number) {
const baseUrl = '<?= $baseUrl ?>';
const qorderUrl = baseUrl + '/qorder.php?table_id=' + id;
const qrCodeUrl = "https://api.qrserver.com/v1/create-qr-code/?size=300x300&data=" + encodeURIComponent(qorderUrl);
document.getElementById('qrTableNumber').innerText = 'Table ' + number; document.getElementById('qrTableNumber').innerText = 'Table ' + number;
document.getElementById('qrContainer').innerHTML = '<img src="' + qrCodeUrl + '" alt="QR Code" class="img-fluid shadow-sm" style="max-width: 200px;">'; const qrContainer = document.getElementById('qrcode');
document.getElementById('qrLink').innerText = qorderUrl; qrContainer.innerHTML = '';
const modal = new bootstrap.Modal(document.getElementById('qrModal')); const url = baseUrl + '/qorder.php?table=' + id;
modal.show();
qrGenerator = new QRCode(qrContainer, {
text: url,
width: 256,
height: 256,
colorDark: "#000000",
colorLight: "#ffffff",
correctLevel: QRCode.CorrectLevel.H
});
new bootstrap.Modal(document.getElementById('qrModal')).show();
}
function downloadQR() {
const img = document.querySelector('#qrcode img');
if (img) {
const link = document.createElement('a');
link.download = 'table-qr.png';
link.href = img.src;
link.click();
}
} }
function printQR() { function printQR() {
const content = document.getElementById('printableQR').innerHTML; const img = document.querySelector('#qrcode img');
const printWindow = window.open('', '_blank'); if (!img) return;
printWindow.document.write('<html><head><title>Print Table QR</title>');
printWindow.document.write('<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">'); const win = window.open('', '_blank');
printWindow.document.write('<style>body { text-align: center; padding: 50px; }</style>'); win.document.write('<html><body style="text-align:center;padding:50px;">');
printWindow.document.write('</head><body>'); win.document.write('<h1>' + document.getElementById('qrTableNumber').innerText + '</h1>');
printWindow.document.write(content); win.document.write('<img src="' + img.src + '" style="width:300px;">');
printWindow.document.write('</body></html>'); win.document.write('<p style="font-family:sans-serif;margin-top:20px;">Scan to Order</p>');
printWindow.document.close(); win.document.write('</body></html>');
setTimeout(() => { win.document.close();
printWindow.print(); win.print();
printWindow.close(); win.close();
}, 500);
} }
</script> </script>

View File

@ -1,5 +1,6 @@
<?php <?php
require_once __DIR__ . "/../includes/functions.php"; require_once __DIR__ . "/../includes/functions.php";
require_once __DIR__ . "/../db/config.php";
require_permission("user_groups_view"); require_permission("user_groups_view");
require_once __DIR__ . '/../db/config.php'; require_once __DIR__ . '/../db/config.php';
$pdo = db(); $pdo = db();

View File

@ -1,5 +1,6 @@
<?php <?php
require_once __DIR__ . "/../includes/functions.php"; require_once __DIR__ . "/../includes/functions.php";
require_once __DIR__ . "/../db/config.php";
require_permission("users_view"); require_permission("users_view");
require_once __DIR__ . '/../db/config.php'; require_once __DIR__ . '/../db/config.php';
$pdo = db(); $pdo = db();

View File

@ -467,7 +467,7 @@ document.addEventListener('DOMContentLoaded', () => {
const statusClass = table.is_occupied ? "btn-outline-danger" : "btn-outline-success"; const statusClass = table.is_occupied ? "btn-outline-danger" : "btn-outline-success";
col.innerHTML = ` col.innerHTML = `
<button class=\"btn ${statusClass} w-100 py-3 rounded-3 position-relative\" onclick=\"selectTable(${table.id}, '${table.name}')\"> <button class=\"btn ${statusClass} w-100 py-3 rounded-3 position-relative\" onclick=\"selectTable(${table.id}, '${table.name}')\">
<div class=\"fw-bold\">${table.name}</div> <div class=\"fw-bold">${table.name}</div>
<div class=\"small\" style=\"font-size: 0.7rem;\">Cap: ${table.capacity}</div> <div class=\"small\" style=\"font-size: 0.7rem;\">Cap: ${table.capacity}</div>
${table.is_occupied ? '<span class="position-absolute top-0 start-100 translate-middle p-1 bg-danger border border-light rounded-circle" title="Occupied"></span>' : ''} ${table.is_occupied ? '<span class="position-absolute top-0 start-100 translate-middle p-1 bg-danger border border-light rounded-circle" title="Occupied"></span>' : ''}
</button> </button>
@ -516,7 +516,7 @@ document.addEventListener('DOMContentLoaded', () => {
price: parseFloat(product.price), base_price: parseFloat(product.price), price: parseFloat(product.price), base_price: parseFloat(product.price),
hasVariants: false, quantity: 1, variant_id: null, variant_name: null, hasVariants: false, quantity: 1, variant_id: null, variant_name: null,
is_loyalty: parseInt(product.is_loyalty) === 1, is_loyalty: parseInt(product.is_loyalty) === 1,
vat_percent: parseFloat(product.vat_percent || 0) vat_percent: parseFloat(product.vat_percent || settings.vat_rate || 0)
}); });
} }
}; };
@ -540,7 +540,7 @@ document.addEventListener('DOMContentLoaded', () => {
price: finalPrice, base_price: parseFloat(product.price), price: finalPrice, base_price: parseFloat(product.price),
hasVariants: true, quantity: 1, variant_id: v.id, variant_name: v.name, hasVariants: true, quantity: 1, variant_id: v.id, variant_name: v.name,
is_loyalty: parseInt(product.is_loyalty) === 1, is_loyalty: parseInt(product.is_loyalty) === 1,
vat_percent: parseFloat(product.vat_percent || 0) vat_percent: parseFloat(product.vat_percent || settings.vat_rate || 0)
}); });
variantSelectionModal.hide(); variantSelectionModal.hide();
}; };
@ -587,7 +587,8 @@ document.addEventListener('DOMContentLoaded', () => {
cartItemsContainer.innerHTML = `<div class="text-center text-muted mt-5"><i class="bi bi-basket3 fs-1 text-light"></i><p class="mt-2">${_t('cart_empty')}</p></div>`; cartItemsContainer.innerHTML = `<div class="text-center text-muted mt-5"><i class="bi bi-basket3 fs-1 text-light"></i><p class="mt-2">${_t('cart_empty')}</p></div>`;
if (cartSubtotal) cartSubtotal.innerText = formatCurrency(0); if (cartSubtotal) cartSubtotal.innerText = formatCurrency(0);
if (cartVatAmount) cartVatAmount.innerText = formatCurrency(0); if (cartVatAmount) cartVatAmount.innerText = formatCurrency(0);
if (cartVatRow) cartVatRow.classList.add('d-none'); // Always show VAT row even if 0
if (cartVatRow) cartVatRow.classList.remove('d-none');
if (cartTotalPrice) cartTotalPrice.innerText = formatCurrency(0); if (cartTotalPrice) cartTotalPrice.innerText = formatCurrency(0);
if (quickOrderBtn) { quickOrderBtn.disabled = true; quickOrderBtn.innerText = _t('quick_pay'); } if (quickOrderBtn) { quickOrderBtn.disabled = true; quickOrderBtn.innerText = _t('quick_pay'); }
if (placeOrderBtn) { placeOrderBtn.disabled = true; placeOrderBtn.innerText = _t('save_bill'); } if (placeOrderBtn) { placeOrderBtn.disabled = true; placeOrderBtn.innerText = _t('save_bill'); }
@ -629,10 +630,8 @@ document.addEventListener('DOMContentLoaded', () => {
if (cartSubtotal) cartSubtotal.innerText = formatCurrency(subtotal); if (cartSubtotal) cartSubtotal.innerText = formatCurrency(subtotal);
if (cartVatAmount) cartVatAmount.innerText = formatCurrency(totalVat); if (cartVatAmount) cartVatAmount.innerText = formatCurrency(totalVat);
if (cartVatRow) { // Always show VAT row
if (totalVat > 0) cartVatRow.classList.remove('d-none'); if (cartVatRow) cartVatRow.classList.remove('d-none');
else cartVatRow.classList.add('d-none');
}
if (cartVatInput) cartVatInput.value = totalVat.toFixed(3); if (cartVatInput) cartVatInput.value = totalVat.toFixed(3);
const total = subtotal + totalVat; const total = subtotal + totalVat;
@ -806,6 +805,8 @@ document.addEventListener('DOMContentLoaded', () => {
const logoHtml = settings.logo_url ? `<img src="${BASE_URL}${settings.logo_url}" style="max-height: 80px; max-width: 150px; margin-bottom: 10px;">` : ''; const logoHtml = settings.logo_url ? `<img src="${BASE_URL}${settings.logo_url}" style="max-height: 80px; max-width: 150px; margin-bottom: 10px;">` : '';
const vatRate = settings.vat_rate || 0;
const html = ` const html = `
<html dir="ltr"> <html dir="ltr">
<head> <head>
@ -860,7 +861,7 @@ document.addEventListener('DOMContentLoaded', () => {
<div class="totals"> <div class="totals">
<table style="width: 100%"> <table style="width: 100%">
<tr><td>Subtotal / ${tr['Subtotal']}</td><td style="text-align: right">${formatCurrency(data.subtotal)}</td></tr> <tr><td>Subtotal / ${tr['Subtotal']}</td><td style="text-align: right">${formatCurrency(data.subtotal)}</td></tr>
${Math.abs(data.vat) > 0 ? `<tr><td>VAT / ${tr['VAT']}</td><td style="text-align: right">${formatCurrency(Math.abs(data.vat))}</td></tr>` : ''} <tr><td>VAT (${vatRate}%) / ${tr['VAT']}</td><td style="text-align: right">${formatCurrency(Math.abs(data.vat))}</td></tr>
<tr style="font-weight: bold; font-size: 18px;"><td style="padding-top: 10px;">TOTAL / ${tr['TOTAL']}</td><td style="text-align: right; padding-top: 10px;">${formatCurrency(data.total)}</td></tr> <tr style="font-weight: bold; font-size: 18px;"><td style="padding-top: 10px;">TOTAL / ${tr['TOTAL']}</td><td style="text-align: right; padding-top: 10px;">${formatCurrency(data.total)}</td></tr>
</table> </table>
</div> </div>

45
db/migrate.php Normal file
View File

@ -0,0 +1,45 @@
<?php
require_once __DIR__ . '/config.php';
$pdo = db();
// Ensure migrations table exists
$pdo->exec("CREATE TABLE IF NOT EXISTS migrations (
id INT AUTO_INCREMENT PRIMARY KEY,
migration_name VARCHAR(255) NOT NULL UNIQUE,
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)");
$migrations_folder = array_diff(scandir(__DIR__ . '/migrations'), ['.', '..']);
sort($migrations_folder);
$applied_migrations = $pdo->query("SELECT migration_name FROM migrations")->fetchAll(PDO::FETCH_COLUMN);
foreach ($migrations_folder as $migration) {
if (!in_array($migration, $applied_migrations)) {
echo "Applying migration: $migration\n";
$sql = file_get_contents(__DIR__ . '/migrations/' . $migration);
try {
if (!empty(trim($sql))) {
$pdo->exec($sql);
}
$stmt = $pdo->prepare("INSERT INTO migrations (migration_name) VALUES (?)");
$stmt->execute([$migration]);
echo "Successfully applied $migration\n";
} catch (Exception $e) {
echo "Error applying $migration: " . $e->getMessage() . "\n";
// If it's a "Duplicate column name" error, we can assume it was applied manually and just record it
if (strpos($e->getMessage(), 'Duplicate column name') !== false || strpos($e->getMessage(), 'already exists') !== false) {
echo "Column/Table already exists, recording as applied.\n";
$stmt = $pdo->prepare("INSERT INTO migrations (migration_name) VALUES (?)");
$stmt->execute([$migration]);
} else {
// For other errors, we might want to stop or continue
echo "Stopping migrations due to error.\n";
break;
}
}
}
}
echo "Migration process finished.\n";

View File

@ -108,6 +108,7 @@ function t($key, $lang = null) {
'orders' => 'Orders', 'orders' => 'Orders',
'kitchen' => 'Kitchen', 'kitchen' => 'Kitchen',
'switch' => 'Switch', 'switch' => 'Switch',
'are_you_sure' => 'Are you sure?',
] ]
]; ];

View File

@ -75,6 +75,8 @@ $loyalty_settings = $loyalty_stmt->fetch(PDO::FETCH_ASSOC);
if (!$loyalty_settings) { if (!$loyalty_settings) {
$loyalty_settings = ['is_enabled' => 0, 'points_per_order' => 0, 'points_for_free_meal' => 0]; $loyalty_settings = ['is_enabled' => 0, 'points_per_order' => 0, 'points_for_free_meal' => 0];
} }
$vat_rate = (float)($settings['vat_rate'] ?? 0);
?> ?>
<!doctype html> <!doctype html>
<html lang="en" dir="ltr"> <html lang="en" dir="ltr">
@ -327,7 +329,7 @@ if (!$loyalty_settings) {
<span class="fw-bold small" id="cart-subtotal"><?= format_currency(0) ?></span> <span class="fw-bold small" id="cart-subtotal"><?= format_currency(0) ?></span>
</div> </div>
<div class="d-flex justify-content-between mb-1" id="cart-vat-row"> <div class="d-flex justify-content-between mb-1" id="cart-vat-row">
<span class="text-muted small">VAT</span> <span class="text-muted small">VAT (<?= $vat_rate ?>%)</span>
<span class="fw-bold small" id="cart-vat-amount"><?= format_currency(0) ?></span> <span class="fw-bold small" id="cart-vat-amount"><?= format_currency(0) ?></span>
<input type="hidden" id="cart-vat-input" value="0"> <input type="hidden" id="cart-vat-input" value="0">
</div> </div>

File diff suppressed because it is too large Load Diff