symbol added for currency

This commit is contained in:
Flatlogic Bot 2026-02-26 17:57:35 +00:00
parent 13a3054fd1
commit ac32148f05
11 changed files with 501 additions and 123 deletions

View File

@ -19,6 +19,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$vat_rate = $_POST['vat_rate'] ?? 0;
$currency_symbol = $_POST['currency_symbol'] ?? '$';
$currency_decimals = $_POST['currency_decimals'] ?? 2;
$currency_position = $_POST['currency_position'] ?? 'before';
$ctr_number = $_POST['ctr_number'] ?? '';
$vat_number = $_POST['vat_number'] ?? '';
$commission_enabled = isset($_POST['commission_enabled']) ? 1 : 0;
@ -67,11 +68,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$exists = $pdo->query("SELECT COUNT(*) FROM company_settings")->fetchColumn();
if ($exists) {
$stmt = $pdo->prepare("UPDATE company_settings SET company_name=?, address=?, phone=?, email=?, vat_rate=?, currency_symbol=?, currency_decimals=?, ctr_number=?, vat_number=?, logo_url=?, favicon_url=?, commission_enabled=?, updated_at=NOW()");
$stmt->execute([$company_name, $address, $phone, $email, $vat_rate, $currency_symbol, $currency_decimals, $ctr_number, $vat_number, $logo_url, $favicon_url, $commission_enabled]);
$stmt = $pdo->prepare("UPDATE company_settings SET company_name=?, address=?, phone=?, email=?, vat_rate=?, currency_symbol=?, currency_decimals=?, currency_position=?, ctr_number=?, vat_number=?, logo_url=?, favicon_url=?, commission_enabled=?, updated_at=NOW()");
$stmt->execute([$company_name, $address, $phone, $email, $vat_rate, $currency_symbol, $currency_decimals, $currency_position, $ctr_number, $vat_number, $logo_url, $favicon_url, $commission_enabled]);
} else {
$stmt = $pdo->prepare("INSERT INTO company_settings (company_name, address, phone, email, vat_rate, currency_symbol, currency_decimals, ctr_number, vat_number, logo_url, favicon_url, commission_enabled) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([$company_name, $address, $phone, $email, $vat_rate, $currency_symbol, $currency_decimals, $ctr_number, $vat_number, $logo_url, $favicon_url, $commission_enabled]);
$stmt = $pdo->prepare("INSERT INTO company_settings (company_name, address, phone, email, vat_rate, currency_symbol, currency_decimals, currency_position, ctr_number, vat_number, logo_url, favicon_url, commission_enabled) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([$company_name, $address, $phone, $email, $vat_rate, $currency_symbol, $currency_decimals, $currency_position, $ctr_number, $vat_number, $logo_url, $favicon_url, $commission_enabled]);
}
$message = '<div class="alert alert-success">Company settings updated successfully!</div>';
@ -138,18 +139,25 @@ include 'includes/header.php';
<h5 class="mb-3">Financial Settings</h5>
<div class="row">
<div class="col-md-4 mb-3">
<div class="col-md-3 mb-3">
<label class="form-label">VAT Rate (%)</label>
<div class="input-group">
<input type="number" step="0.01" name="vat_rate" class="form-control" value="<?= htmlspecialchars($settings['vat_rate'] ?? 0) ?>" <?= !has_permission('settings_add') ? 'readonly' : '' ?>>
<span class="input-group-text">%</span>
</div>
</div>
<div class="col-md-4 mb-3">
<div class="col-md-3 mb-3">
<label class="form-label">Currency Symbol</label>
<input type="text" name="currency_symbol" class="form-control" value="<?= htmlspecialchars($settings['currency_symbol'] ?? '$') ?>" placeholder="e.g. $, €, £" <?= !has_permission('settings_add') ? 'readonly' : '' ?>>
</div>
<div class="col-md-4 mb-3">
<div class="col-md-3 mb-3">
<label class="form-label">Currency Position</label>
<select name="currency_position" class="form-select" <?= !has_permission('settings_add') ? 'disabled' : '' ?>>
<option value="before" <?= ($settings['currency_position'] ?? 'before') === 'before' ? 'selected' : '' ?>>Before (e.g. $10.00)</option>
<option value="after" <?= ($settings['currency_position'] ?? 'before') === 'after' ? 'selected' : '' ?>>After (e.g. 10.00 OMR)</option>
</select>
</div>
<div class="col-md-3 mb-3">
<label class="form-label">Decimal Places</label>
<input type="number" name="currency_decimals" class="form-control" value="<?= htmlspecialchars($settings['currency_decimals'] ?? 2) ?>" min="0" max="4" <?= !has_permission('settings_add') ? 'readonly' : '' ?>>
</div>

View File

@ -489,6 +489,16 @@ function can_view($module) {
<li class="nav-item">
<a class="nav-link <?= isActive('reports.php') ?>" href="reports.php">
<i class="bi bi-graph-up me-2"></i> <?= t('daily_reports') ?>
<li class="nav-item">
<a class="nav-link <?= isActive('report_products.php') ?>" href="report_products.php">
<i class="bi bi-box-seam me-2"></i> Product Sales
</a>
</li>
<li class="nav-item">
<a class="nav-link <?= isActive('report_staff.php') ?>" href="report_staff.php">
<i class="bi bi-person-badge me-2"></i> Staff Sales
</a>
</li>
</a>
</li>
</ul>

View File

@ -94,7 +94,7 @@ Thank you for dining with *{company_name}*! 🍽️
*Order Details:*
{order_details}
Total: *{total_amount}* OMR
Total: *{total_amount}*
You've earned *{points_earned} points* with this order.
💰 *Current Balance: {new_balance} points*";
@ -193,7 +193,7 @@ require_once __DIR__ . '/includes/header.php';
<div class="form-text mt-2">
<strong>Available Variables:</strong><br>
<code>{customer_name}</code>, <code>{company_name}</code>, <code>{order_id}</code>,
<code>{order_details}</code> (list of items), <code>{total_amount}</code>,
<code>{order_details}</code> (list of items), <code>{total_amount}</code>, <code>{currency_symbol}</code>,
<code>{points_earned}</code>, <code>{points_redeemed}</code>, <code>{new_balance}</code>.
</div>
</div>

147
admin/report_products.php Normal file
View File

@ -0,0 +1,147 @@
<?php
require_once __DIR__ . '/includes/header.php';
// Check permission
if (function_exists('require_permission')) {
require_permission('reports_view');
}
$pdo = db();
// Date and Outlet Filter
$startDate = $_GET['start_date'] ?? date('Y-m-d');
$endDate = $_GET['end_date'] ?? date('Y-m-d');
$outletId = $_GET['outlet_id'] ?? '';
// Fetch Outlets for filter
$outletsStmt = $pdo->query("SELECT id, name, name_ar FROM outlets WHERE is_deleted = 0 ORDER BY name ASC");
$allOutlets = $outletsStmt->fetchAll();
// Base query additions
$outletCondition = "";
$queryParams = [$startDate, $endDate];
if (!empty($outletId)) {
$outletCondition = " AND o.outlet_id = ? ";
$queryParams[] = $outletId;
}
// Product Sales & Profit
$productSalesStmt = $pdo->prepare("
SELECT
p.name as product_name,
p.name_ar as product_name_ar,
SUM(oi.quantity) as qty_sold,
SUM(oi.quantity * oi.unit_price) as total_amount,
SUM(oi.quantity * (oi.unit_price - IFNULL(p.cost_price, 0))) as total_profit
FROM order_items oi
JOIN orders o ON oi.order_id = o.id
JOIN products p ON oi.product_id = p.id
WHERE DATE(o.created_at) BETWEEN ? AND ?
$outletCondition
GROUP BY p.id
ORDER BY qty_sold DESC
");
$productSalesStmt->execute($queryParams);
$productSales = $productSalesStmt->fetchAll();
// Totals for the footer
$totalQty = 0;
$totalAmount = 0;
$totalProfit = 0;
foreach ($productSales as $p) {
$totalQty += $p['qty_sold'];
$totalAmount += $p['total_amount'];
$totalProfit += $p['total_profit'];
}
?>
<div class="container-fluid p-0">
<div class="d-flex justify-content-between align-items-center mb-4 flex-wrap gap-3">
<div>
<h2 class="fw-bold mb-1">Product Sales Report</h2>
<p class="text-muted mb-0">Detailed breakdown of product performance and profitability</p>
</div>
<form class="row g-2 align-items-center" method="GET">
<div class="col-auto">
<select name="outlet_id" class="form-select" style="min-width: 180px;">
<option value="">All Outlets</option>
<?php foreach ($allOutlets as $o): ?>
<option value="<?= $o['id'] ?>" <?= $outletId == $o['id'] ? 'selected' : '' ?>>
<?= htmlspecialchars($o['name']) ?> <?= $o['name_ar'] ? '('.$o['name_ar'].')' : '' ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-auto">
<div class="input-group">
<span class="input-group-text bg-white border-end-0 text-muted"><i class="bi bi-calendar"></i></span>
<input type="date" name="start_date" class="form-control border-start-0" value="<?= htmlspecialchars($startDate) ?>">
</div>
</div>
<div class="col-auto">
<div class="input-group">
<span class="input-group-text bg-white border-end-0 text-muted"><i class="bi bi-calendar"></i></span>
<input type="date" name="end_date" class="form-control border-start-0" value="<?= htmlspecialchars($endDate) ?>">
</div>
</div>
<div class="col-auto">
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary px-4 text-nowrap">Filter</button>
<a href="report_products.php" class="btn btn-light text-nowrap">Reset</a>
</div>
</div>
</form>
</div>
<div class="card border-0 shadow-sm">
<div class="card-header bg-white py-3 border-0 d-flex justify-content-between align-items-center">
<h5 class="fw-bold mb-0"><i class="bi bi-box-seam me-2 text-dark"></i> Products</h5>
<button onclick="window.print()" class="btn btn-sm btn-outline-secondary"><i class="bi bi-printer me-1"></i> Print</button>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light">
<tr>
<th class="ps-3">Product Name</th>
<th class="text-center">Qty Sold</th>
<th class="text-end">Total Amount</th>
<th class="text-end pe-3">Estimated Profit</th>
</tr>
</thead>
<tbody>
<?php if (empty($productSales)): ?>
<tr><td colspan="4" class="text-center py-5 text-muted">No sales found for the selected criteria</td></tr>
<?php else: ?>
<?php foreach ($productSales as $prod): ?>
<tr>
<td class="ps-3">
<div class="fw-bold text-dark"><?= htmlspecialchars($prod['product_name']) ?></div>
<?php if ($prod['product_name_ar']): ?>
<small class="text-muted d-block"><?= htmlspecialchars($prod['product_name_ar']) ?></small>
<?php endif; ?>
</td>
<td class="text-center"><?= number_format($prod['qty_sold']) ?></td>
<td class="text-end fw-bold"><?= format_currency($prod['total_amount']) ?></td>
<td class="text-end pe-3 fw-bold text-success"><?= format_currency($prod['total_profit']) ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
<?php if (!empty($productSales)): ?>
<tfoot class="bg-light fw-bold">
<tr>
<td class="ps-3 text-uppercase">Total</td>
<td class="text-center"><?= number_format($totalQty) ?></td>
<td class="text-end"><?= format_currency($totalAmount) ?></td>
<td class="text-end pe-3 text-success"><?= format_currency($totalProfit) ?></td>
</tr>
</tfoot>
<?php endif; ?>
</table>
</div>
</div>
</div>
</div>
<?php require_once __DIR__ . '/includes/footer.php'; ?>

171
admin/report_staff.php Normal file
View File

@ -0,0 +1,171 @@
<?php
require_once __DIR__ . '/includes/header.php';
// Check permission
if (function_exists('require_permission')) {
require_permission('reports_view');
}
$pdo = db();
// Date and Outlet Filter
$startDate = $_GET['start_date'] ?? date('Y-m-d');
$endDate = $_GET['end_date'] ?? date('Y-m-d');
$outletId = $_GET['outlet_id'] ?? '';
// Fetch Outlets for filter
$outletsStmt = $pdo->query("SELECT id, name, name_ar FROM outlets WHERE is_deleted = 0 ORDER BY name ASC");
$allOutlets = $outletsStmt->fetchAll();
// Base query additions
$outletCondition = "";
$queryParams = [$startDate, $endDate];
if (!empty($outletId)) {
$outletCondition = " AND o.outlet_id = ? ";
$queryParams[] = $outletId;
}
// Staff Sales by Payment Type
$staffPaymentStmt = $pdo->prepare("
SELECT
u.full_name as staff_name,
u.full_name_ar as staff_name_ar,
pt.name as payment_name,
SUM(o.total_amount) as total_amount
FROM orders o
JOIN users u ON o.user_id = u.id
LEFT JOIN payment_types pt ON o.payment_type_id = pt.id
WHERE DATE(o.created_at) BETWEEN ? AND ?
$outletCondition
GROUP BY o.user_id, o.payment_type_id
ORDER BY u.full_name ASC, total_amount DESC
");
$staffPaymentStmt->execute($queryParams);
$staffPaymentSales = $staffPaymentStmt->fetchAll();
// Summary by payment type
$paymentSummary = [];
$grandTotal = 0;
foreach ($staffPaymentSales as $row) {
$pName = $row['payment_name'] ?? 'N/A';
if (!isset($paymentSummary[$pName])) {
$paymentSummary[$pName] = 0;
}
$paymentSummary[$pName] += $row['total_amount'];
$grandTotal += $row['total_amount'];
}
?>
<div class="container-fluid p-0">
<div class="d-flex justify-content-between align-items-center mb-4 flex-wrap gap-3">
<div>
<h2 class="fw-bold mb-1">Staff Sales Report</h2>
<p class="text-muted mb-0">Sales breakdown by staff and payment method</p>
</div>
<form class="row g-2 align-items-center" method="GET">
<div class="col-auto">
<select name="outlet_id" class="form-select" style="min-width: 180px;">
<option value="">All Outlets</option>
<?php foreach ($allOutlets as $o): ?>
<option value="<?= $o['id'] ?>" <?= $outletId == $o['id'] ? 'selected' : '' ?>>
<?= htmlspecialchars($o['name']) ?> <?= $o['name_ar'] ? '('.$o['name_ar'].')' : '' ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-auto">
<div class="input-group">
<span class="input-group-text bg-white border-end-0 text-muted"><i class="bi bi-calendar"></i></span>
<input type="date" name="start_date" class="form-control border-start-0" value="<?= htmlspecialchars($startDate) ?>">
</div>
</div>
<div class="col-auto">
<div class="input-group">
<span class="input-group-text bg-white border-end-0 text-muted"><i class="bi bi-calendar"></i></span>
<input type="date" name="end_date" class="form-control border-start-0" value="<?= htmlspecialchars($endDate) ?>">
</div>
</div>
<div class="col-auto">
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary px-4 text-nowrap">Filter</button>
<a href="report_staff.php" class="btn btn-light text-nowrap">Reset</a>
</div>
</div>
</form>
</div>
<div class="row g-4">
<div class="col-lg-8">
<div class="card border-0 shadow-sm h-100">
<div class="card-header bg-white py-3 border-0 d-flex justify-content-between align-items-center">
<h5 class="fw-bold mb-0"><i class="bi bi-person-badge me-2 text-primary"></i> Detailed Staff Sales</h5>
<button onclick="window.print()" class="btn btn-sm btn-outline-secondary"><i class="bi bi-printer me-1"></i> Print</button>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light">
<tr>
<th class="ps-3">Staff Name</th>
<th>Payment Type</th>
<th class="text-end pe-3">Total Amount</th>
</tr>
</thead>
<tbody>
<?php if (empty($staffPaymentSales)): ?>
<tr><td colspan="3" class="text-center py-5 text-muted">No sales found for the selected criteria</td></tr>
<?php else: ?>
<?php
$currentStaff = '';
foreach ($staffPaymentSales as $row):
$showStaff = ($currentStaff != $row['staff_name']);
$currentStaff = $row['staff_name'];
?>
<tr class="<?= $showStaff ? 'border-top' : '' ?>">
<td class="ps-3">
<?php if ($showStaff): ?>
<div class="fw-bold text-dark"><?= htmlspecialchars($row['staff_name']) ?></div>
<?php if ($row['staff_name_ar']): ?>
<small class="text-muted"><?= htmlspecialchars($row['staff_name_ar']) ?></small>
<?php endif; ?>
<?php endif; ?>
</td>
<td>
<span class="badge bg-light text-dark border"><?= htmlspecialchars($row['payment_name'] ?? 'N/A') ?></span>
</td>
<td class="text-end pe-3 fw-bold"><?= format_currency($row['total_amount']) ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card border-0 shadow-sm mb-4">
<div class="card-header bg-white py-3 border-0">
<h5 class="fw-bold mb-0"><i class="bi bi-pie-chart me-2 text-success"></i> Payment Summary</h5>
</div>
<div class="card-body">
<ul class="list-group list-group-flush">
<?php foreach ($paymentSummary as $pName => $amount): ?>
<li class="list-group-item d-flex justify-content-between align-items-center px-0">
<span><?= htmlspecialchars($pName) ?></span>
<span class="fw-bold"><?= format_currency($amount) ?></span>
</li>
<?php endforeach; ?>
<li class="list-group-item d-flex justify-content-between align-items-center px-0 bg-light mt-2 p-2 rounded">
<span class="fw-bold">Grand Total</span>
<span class="fw-bold text-primary fs-5"><?= format_currency($grandTotal) ?></span>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<?php require_once __DIR__ . '/includes/footer.php'; ?>

View File

@ -14,7 +14,7 @@ $endDate = $_GET['end_date'] ?? date('Y-m-d');
$outletId = $_GET['outlet_id'] ?? '';
// Fetch Outlets for filter
$outletsStmt = $pdo->query("SELECT id, name, name_ar FROM outlets ORDER BY name ASC");
$outletsStmt = $pdo->query("SELECT id, name, name_ar FROM outlets WHERE is_deleted = 0 ORDER BY name ASC");
$allOutlets = $outletsStmt->fetchAll();
// Base query additions
@ -124,7 +124,7 @@ $netProfit = ($summary['total_revenue'] ?? 0) - $totalExpenses;
<div class="container-fluid p-0">
<div class="d-flex justify-content-between align-items-center mb-4 flex-wrap gap-3">
<div>
<h2 class="fw-bold mb-1">Daily Reports</h2>
<h2 class="fw-bold mb-1">Business Reports</h2>
<p class="text-muted mb-0">Overview of your business performance</p>
</div>
<form class="row g-2 align-items-center" method="GET">
@ -216,86 +216,6 @@ $netProfit = ($summary['total_revenue'] ?? 0) - $totalExpenses;
</div>
<div class="row g-4">
<!-- Sales by Staff -->
<div class="col-md-6">
<div class="card border-0 shadow-sm h-100">
<div class="card-header bg-white py-3 border-0">
<h5 class="fw-bold mb-0"><i class="bi bi-people me-2 text-primary"></i> Sales by Staff</h5>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light">
<tr>
<th class="ps-3">Staff Name</th>
<th class="text-center">Orders</th>
<th class="text-end pe-3">Total Sales</th>
</tr>
</thead>
<tbody>
<?php if (empty($staffSales)): ?>
<tr><td colspan="3" class="text-center py-4 text-muted">No data found for this period</td></tr>
<?php else: ?>
<?php foreach ($staffSales as $staff): ?>
<tr>
<td class="ps-3">
<div class="fw-bold"><?= htmlspecialchars($staff['staff_name'] ?: $staff['username']) ?></div>
<?php if ($staff['staff_name_ar']): ?>
<small class="text-muted"><?= htmlspecialchars($staff['staff_name_ar']) ?></small>
<?php endif; ?>
</td>
<td class="text-center"><?= $staff['order_count'] ?></td>
<td class="text-end pe-3 fw-bold text-primary"><?= format_currency($staff['total_sales']) ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Sales by Outlet -->
<div class="col-md-6">
<div class="card border-0 shadow-sm h-100">
<div class="card-header bg-white py-3 border-0">
<h5 class="fw-bold mb-0"><i class="bi bi-shop me-2 text-success"></i> Sales by Outlet</h5>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light">
<tr>
<th class="ps-3">Outlet</th>
<th class="text-center">Orders</th>
<th class="text-end pe-3">Total Sales</th>
</tr>
</thead>
<tbody>
<?php if (empty($outletSales)): ?>
<tr><td colspan="3" class="text-center py-4 text-muted">No data found for this period</td></tr>
<?php else: ?>
<?php foreach ($outletSales as $outlet): ?>
<tr>
<td class="ps-3">
<div class="fw-bold"><?= htmlspecialchars($outlet['outlet_name']) ?></div>
<?php if ($outlet['outlet_name_ar']): ?>
<small class="text-muted"><?= htmlspecialchars($outlet['outlet_name_ar']) ?></small>
<?php endif; ?>
</td>
<td class="text-center"><?= $outlet['order_count'] ?></td>
<td class="text-end pe-3 fw-bold text-success"><?= format_currency($outlet['total_sales']) ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Sales by Category -->
<div class="col-md-6">
<div class="card border-0 shadow-sm h-100">
@ -373,6 +293,86 @@ $netProfit = ($summary['total_revenue'] ?? 0) - $totalExpenses;
</div>
</div>
</div>
<!-- Sales by Staff -->
<div class="col-md-6">
<div class="card border-0 shadow-sm h-100">
<div class="card-header bg-white py-3 border-0">
<h5 class="fw-bold mb-0"><i class="bi bi-people me-2 text-primary"></i> Sales Summary by Staff</h5>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light">
<tr>
<th class="ps-3">Staff Name</th>
<th class="text-center">Orders</th>
<th class="text-end pe-3">Total Sales</th>
</tr>
</thead>
<tbody>
<?php if (empty($staffSales)): ?>
<tr><td colspan="3" class="text-center py-4 text-muted">No data found for this period</td></tr>
<?php else: ?>
<?php foreach ($staffSales as $staff): ?>
<tr>
<td class="ps-3">
<div class="fw-bold"><?= htmlspecialchars($staff['staff_name'] ?: $staff['username']) ?></div>
<?php if ($staff['staff_name_ar']): ?>
<small class="text-muted"><?= htmlspecialchars($staff['staff_name_ar']) ?></small>
<?php endif; ?>
</td>
<td class="text-center"><?= $staff['order_count'] ?></td>
<td class="text-end pe-3 fw-bold text-primary"><?= format_currency($staff['total_sales']) ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Sales by Outlet -->
<div class="col-md-6">
<div class="card border-0 shadow-sm h-100">
<div class="card-header bg-white py-3 border-0">
<h5 class="fw-bold mb-0"><i class="bi bi-shop me-2 text-success"></i> Sales by Outlet</h5>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light">
<tr>
<th class="ps-3">Outlet</th>
<th class="text-center">Orders</th>
<th class="text-end pe-3">Total Sales</th>
</tr>
</thead>
<tbody>
<?php if (empty($outletSales)): ?>
<tr><td colspan="3" class="text-center py-4 text-muted">No data found for this period</td></tr>
<?php else: ?>
<?php foreach ($outletSales as $outlet): ?>
<tr>
<td class="ps-3">
<div class="fw-bold"><?= htmlspecialchars($outlet['outlet_name']) ?></div>
<?php if ($outlet['outlet_name_ar']): ?>
<small class="text-muted"><?= htmlspecialchars($outlet['outlet_name_ar']) ?></small>
<?php endif; ?>
</td>
<td class="text-center"><?= $outlet['order_count'] ?></td>
<td class="text-end pe-3 fw-bold text-success"><?= format_currency($outlet['total_sales']) ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -269,8 +269,8 @@ try {
$payment_type_id = !empty($data['payment_type_id']) ? intval($data['payment_type_id']) : null;
// Commission Calculation
$commission_amount = 0;
$companySettings = get_company_settings();
$commission_amount = 0;
if (!empty($companySettings['commission_enabled']) && $user_id) {
$userStmt = $pdo->prepare("SELECT commission_rate FROM users WHERE id = ?");
$userStmt->execute([$user_id]);
@ -352,8 +352,9 @@ try {
try {
$final_points = $current_points - $points_deducted + ($loyalty_enabled ? $points_awarded : 0);
$wablas = new WablasService($pdo);
$companySettings = get_company_settings();
$company_name = $companySettings['company_name'] ?? 'Flatlogic POS';
$currency_symbol = $companySettings['currency_symbol'] ?? 'OMR';
$currency_position = $companySettings['currency_position'] ?? 'after';
$stmt = $pdo->prepare("SELECT setting_value FROM integration_settings WHERE provider = 'wablas' AND setting_key = 'order_template'");
$stmt->execute();
@ -367,7 +368,7 @@ Thank you for dining with *{company_name}*! 🍽️
*Order Details:*
{order_details}
Total: *{total_amount}* OMR
Total: *{total_amount}*
You've earned *{points_earned} points* with this order.
💰 *Current Balance: {new_balance} points*
@ -382,12 +383,20 @@ You've earned *{points_earned} points* with this order.
: "You need *" . ($points_threshold - $final_points) . " more points* to unlock a free meal.";
}
$formatted_total = number_format($final_total, (int)($companySettings['currency_decimals'] ?? 2));
if ($currency_position === 'after') {
$total_with_currency = $formatted_total . " " . $currency_symbol;
} else {
$total_with_currency = $currency_symbol . $formatted_total;
}
$replacements = [
'{customer_name}' => $customer_name,
'{company_name}' => $company_name,
'{order_id}' => $order_id,
'{order_details}' => implode("\n", $order_items_list),
'{total_amount}' => number_format($final_total, 3),
'{total_amount}' => $total_with_currency,
'{currency_symbol}' => $currency_symbol,
'{points_earned}' => $loyalty_enabled ? $points_awarded : 0,
'{points_redeemed}' => $points_deducted,
'{new_balance}' => $final_points,
@ -408,4 +417,4 @@ You've earned *{points_earned} points* with this order.
if ($pdo->inTransaction()) $pdo->rollBack();
error_log("Order Error: " . $e->getMessage());
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
}
}

View File

@ -32,6 +32,7 @@ document.addEventListener('DOMContentLoaded', () => {
const settings = (typeof COMPANY_SETTINGS !== 'undefined') ? COMPANY_SETTINGS : {
currency_symbol: '$',
currency_decimals: 2,
currency_position: 'before',
vat_rate: 0
};
@ -101,7 +102,14 @@ document.addEventListener('DOMContentLoaded', () => {
function formatCurrency(amount) {
const symbol = settings.currency_symbol || '$';
const decimals = parseInt(settings.currency_decimals || 2);
return symbol + parseFloat(Math.abs(amount)).toFixed(decimals);
const position = settings.currency_position || 'before';
const formatted = parseFloat(Math.abs(amount)).toFixed(decimals);
if (position === 'after') {
return formatted + ' ' + symbol;
} else {
return symbol + formatted;
}
}
function filterProducts() {
@ -427,11 +435,11 @@ document.addEventListener('DOMContentLoaded', () => {
if (data.success && data.tables.length > 0) {
renderTables(data.tables);
} else {
grid.innerHTML = `<div class=\"p-4 text-center text-muted w-100\">${_t("none")}</div>`;
grid.innerHTML = `<div class=\"p-4 text-center text-muted w-100">${_t("none")}</div>`;
}
})
.catch(() => {
grid.innerHTML = `<div class=\"alert alert-danger w-100\">${_t("error")}</div>`;
grid.innerHTML = `<div class=\"alert alert-danger w-100">${_t("error")}</div>`;
});
}
@ -450,7 +458,7 @@ document.addEventListener('DOMContentLoaded', () => {
for (const area in areas) {
const areaHeader = document.createElement("div");
areaHeader.className = "col-12 mt-3";
areaHeader.innerHTML = `<h6 class=\"fw-bold text-muted text-uppercase small border-bottom pb-2\">${area}</h6>`;
areaHeader.innerHTML = `<h6 class=\"fw-bold text-muted text-uppercase small border-bottom pb-2">${area}</h6>`;
grid.appendChild(areaHeader);
areas[area].forEach(table => {
@ -881,4 +889,4 @@ document.addEventListener('DOMContentLoaded', () => {
const modal = new bootstrap.Modal(document.getElementById('qrRatingModal'));
modal.show();
};
});
});

View File

@ -0,0 +1,5 @@
-- Add currency position setting
ALTER TABLE company_settings ADD COLUMN currency_position ENUM('before', 'after') DEFAULT 'after';
-- Update existing Omani settings to use 'after' as it's more common for OMR
UPDATE company_settings SET currency_position = 'after' WHERE currency_symbol IN ('OMR', 'ر.ع.', 'OMRR');

View File

@ -22,7 +22,8 @@ function get_company_settings() {
'email' => 'info@restaurant.com',
'vat_rate' => 0.00,
'currency_symbol' => '$',
'currency_decimals' => 2
'currency_decimals' => 2,
'currency_position' => 'before'
];
}
}
@ -32,7 +33,17 @@ function get_company_settings() {
// Function to format currency using settings
function format_currency($amount) {
$settings = get_company_settings();
return ($settings['currency_symbol'] ?? '$') . number_format((float)$amount, (int)($settings['currency_decimals'] ?? 2));
$symbol = $settings['currency_symbol'] ?? '$';
$decimals = (int)($settings['currency_decimals'] ?? 2);
$position = $settings['currency_position'] ?? 'before';
$formatted_number = number_format((float)$amount, $decimals);
if ($position === 'after') {
return $formatted_number . ' ' . $symbol;
} else {
return $symbol . $formatted_number;
}
}
/**
@ -431,4 +442,4 @@ function trigger_auto_backup() {
$stmt->execute();
}
}
}
}

View File

@ -143,12 +143,11 @@ foreach ($variants_raw as $v) {
<img src="https://picsum.photos/seed/<?= $product['id'] ?>/400/300" class="card-img-top product-img" alt="<?= htmlspecialchars($product['name']) ?>">
<div class="badge-price text-primary">
<?php if ($is_promo): ?>
<span class="text-danger fw-bold"><?= number_format($effective_price, 3) ?></span>
<small class="text-muted text-decoration-line-through ms-1" style="font-size: 0.7rem;"><?= number_format((float)$product['price'], 3) ?></small>
<span class="text-danger fw-bold"><?= format_currency($effective_price) ?></span>
<small class="text-muted text-decoration-line-through ms-1" style="font-size: 0.7rem;"><?= format_currency((float)$product['price']) ?></small>
<?php else: ?>
<?= number_format((float)$product['price'], 3) ?>
<?= format_currency((float)$product['price']) ?>
<?php endif; ?>
<span data-t="currency">OMR</span>
</div>
<?php if ($is_promo): ?>
<div class="position-absolute top-0 start-0 m-2">
@ -177,7 +176,7 @@ foreach ($variants_raw as $v) {
<div class="d-flex align-items-center justify-content-between">
<div>
<div class="small text-muted"><span id="cart-items-count">0</span> <span data-t="items">Items</span></div>
<div class="fw-bold fs-5 text-primary" id="cart-total-display">0.000 OMR</div>
<div class="fw-bold fs-5 text-primary" id="cart-total-display"><?= format_currency(0) ?></div>
</div>
<button class="btn btn-primary px-4 fw-bold" onclick="showCart()">
<span data-t="view_cart">View Cart</span> <i class="bi bi-cart-fill ms-1"></i>
@ -200,11 +199,11 @@ foreach ($variants_raw as $v) {
<div class="p-3 bg-light border-top">
<div class="d-flex justify-content-between mb-2">
<span data-t="subtotal">Subtotal</span>
<span id="modal-subtotal">0.000 OMR</span>
<span id="modal-subtotal"><?= format_currency(0) ?></span>
</div>
<div class="d-flex justify-content-between fw-bold fs-5">
<span data-t="total">Total</span>
<span id="modal-total">0.000 OMR</span>
<span id="modal-total"><?= format_currency(0) ?></span>
</div>
</div>
<div class="p-3">
@ -244,6 +243,7 @@ foreach ($variants_raw as $v) {
const TABLE_ID = <?= $table_id ?>;
const OUTLET_ID = <?= $outlet_id ?>;
const PRODUCT_VARIANTS = <?= json_encode($variants_by_product) ?>;
const COMPANY_SETTINGS = <?= json_encode($settings) ?>;
let cart = [];
let currentLang = localStorage.getItem('qorder_lang') || 'en';
@ -262,7 +262,6 @@ foreach ($variants_raw as $v) {
cust_name_placeholder: 'To identify your order',
place_order: 'Place Order',
select_option: 'Select Option',
currency: 'OMR',
added_to_cart: 'added to cart',
order_placed: 'Order Placed!',
order_success_msg: 'Your order has been sent to the kitchen. Thank you!',
@ -279,7 +278,6 @@ foreach ($variants_raw as $v) {
cust_name_placeholder: 'لتحديد طلبك',
place_order: 'إتمام الطلب',
select_option: 'اختر الخيار',
currency: 'ر.ع.',
added_to_cart: 'تم الإضافة إلى السلة',
order_placed: 'تم إرسال الطلب!',
order_success_msg: 'تم إرسال طلبك إلى المطبخ. شكراً لك!',
@ -287,6 +285,19 @@ foreach ($variants_raw as $v) {
}
};
function formatCurrency(amount) {
const symbol = COMPANY_SETTINGS.currency_symbol || '$';
const decimals = parseInt(COMPANY_SETTINGS.currency_decimals || 2);
const position = COMPANY_SETTINGS.currency_position || 'before';
const formatted = parseFloat(Math.abs(amount)).toFixed(decimals);
if (position === 'after') {
return formatted + ' ' + symbol;
} else {
return symbol + formatted;
}
}
function updateTranslations() {
document.querySelectorAll('[data-t]').forEach(el => {
const key = el.getAttribute('data-t');
@ -358,9 +369,9 @@ foreach ($variants_raw as $v) {
btn.innerHTML = `
<div>
<div class="fw-bold">${vName}</div>
<div class="small text-muted">${adj > 0 ? '+' : ''}${adj.toFixed(3)} ${translations[currentLang].currency}</div>
<div class="small text-muted">${adj > 0 ? '+' : ''}${formatCurrency(adj)}</div>
</div>
<div class="fw-bold text-primary">${finalPrice.toFixed(3)} ${translations[currentLang].currency}</div>
<div class="fw-bold text-primary">${formatCurrency(finalPrice)}</div>
`;
btn.onclick = () => {
addToCart(product.id, `${pName} (${vName})`, finalPrice, v.id);
@ -385,10 +396,9 @@ foreach ($variants_raw as $v) {
function updateCartUI() {
const total = cart.reduce((sum, item) => sum + (item.unit_price * item.quantity), 0);
const count = cart.reduce((sum, item) => sum + item.quantity, 0);
const currency = translations[currentLang].currency;
document.getElementById('cart-items-count').textContent = count;
document.getElementById('cart-total-display').textContent = total.toFixed(3) + ' ' + currency;
document.getElementById('cart-total-display').textContent = formatCurrency(total);
const footer = document.getElementById('cart-footer');
if (count > 0) {
@ -401,7 +411,6 @@ foreach ($variants_raw as $v) {
function showCart() {
const list = document.getElementById('cart-list');
list.innerHTML = '';
const currency = translations[currentLang].currency;
cart.forEach((item, index) => {
const div = document.createElement('div');
@ -409,10 +418,10 @@ foreach ($variants_raw as $v) {
div.innerHTML = `
<div class="d-flex justify-content-between align-items-start mb-2">
<div class="fw-bold text-truncate me-2">${item.name}</div>
<div class="fw-bold">${(item.unit_price * item.quantity).toFixed(3)}</div>
<div class="fw-bold">${formatCurrency(item.unit_price * item.quantity)}</div>
</div>
<div class="d-flex justify-content-between align-items-center">
<div class="text-muted small">${item.unit_price.toFixed(3)} / unit</div>
<div class="text-muted small">${formatCurrency(item.unit_price)} / unit</div>
<div class="quantity-controls">
<button class="quantity-btn" onclick="updateQty(${index}, -1)"><i class="bi bi-dash"></i></button>
<span class="fw-bold">${item.quantity}</span>
@ -424,8 +433,8 @@ foreach ($variants_raw as $v) {
});
const total = cart.reduce((sum, item) => sum + (item.unit_price * item.quantity), 0);
document.getElementById('modal-subtotal').textContent = total.toFixed(3) + ' ' + currency;
document.getElementById('modal-total').textContent = total.toFixed(3) + ' ' + currency;
document.getElementById('modal-subtotal').textContent = formatCurrency(total);
document.getElementById('modal-total').textContent = formatCurrency(total);
cartModal.show();
}
@ -510,4 +519,4 @@ foreach ($variants_raw as $v) {
}
</script>
</body>
</html>
</html>