update sales id

This commit is contained in:
Flatlogic Bot 2026-04-19 09:52:55 +00:00
parent 9b7ec271a9
commit 1ac0f55ef8
11 changed files with 561 additions and 207 deletions

View File

@ -166,4 +166,38 @@ body.auth-body {
[dir="rtl"] .form-select-lg { [dir="rtl"] .form-select-lg {
padding-right: 1rem; padding-right: 1rem;
padding-left: 3rem; padding-left: 3rem;
} }
/* Print specific styles */
@media print {
#sidebar-wrapper, .top-navbar, .d-print-none {
display: none !important;
}
#page-content-wrapper {
margin: 0 !important;
width: 100% !important;
min-width: 100% !important;
padding: 0 !important;
}
body {
font-size: 11pt;
background-color: #fff;
}
.table {
font-size: 10pt;
margin-bottom: 1rem;
}
.table th, .table td {
padding: 0.3rem;
}
.fs-5 {
font-size: 1rem !important;
}
h2 {
font-size: 1.5rem;
}
.surface-card {
box-shadow: none !important;
border: none !important;
}
}

View File

@ -2,4 +2,4 @@
# https://curl.se/docs/http-cookies.html # https://curl.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk. # This file was generated by libcurl! Edit at your own risk.
127.0.0.1 FALSE / FALSE 0 PHPSESSID 6qft39lctsp4e64kmen99qtqfo 127.0.0.1 FALSE / FALSE 0 PHPSESSID une8u6o0qtfojm7tp3ppv39knh

View File

@ -46,6 +46,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
} else { } else {
$normalized = []; $normalized = [];
$subtotal = 0.0; $subtotal = 0.0;
$totalVat = 0.0;
$itemCount = 0; $itemCount = 0;
foreach ($items as $item) { foreach ($items as $item) {
$sku = (string) ($item['sku'] ?? ''); $sku = (string) ($item['sku'] ?? '');
@ -56,6 +57,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$product = $catalog[$sku]; $product = $catalog[$sku];
$price = (float) $product['price']; $price = (float) $product['price'];
$lineTotal = $price * $qty; $lineTotal = $price * $qty;
$vatPercent = (float) ($product['vat'] ?? 0);
$itemVat = $lineTotal - ($lineTotal / (1 + ($vatPercent / 100)));
$totalVat += $itemVat;
$normalized[] = [ $normalized[] = [
'sku' => $sku, 'sku' => $sku,
'name_ar' => $product['name_ar'], 'name_ar' => $product['name_ar'],
@ -63,6 +69,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
'qty' => $qty, 'qty' => $qty,
'price' => $price, 'price' => $price,
'line_total' => $lineTotal, 'line_total' => $lineTotal,
'vat_percent' => $vatPercent,
'vat_amount' => $itemVat
]; ];
$subtotal += $lineTotal; $subtotal += $lineTotal;
$itemCount += $qty; $itemCount += $qty;
@ -79,6 +87,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
items_json = :items_json, items_json = :items_json,
item_count = :item_count, item_count = :item_count,
subtotal = :subtotal, subtotal = :subtotal,
vat_amount = :vat_amount,
total_amount = :total_amount, total_amount = :total_amount,
status = :status, status = :status,
notes = :notes notes = :notes
@ -380,8 +389,8 @@ require __DIR__ . '/includes/header.php';
<span id="displaySubtotal" class="fw-medium">0.000</span> <span id="displaySubtotal" class="fw-medium">0.000</span>
</div> </div>
<div class="totals-row"> <div class="totals-row">
<span><?= h(tr('الضريبة (' . get_setting('vat_percentage', 5) . '%)', 'VAT (' . get_setting('vat_percentage', 5) . '%)')) ?></span> <span><?= h(tr('الضريبة (مشمولة)', 'VAT (Included)')) ?></span>
<span class="text-success small"><?= h(tr('مشمولة', 'Included')) ?></span> <span id="displayVat" class="text-muted">0.000</span>
</div> </div>
<div class="totals-row grand-total"> <div class="totals-row grand-total">
<span><?= h(tr('الإجمالي', 'Total')) ?></span> <span><?= h(tr('الإجمالي', 'Total')) ?></span>
@ -633,18 +642,24 @@ function renderInvoice() {
if (skus.length === 0) { if (skus.length === 0) {
tbody.innerHTML = ''; tbody.innerHTML = '';
tbody.appendChild(emptyRow); tbody.appendChild(emptyRow);
updateTotals(0); updateTotals(0, 0);
cartJson.value = '[]'; cartJson.value = '[]';
return; return;
} }
tbody.innerHTML = ''; tbody.innerHTML = '';
let totalAmount = 0; let totalAmount = 0;
let totalVat = 0;
const cartData = []; const cartData = [];
skus.forEach(sku => { skus.forEach(sku => {
const item = invoiceItems[sku]; const item = invoiceItems[sku];
const lineTotal = item.qty * item.price; const lineTotal = item.qty * item.price;
const vatPercent = parseFloat(catalogData[sku].vat) || 0;
const itemVat = lineTotal - (lineTotal / (1 + (vatPercent / 100)));
totalVat += itemVat;
totalAmount += lineTotal; totalAmount += lineTotal;
cartData.push({ sku: item.sku, qty: item.qty }); cartData.push({ sku: item.sku, qty: item.qty });
@ -668,12 +683,14 @@ function renderInvoice() {
tbody.appendChild(tr); tbody.appendChild(tr);
}); });
updateTotals(totalAmount); updateTotals(totalAmount, totalVat);
cartJson.value = JSON.stringify(cartData); cartJson.value = JSON.stringify(cartData);
} }
function updateTotals(total) { function updateTotals(total, vat) {
document.getElementById('displaySubtotal').innerText = total.toFixed(3); const subtotal = total - vat;
document.getElementById('displaySubtotal').innerText = subtotal.toFixed(3);
document.getElementById('displayVat').innerText = vat.toFixed(3);
document.getElementById('displayTotal').innerText = total.toFixed(3) + currencySuffix; document.getElementById('displayTotal').innerText = total.toFixed(3) + currencySuffix;
} }

View File

@ -115,35 +115,6 @@ function branch_label(string $code): string
return current_lang() === 'ar' ? $branch['name_ar'] : $branch['name_en']; return current_lang() === 'ar' ? $branch['name_ar'] : $branch['name_en'];
} }
function demo_users(): array
{
return [
'owner' => [
'username' => 'owner',
'password' => 'owner123',
'role' => 'owner',
'branch_code' => 'muscat',
'name_ar' => 'مالك النظام',
'name_en' => 'System Owner',
],
'manager_muscat' => [
'username' => 'manager_muscat',
'password' => 'manager123',
'role' => 'manager',
'branch_code' => 'muscat',
'name_ar' => 'مدير فرع مسقط',
'name_en' => 'Muscat Branch Manager',
],
'cashier_sohar' => [
'username' => 'cashier_sohar',
'password' => 'cashier123',
'role' => 'cashier',
'branch_code' => 'sohar',
'name_ar' => 'كاشير فرع صحار',
'name_en' => 'Sohar Cashier',
],
];
}
function role_label(string $role): string function role_label(string $role): string
{ {
@ -162,18 +133,21 @@ function current_user(): ?array
function login_attempt(string $username, string $password): bool function login_attempt(string $username, string $password): bool
{ {
$users = demo_users(); require_once __DIR__ . "/../db/config.php";
if (!isset($users[$username])) { $stmt = db()->prepare("SELECT * FROM users WHERE username = ?");
$stmt->execute([$username]);
$user = $stmt->fetch();
if (!$user) {
return false; return false;
} }
$user = $users[$username]; if (password_verify($password, $user["password"])) {
if ($user['password'] !== $password) { $_SESSION["auth_user"] = $user;
return false; return true;
} }
$_SESSION['auth_user'] = $user; return false;
return true;
} }
function logout_user(): void function logout_user(): void
@ -525,7 +499,7 @@ function purchase_pipeline(): array
function receipt_code(): string function receipt_code(): string
{ {
return 'AR-' . date('ymd-His') . '-' . random_int(100, 999); return (string) random_int(100000, 999999);
} }
function create_purchase(array $data): int function create_purchase(array $data): int

View File

@ -31,6 +31,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
} else { } else {
$normalized = []; $normalized = [];
$subtotal = 0.0; $subtotal = 0.0;
$totalVat = 0.0;
$itemCount = 0; $itemCount = 0;
foreach ($items as $item) { foreach ($items as $item) {
$sku = (string) ($item['sku'] ?? ''); $sku = (string) ($item['sku'] ?? '');
@ -41,6 +42,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$product = $catalog[$sku]; $product = $catalog[$sku];
$price = (float) $product['price']; $price = (float) $product['price'];
$lineTotal = $price * $qty; $lineTotal = $price * $qty;
$vatPercent = (float) ($product['vat'] ?? 0);
// Assuming price is inclusive of VAT:
$itemVat = $lineTotal - ($lineTotal / (1 + ($vatPercent / 100)));
$totalVat += $itemVat;
$normalized[] = [ $normalized[] = [
'sku' => $sku, 'sku' => $sku,
'name_ar' => $product['name_ar'], 'name_ar' => $product['name_ar'],
@ -48,6 +55,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
'qty' => $qty, 'qty' => $qty,
'price' => $price, 'price' => $price,
'line_total' => $lineTotal, 'line_total' => $lineTotal,
'vat_percent' => $vatPercent,
'vat_amount' => $itemVat
]; ];
$subtotal += $lineTotal; $subtotal += $lineTotal;
$itemCount += $qty; $itemCount += $qty;
@ -68,7 +77,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
'payment_method' => $paymentMethod, 'payment_method' => $paymentMethod,
'items' => $normalized, 'items' => $normalized,
'item_count' => $itemCount, 'item_count' => $itemCount,
'subtotal' => $subtotal, 'subtotal' => $subtotal - $totalVat,
'vat_amount' => $totalVat,
'total_amount' => $subtotal, 'total_amount' => $subtotal,
'status' => $saleStatus, 'status' => $saleStatus,
'notes' => $notes !== '' ? $notes : null, 'notes' => $notes !== '' ? $notes : null,
@ -360,8 +370,8 @@ require __DIR__ . '/header.php';
<span id="displaySubtotal" class="fw-medium">0.000</span> <span id="displaySubtotal" class="fw-medium">0.000</span>
</div> </div>
<div class="totals-row"> <div class="totals-row">
<span><?= h(tr('الضريبة (' . get_setting('vat_percentage', 5) . '%)', 'VAT (' . get_setting('vat_percentage', 5) . '%)')) ?></span> <span><?= h(tr('الضريبة (مشمولة)', 'VAT (Included)')) ?></span>
<span class="text-success small"><?= h(tr('مشمولة', 'Included')) ?></span> <span id="displayVat" class="text-muted">0.000</span>
</div> </div>
<div class="totals-row grand-total"> <div class="totals-row grand-total">
<span><?= h(tr('الإجمالي', 'Total')) ?></span> <span><?= h(tr('الإجمالي', 'Total')) ?></span>
@ -601,18 +611,24 @@ function renderInvoice() {
if (skus.length === 0) { if (skus.length === 0) {
tbody.innerHTML = ''; tbody.innerHTML = '';
tbody.appendChild(emptyRow); tbody.appendChild(emptyRow);
updateTotals(0); updateTotals(0, 0);
cartJson.value = '[]'; cartJson.value = '[]';
return; return;
} }
tbody.innerHTML = ''; tbody.innerHTML = '';
let totalAmount = 0; let totalAmount = 0;
let totalVat = 0;
const cartData = []; const cartData = [];
skus.forEach(sku => { skus.forEach(sku => {
const item = invoiceItems[sku]; const item = invoiceItems[sku];
const lineTotal = item.qty * item.price; const lineTotal = item.qty * item.price;
const vatPercent = parseFloat(catalogData[sku].vat) || 0;
const itemVat = lineTotal - (lineTotal / (1 + (vatPercent / 100)));
totalVat += itemVat;
totalAmount += lineTotal; totalAmount += lineTotal;
cartData.push({ sku: item.sku, qty: item.qty }); cartData.push({ sku: item.sku, qty: item.qty });
@ -636,12 +652,14 @@ function renderInvoice() {
tbody.appendChild(tr); tbody.appendChild(tr);
}); });
updateTotals(totalAmount); updateTotals(totalAmount, totalVat);
cartJson.value = JSON.stringify(cartData); cartJson.value = JSON.stringify(cartData);
} }
function updateTotals(total) { function updateTotals(total, vat) {
document.getElementById('displaySubtotal').innerText = total.toFixed(3); const subtotal = total - vat;
document.getElementById('displaySubtotal').innerText = subtotal.toFixed(3);
document.getElementById('displayVat').innerText = vat.toFixed(3);
document.getElementById('displayTotal').innerText = total.toFixed(3) + currencySuffix; document.getElementById('displayTotal').innerText = total.toFixed(3) + currencySuffix;
} }

View File

@ -35,7 +35,7 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? '';
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
$projectName = $_SERVER['PROJECT_NAME'] ?? app_name(); $projectName = $_SERVER['PROJECT_NAME'] ?? app_name();
$assetVersion = date('YmdHi'); $assetVersion = date('YmdHi');
$accounts = demo_users(); $accounts = [];
?> ?>
<!doctype html> <!doctype html>
<html lang="<?= h(current_lang()) ?>" dir="<?= is_rtl() ? 'rtl' : 'ltr' ?>"> <html lang="<?= h(current_lang()) ?>" dir="<?= is_rtl() ? 'rtl' : 'ltr' ?>">
@ -175,24 +175,7 @@ $accounts = demo_users();
<button class="btn btn-primary btn-lg w-100 rounded-3 shadow-sm fw-semibold" type="submit"><?= h(tr('دخول', 'Sign in')) ?></button> <button class="btn btn-primary btn-lg w-100 rounded-3 shadow-sm fw-semibold" type="submit"><?= h(tr('دخول', 'Sign in')) ?></button>
</form> </form>
<div class="position-relative mb-4">
<hr class="text-muted opacity-25">
<span class="position-absolute top-50 start-50 translate-middle bg-white px-3 small text-muted fw-medium"><?= h(tr('حسابات تجريبية سريعة', 'Quick demo access')) ?></span>
</div>
<div class="row g-2">
<?php foreach ($accounts as $account): ?>
<div class="col-12 col-md-4">
<button type="button"
class="btn btn-outline-secondary border-1 w-100 p-3 text-start demo-account h-100"
data-username="<?= h($account['username']) ?>"
data-password="<?= h($account['password']) ?>">
<div class="fw-bold mb-1 text-dark text-truncate"><?= h(current_lang() === 'ar' ? $account['name_ar'] : $account['name_en']) ?></div>
<div class="small text-muted" style="font-size: 0.75rem;"><?= h(role_label($account['role'])) ?></div>
</button>
</div>
<?php endforeach; ?>
</div>
</div> </div>
</div> </div>

View File

@ -248,8 +248,8 @@ $registerNo = 'REG-01';
<span><?= number_format((float)$sale['subtotal'], 3) ?></span> <span><?= number_format((float)$sale['subtotal'], 3) ?></span>
</div> </div>
<div class="totals-row"> <div class="totals-row">
<span><?= h(tr('ضريبة القيمة المضافة (' . get_setting('vat_percentage', 5) . '%)', 'VAT (' . get_setting('vat_percentage', 5) . '%)')) ?></span> <span><?= h(tr('ضريبة القيمة المضافة (مشمولة)', 'VAT (Inclusive)')) ?></span>
<span><?= h(tr('شامل', 'Inclusive')) ?></span> <span><?= number_format((float)($sale['vat_amount'] ?? 0), 3) ?></span>
</div> </div>
<div class="totals-row grand-total"> <div class="totals-row grand-total">
<span><?= h(tr('الإجمالي', 'Total')) ?></span> <span><?= h(tr('الإجمالي', 'Total')) ?></span>

View File

@ -3,50 +3,301 @@ require_once __DIR__ . '/includes/app.php';
$user = require_roles(['owner', 'manager']); $user = require_roles(['owner', 'manager']);
$pageTitle = tr('التقارير', 'Reports'); $pageTitle = tr('التقارير', 'Reports');
$activeNav = 'reports'; $activeNav = 'reports';
$tab = $_GET['tab'] ?? 'summary';
$dbError = null; $dbError = null;
$report = ['gross' => 0.0, 'branch_totals' => [], 'payment_totals' => [], 'product_totals' => [], 'sales_count' => 0];
try { if ($tab === 'sales') {
$report = report_metrics(); $dateFrom = $_GET['date_from'] ?? date('Y-m-01');
} catch (Throwable $e) { $dateTo = $_GET['date_to'] ?? date('Y-m-t');
$dbError = $e->getMessage(); $branchFilter = $_GET['branch'] ?? '';
$params = [];
$where = base_sales_query_filters($params, null, $branchFilter ?: null);
$where .= ' AND DATE(sale_date) >= :date_from AND DATE(sale_date) <= :date_to';
$params[':date_from'] = $dateFrom;
$params[':date_to'] = $dateTo;
$sql = 'SELECT * FROM sales_orders' . $where . ' ORDER BY sale_date DESC';
try {
$stmt = db()->prepare($sql);
foreach ($params as $k => $v) {
$stmt->bindValue($k, $v);
}
$stmt->execute();
$salesReport = $stmt->fetchAll();
} catch(Throwable $e) {
$dbError = $e->getMessage();
$salesReport = [];
}
} elseif ($tab === 'orders') {
$branchFilter = $_GET['branch'] ?? '';
$params = [];
$where = base_sales_query_filters($params, null, $branchFilter ?: null);
$where .= " AND status = 'order'";
$sql = 'SELECT * FROM sales_orders' . $where . ' ORDER BY sale_date ASC';
try {
$stmt = db()->prepare($sql);
foreach ($params as $k => $v) {
$stmt->bindValue($k, $v);
}
$stmt->execute();
$followUpOrders = $stmt->fetchAll();
} catch(Throwable $e) {
$dbError = $e->getMessage();
$followUpOrders = [];
}
} else {
$report = ['gross' => 0.0, 'branch_totals' => [], 'payment_totals' => [], 'product_totals' => [], 'sales_count' => 0];
try {
$report = report_metrics();
} catch (Throwable $e) {
$dbError = $e->getMessage();
}
} }
require __DIR__ . '/includes/header.php'; require __DIR__ . '/includes/header.php';
?> ?>
<section class="row g-3 mb-4">
<div class="col-md-4"><article class="metric-card"><div class="eyebrow"><?= h(tr('إجمالي المبيعات', 'Gross sales')) ?></div><div class="metric-value"><?= h(currency((float) $report['gross'])) ?></div><div class="small text-muted"><?= h(tr('حسب نطاق صلاحية المستخدم الحالي', 'Scoped to the current viewer permissions')) ?></div></article></div> <div class="d-flex justify-content-between align-items-center mb-4 d-print-none">
<div class="col-md-4"><article class="metric-card"><div class="eyebrow"><?= h(tr('عدد الفواتير', 'Invoices')) ?></div><div class="metric-value"><?= h((string) $report['sales_count']) ?></div><div class="small text-muted"><?= h(tr('إجمالي الفواتير المسجلة', 'Total logged invoices')) ?></div></article></div> <div>
<div class="col-md-4"><article class="metric-card"><div class="eyebrow"><?= h(tr('أفضل صنف', 'Top product')) ?></div><div class="metric-value small-metric"><?= h($report['product_totals'] ? product_label((string) array_key_first($report['product_totals'])) : tr('لا يوجد', 'None yet')) ?></div><div class="small text-muted"><?= h(tr('الأكثر مبيعاً حتى الآن', 'Most sold item so far')) ?></div></article></div> <h1 class="h3 mb-0"><?= h($pageTitle) ?></h1>
</section>
<section class="row g-4">
<div class="col-lg-6">
<div class="surface-card h-100">
<h3 class="h5 mb-3"><?= h(tr('المبيعات حسب الفرع', 'Sales by branch')) ?></h3>
<?php if ($dbError): ?>
<div class="alert alert-warning"><?= h($dbError) ?></div>
<?php elseif (!$report['branch_totals']): ?>
<div class="empty-state compact"><h4><?= h(tr('لا توجد بيانات', 'No data')) ?></h4><p><?= h(tr('أضف عملية بيع أولاً لبدء التقارير.', 'Add a first sale to activate reports.')) ?></p></div>
<?php else: ?>
<div class="d-grid gap-2">
<?php foreach ($report['branch_totals'] as $branchCode => $amount): ?>
<div class="report-row"><span><?= h(branch_label((string) $branchCode)) ?></span><strong><?= h(currency((float) $amount)) ?></strong></div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</div> </div>
<div class="col-lg-6"> </div>
<div class="surface-card h-100">
<h3 class="h5 mb-3"><?= h(tr('المبيعات حسب الدفع', 'Sales by payment')) ?></h3> <ul class="nav nav-tabs mb-4 d-print-none">
<?php if (!$report['payment_totals']): ?> <li class="nav-item">
<div class="empty-state compact"><h4><?= h(tr('بانتظار البيانات', 'Waiting for data')) ?></h4><p><?= h(tr('عند تسجيل عمليات بيع ستظهر هنا طرق الدفع.', 'Payment mix will appear here once sales are logged.')) ?></p></div> <a class="nav-link <?= $tab === 'summary' ? 'active' : '' ?>" href="reports.php?tab=summary"><?= h(tr('ملخص عام', 'General Summary')) ?></a>
<?php else: ?> </li>
<div class="d-grid gap-2"> <li class="nav-item">
<?php foreach ($report['payment_totals'] as $payment => $amount): ?> <a class="nav-link <?= $tab === 'sales' ? 'active' : '' ?>" href="reports.php?tab=sales"><?= h(tr('تقرير المبيعات', 'Sales Report')) ?></a>
<div class="report-row"><span><?= h(ucfirst((string) $payment)) ?></span><strong><?= h(currency((float) $amount)) ?></strong></div> </li>
<?php endforeach; ?> <li class="nav-item">
<a class="nav-link <?= $tab === 'orders' ? 'active' : '' ?>" href="reports.php?tab=orders"><?= h(tr('طلبات للمتابعة', 'Follow-up Orders')) ?></a>
</li>
</ul>
<?php if ($dbError): ?>
<div class="alert alert-danger d-print-none"><?= h($dbError) ?></div>
<?php endif; ?>
<?php if ($tab === 'sales'): ?>
<div class="card mb-4 d-print-none">
<div class="card-body">
<form method="GET" action="reports.php" class="row g-3 align-items-end">
<input type="hidden" name="tab" value="sales">
<div class="col-md-3">
<label class="form-label"><?= h(tr('من تاريخ', 'From Date')) ?></label>
<input type="date" name="date_from" class="form-control" value="<?= h($dateFrom) ?>">
</div>
<div class="col-md-3">
<label class="form-label"><?= h(tr('إلى تاريخ', 'To Date')) ?></label>
<input type="date" name="date_to" class="form-control" value="<?= h($dateTo) ?>">
</div>
<div class="col-md-4">
<label class="form-label"><?= h(tr('الفرع', 'Branch')) ?></label>
<select name="branch" class="form-select">
<option value=""><?= h(tr('جميع الفروع', 'All Branches')) ?></option>
<?php
$availableBranches = $user['role'] === 'owner' ? branches() : [$user['branch_code'] => branches()[$user['branch_code']]];
foreach ($availableBranches as $code => $b):
?>
<option value="<?= h($code) ?>" <?= $branchFilter === $code ? 'selected' : '' ?>><?= h(branch_label($code)) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-2">
<button type="submit" class="btn btn-primary w-100"><?= h(tr('بحث', 'Search')) ?></button>
</div>
</form>
</div> </div>
<?php endif; ?>
</div> </div>
</div>
</section> <div class="d-none d-print-block mb-4 text-center">
<?php require __DIR__ . '/includes/footer.php'; ?> <h2><?= h(tr('تقرير المبيعات', 'Sales Report')) ?></h2>
<p><?= h(tr('الفترة من', 'Period from')) ?> <?= h($dateFrom) ?> <?= h(tr('إلى', 'to')) ?> <?= h($dateTo) ?></p>
<?php if ($branchFilter): ?>
<p><?= h(tr('الفرع:', 'Branch:')) ?> <?= h(branch_label($branchFilter)) ?></p>
<?php endif; ?>
</div>
<div class="surface-card">
<div class="d-flex justify-content-between align-items-center mb-3 d-print-none">
<h3 class="h5 mb-0"><?= h(tr('نتائج التقرير', 'Report Results')) ?></h3>
<button class="btn btn-outline-secondary btn-sm" onclick="window.print()"><i class="bi bi-printer"></i> <?= h(tr('طباعة', 'Print')) ?></button>
</div>
<?php if(empty($salesReport)): ?>
<p class="text-muted"><?= h(tr('لا توجد مبيعات في هذه الفترة.', 'No sales found in this period.')) ?></p>
<?php else: ?>
<div class="table-responsive">
<table class="table table-bordered table-striped align-middle">
<thead>
<tr>
<th><?= h(tr('التاريخ', 'Date')) ?></th>
<th><?= h(tr('رقم الإيصال', 'Receipt No')) ?></th>
<th><?= h(tr('الكاشير', 'Cashier')) ?></th>
<th><?= h(tr('الفرع', 'Branch')) ?></th>
<th><?= h(tr('طريقة الدفع', 'Payment Method')) ?></th>
<th><?= h(tr('الحالة', 'Status')) ?></th>
<th class="text-end"><?= h(tr('الإجمالي', 'Total')) ?></th>
</tr>
</thead>
<tbody>
<?php
$totalSum = 0;
foreach($salesReport as $sale):
$totalSum += (float) $sale['total_amount'];
?>
<tr>
<td><?= h(date('Y-m-d H:i', strtotime((string)$sale['sale_date']))) ?></td>
<td><?= h((string)$sale['receipt_no']) ?></td>
<td><?= h((string)$sale['cashier_name']) ?></td>
<td><?= h(branch_label((string)$sale['branch_code'])) ?></td>
<td><?= h(ucfirst((string)$sale['payment_method'])) ?></td>
<td>
<?php if (($sale['status'] ?? 'completed') === 'order'): ?>
<span class="badge bg-warning text-dark"><i class="bi bi-clock"></i> <?= h(tr('طلب حجز', 'Order')) ?></span>
<?php else: ?>
<span class="badge bg-success"><i class="bi bi-check-circle"></i> <?= h(tr('مدفوع', 'Paid')) ?></span>
<?php endif; ?>
</td>
<td class="text-end fw-bold"><?= h(currency((float)$sale['total_amount'])) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot class="table-dark">
<tr>
<td colspan="6" class="text-end"><?= h(tr('الإجمالي الكلي', 'Grand Total')) ?></td>
<td class="text-end fw-bold fs-5"><?= h(currency($totalSum)) ?></td>
</tr>
</tfoot>
</table>
</div>
<?php endif; ?>
</div>
<?php elseif ($tab === 'orders'): ?>
<div class="card mb-4 d-print-none">
<div class="card-body">
<form method="GET" action="reports.php" class="row g-3 align-items-end">
<input type="hidden" name="tab" value="orders">
<div class="col-md-4">
<label class="form-label"><?= h(tr('الفرع', 'Branch')) ?></label>
<select name="branch" class="form-select" onchange="this.form.submit()">
<option value=""><?= h(tr('جميع الفروع', 'All Branches')) ?></option>
<?php
$availableBranches = $user['role'] === 'owner' ? branches() : [$user['branch_code'] => branches()[$user['branch_code']]];
foreach ($availableBranches as $code => $b):
?>
<option value="<?= h($code) ?>" <?= $branchFilter === $code ? 'selected' : '' ?>><?= h(branch_label($code)) ?></option>
<?php endforeach; ?>
</select>
</div>
</form>
</div>
</div>
<div class="d-none d-print-block mb-4 text-center">
<h2><?= h(tr('طلبات للمتابعة', 'Follow-up Orders')) ?></h2>
<p><?= h(date('Y-m-d H:i')) ?></p>
<?php if ($branchFilter): ?>
<p><?= h(tr('الفرع:', 'Branch:')) ?> <?= h(branch_label($branchFilter)) ?></p>
<?php endif; ?>
</div>
<div class="surface-card">
<div class="d-flex justify-content-between align-items-center mb-3 d-print-none">
<h3 class="h5 mb-0"><?= h(tr('طلبات حجز بانتظار الدفع', 'Reservation orders pending payment')) ?></h3>
<button class="btn btn-outline-secondary btn-sm" onclick="window.print()"><i class="bi bi-printer"></i> <?= h(tr('طباعة', 'Print')) ?></button>
</div>
<?php if(empty($followUpOrders)): ?>
<p class="text-muted"><?= h(tr('لا توجد طلبات للمتابعة.', 'No follow-up orders.')) ?></p>
<?php else: ?>
<div class="table-responsive">
<table class="table table-bordered table-hover align-middle">
<thead>
<tr>
<th><?= h(tr('التاريخ', 'Date')) ?></th>
<th><?= h(tr('رقم الإيصال', 'Receipt No')) ?></th>
<th><?= h(tr('العميل', 'Customer')) ?></th>
<th><?= h(tr('هاتف العميل', 'Customer Phone')) ?></th>
<th><?= h(tr('الفرع', 'Branch')) ?></th>
<th class="text-end"><?= h(tr('المبلغ المستحق', 'Due Amount')) ?></th>
<th class="d-print-none text-end"><?= h(tr('إجراءات', 'Actions')) ?></th>
</tr>
</thead>
<tbody>
<?php foreach($followUpOrders as $sale): ?>
<tr>
<td><?= h(date('Y-m-d H:i', strtotime((string)$sale['sale_date']))) ?></td>
<td><?= h((string)$sale['receipt_no']) ?></td>
<td><?= h((string)($sale['customer_name'] ?: '-')) ?></td>
<td><?= h((string)($sale['customer_phone'] ?: '-')) ?></td>
<td><?= h(branch_label((string)$sale['branch_code'])) ?></td>
<td class="text-end fw-bold text-danger"><?= h(currency((float)$sale['total_amount'])) ?></td>
<td class="d-print-none text-end">
<a class="btn btn-sm btn-light border" href="<?= h(url_for('sale.php', ['id' => $sale['id']])) ?>"><?= h(tr('عرض', 'View')) ?></a>
<button class="btn btn-sm btn-success" onclick="markPaidFromReports(<?= $sale['id'] ?>)"><i class="bi bi-check-lg"></i> <?= h(tr('دفع', 'Pay')) ?></button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<script>
function markPaidFromReports(id) {
if(confirm("<?= h(tr('هل أنت متأكد من تأكيد دفع هذا الطلب؟', 'Are you sure you want to confirm payment for this order?')) ?>")) {
window.location.href = 'sales.php?mark_paid=' + id + '&redirect=reports.php?tab=orders';
}
}
</script>
<?php endif; ?>
</div>
<?php else: ?>
<section class="row g-3 mb-4 d-print-none">
<div class="col-md-4"><article class="metric-card"><div class="eyebrow"><?= h(tr('إجمالي المبيعات', 'Gross sales')) ?></div><div class="metric-value"><?= h(currency((float) $report['gross'])) ?></div><div class="small text-muted"><?= h(tr('حسب نطاق صلاحية المستخدم الحالي', 'Scoped to the current viewer permissions')) ?></div></article></div>
<div class="col-md-4"><article class="metric-card"><div class="eyebrow"><?= h(tr('عدد الفواتير', 'Invoices')) ?></div><div class="metric-value"><?= h((string) $report['sales_count']) ?></div><div class="small text-muted"><?= h(tr('إجمالي الفواتير المسجلة', 'Total logged invoices')) ?></div></article></div>
<div class="col-md-4"><article class="metric-card"><div class="eyebrow"><?= h(tr('أفضل صنف', 'Top product')) ?></div><div class="metric-value small-metric"><?= h($report['product_totals'] ? product_label((string) array_key_first($report['product_totals'])) : tr('لا يوجد', 'None yet')) ?></div><div class="small text-muted"><?= h(tr('الأكثر مبيعاً حتى الآن', 'Most sold item so far')) ?></div></article></div>
</section>
<section class="row g-4 d-print-none">
<div class="col-lg-6">
<div class="surface-card h-100">
<h3 class="h5 mb-3"><?= h(tr('المبيعات حسب الفرع', 'Sales by branch')) ?></h3>
<?php if (!$report['branch_totals']): ?>
<div class="empty-state compact"><h4><?= h(tr('لا توجد بيانات', 'No data')) ?></h4><p><?= h(tr('أضف عملية بيع أولاً لبدء التقارير.', 'Add a first sale to activate reports.')) ?></p></div>
<?php else: ?>
<div class="d-grid gap-2">
<?php foreach ($report['branch_totals'] as $branchCode => $amount): ?>
<div class="report-row"><span><?= h(branch_label((string) $branchCode)) ?></span><strong><?= h(currency((float) $amount)) ?></strong></div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</div>
<div class="col-lg-6">
<div class="surface-card h-100">
<h3 class="h5 mb-3"><?= h(tr('المبيعات حسب الدفع', 'Sales by payment')) ?></h3>
<?php if (!$report['payment_totals']): ?>
<div class="empty-state compact"><h4><?= h(tr('بانتظار البيانات', 'Waiting for data')) ?></h4><p><?= h(tr('عند تسجيل عمليات بيع ستظهر هنا طرق الدفع.', 'Payment mix will appear here once sales are logged.')) ?></p></div>
<?php else: ?>
<div class="d-grid gap-2">
<?php foreach ($report['payment_totals'] as $payment => $amount): ?>
<div class="report-row"><span><?= h(ucfirst((string) $payment)) ?></span><strong><?= h(currency((float) $amount)) ?></strong></div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</div>
</section>
<?php endif; ?>
<?php require __DIR__ . '/includes/footer.php'; ?>

View File

@ -424,8 +424,8 @@ require __DIR__ . '/includes/header.php';
<td class="total-amount"><?= h(number_format((float) $sale['subtotal'], 3)) ?></td> <td class="total-amount"><?= h(number_format((float) $sale['subtotal'], 3)) ?></td>
</tr> </tr>
<tr> <tr>
<td class="total-label"><?= h(tr('ضريبة القيمة المضافة (' . get_setting('vat_percentage', 5) . '%)', 'VAT (' . get_setting('vat_percentage', 5) . '%)')) ?></td> <td class="total-label"><?= h(tr('ضريبة القيمة المضافة (مشمولة)', 'VAT (Inclusive)')) ?></td>
<td class="total-amount"><?= h(tr('شامل', 'Inclusive')) ?></td> <td class="total-amount"><?= number_format((float)($sale['vat_amount'] ?? 0), 3) ?></td>
</tr> </tr>
<tr class="grand-total-row"> <tr class="grand-total-row">
<td class="total-label"><?= h(tr('الإجمالي', 'Total')) ?></td> <td class="total-label"><?= h(tr('الإجمالي', 'Total')) ?></td>

View File

@ -14,7 +14,8 @@ if (isset($_GET['mark_paid']) && is_numeric($_GET['mark_paid'])) {
$id = (int)$_GET['mark_paid']; $id = (int)$_GET['mark_paid'];
db()->prepare("UPDATE sales_orders SET status = 'completed' WHERE id = ?")->execute([$id]); db()->prepare("UPDATE sales_orders SET status = 'completed' WHERE id = ?")->execute([$id]);
} catch(Throwable $e) {} } catch(Throwable $e) {}
header("Location: sales.php"); $redirect = $_GET["redirect"] ?? "sales.php";
header("Location: " . $redirect);
exit; exit;
} }
@ -99,7 +100,7 @@ require __DIR__ . '/includes/header.php';
<input type="hidden" name="mode" value="<?= h($mode) ?>"> <input type="hidden" name="mode" value="<?= h($mode) ?>">
<?php endif; ?> <?php endif; ?>
<div class="input-group" style="max-width: 600px;"> <div class="input-group" style="max-width: 600px;">
<select name="status" class="form-select" style="max-width: 150px;"> <select name="status" class="form-select" style="max-width: 150px;" onchange="this.form.submit()">
<option value=""><?= h(tr('كل الحالات', 'All Statuses')) ?></option> <option value=""><?= h(tr('كل الحالات', 'All Statuses')) ?></option>
<option value="completed" <?= $statusFilter === 'completed' ? 'selected' : '' ?>><?= h(tr('مدفوع', 'Paid')) ?></option> <option value="completed" <?= $statusFilter === 'completed' ? 'selected' : '' ?>><?= h(tr('مدفوع', 'Paid')) ?></option>
<option value="order" <?= $statusFilter === 'order' ? 'selected' : '' ?>><?= h(tr('طلب حجز', 'Order')) ?></option> <option value="order" <?= $statusFilter === 'order' ? 'selected' : '' ?>><?= h(tr('طلب حجز', 'Order')) ?></option>

256
users.php
View File

@ -4,25 +4,86 @@ $user = require_roles(['owner']);
$pageTitle = tr('المستخدمون والأدوار', 'Users & Roles'); $pageTitle = tr('المستخدمون والأدوار', 'Users & Roles');
$activeNav = 'users'; $activeNav = 'users';
$allAccounts = demo_users(); $flash = pull_flash();
// Handle POST actions (Create, Update, Delete)
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
if ($action === 'add') {
$username = trim($_POST['username'] ?? '');
$password = $_POST['password'] ?? '';
$name_ar = trim($_POST['name_ar'] ?? '');
$name_en = trim($_POST['name_en'] ?? '');
$role = $_POST['role'] ?? 'cashier';
$branch_code = $_POST['branch_code'] ?? 'muscat';
if ($username && $password && $name_ar) {
$hash = password_hash($password, PASSWORD_DEFAULT);
try {
$stmt = db()->prepare("INSERT INTO users (username, password, role, branch_code, name_ar, name_en) VALUES (?, ?, ?, ?, ?, ?)");
$stmt->execute([$username, $hash, $role, $branch_code, $name_ar, $name_en]);
set_flash('success', tr('تمت إضافة المستخدم بنجاح.', 'User added successfully.'));
} catch (PDOException $e) {
set_flash('error', tr('حدث خطأ، قد يكون اسم المستخدم موجوداً مسبقاً.', 'Error occurred, username might already exist.'));
}
} else {
set_flash('error', tr('يرجى تعبئة الحقول المطلوبة.', 'Please fill required fields.'));
}
redirect_to('users.php');
}
if ($action === 'edit') {
$id = (int)($_POST['id'] ?? 0);
$username = trim($_POST['username'] ?? '');
$name_ar = trim($_POST['name_ar'] ?? '');
$name_en = trim($_POST['name_en'] ?? '');
$role = $_POST['role'] ?? 'cashier';
$branch_code = $_POST['branch_code'] ?? 'muscat';
$password = $_POST['password'] ?? '';
if ($id && $username && $name_ar) {
try {
if ($password) {
$hash = password_hash($password, PASSWORD_DEFAULT);
$stmt = db()->prepare("UPDATE users SET username=?, password=?, role=?, branch_code=?, name_ar=?, name_en=? WHERE id=?");
$stmt->execute([$username, $hash, $role, $branch_code, $name_ar, $name_en, $id]);
} else {
$stmt = db()->prepare("UPDATE users SET username=?, role=?, branch_code=?, name_ar=?, name_en=? WHERE id=?");
$stmt->execute([$username, $role, $branch_code, $name_ar, $name_en, $id]);
}
set_flash('success', tr('تم تعديل المستخدم بنجاح.', 'User updated successfully.'));
} catch (PDOException $e) {
set_flash('error', tr('حدث خطأ أثناء التعديل.', 'Error occurred during update.'));
}
}
redirect_to('users.php');
}
if ($action === 'delete') {
$id = (int)($_POST['id'] ?? 0);
if ($id && $id !== $user['id']) {
$stmt = db()->prepare("DELETE FROM users WHERE id=?");
$stmt->execute([$id]);
set_flash('success', tr('تم حذف المستخدم بنجاح.', 'User deleted successfully.'));
} else {
set_flash('error', tr('لا يمكن حذف حسابك الحالي.', 'Cannot delete your own account.'));
}
redirect_to('users.php');
}
}
// Search logic // Search logic
$search = $_GET['q'] ?? ''; $search = $_GET['q'] ?? '';
$filteredAccounts = []; $searchQuery = "%{$search}%";
if ($search) { if ($search) {
$lowerSearch = strtolower($search); $stmt = db()->prepare("SELECT * FROM users WHERE name_ar LIKE ? OR name_en LIKE ? OR username LIKE ? ORDER BY id DESC");
foreach ($allAccounts as $key => $acc) { $stmt->execute([$searchQuery, $searchQuery, $searchQuery]);
if (
str_contains(strtolower((string)$acc['name_ar']), $lowerSearch) ||
str_contains(strtolower((string)$acc['name_en']), $lowerSearch) ||
str_contains(strtolower((string)$acc['username']), $lowerSearch)
) {
$filteredAccounts[$key] = $acc;
}
}
} else { } else {
$filteredAccounts = $allAccounts; $stmt = db()->query("SELECT * FROM users ORDER BY id DESC");
} }
$filteredAccounts = $stmt->fetchAll();
// Pagination logic // Pagination logic
$page = max(1, (int)($_GET['p'] ?? 1)); $page = max(1, (int)($_GET['p'] ?? 1));
@ -32,15 +93,17 @@ $totalPages = max(1, ceil($total / $limit));
$offset = ($page - 1) * $limit; $offset = ($page - 1) * $limit;
$accounts = array_slice($filteredAccounts, $offset, $limit, true); $accounts = array_slice($filteredAccounts, $offset, $limit, true);
$availableBranches = branches();
require __DIR__ . '/includes/header.php'; require __DIR__ . '/includes/header.php';
?> ?>
<section class="surface-card mb-4"> <section class="surface-card mb-4">
<div class="d-flex justify-content-between align-items-center mb-3"> <div class="d-flex justify-content-between align-items-center mb-3">
<div> <div>
<h3 class="h5 mb-2"><i class="bi bi-people me-2"></i><?= h(tr('الوصول حسب الدور', 'Role-based access')) ?></h3> <h3 class="h5 mb-2"><i class="bi bi-people me-2"></i><?= h(tr('الوصول حسب الدور', 'Role-based access')) ?></h3>
<p class="text-muted mb-0"><?= h(tr('الإصدار الأول يستخدم حسابات تجريبية منفصلة لإثبات هيكل الصلاحيات قبل ربط المستخدمين بقاعدة البيانات.', 'This first version uses separate demo accounts to prove the permissions model before wiring users into the database.')) ?></p> <p class="text-muted mb-0"><?= h(tr('إدارة المستخدمين وصلاحيات الوصول للنظام.', 'Manage users and system access permissions.')) ?></p>
</div> </div>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addUserModal"> <button type="button" class="btn btn-primary" onclick="openAddModal()">
<i class="bi bi-person-plus"></i> <?= h(tr('إضافة مستخدم', 'Add User')) ?> <i class="bi bi-person-plus"></i> <?= h(tr('إضافة مستخدم', 'Add User')) ?>
</button> </button>
</div> </div>
@ -51,6 +114,13 @@ require __DIR__ . '/includes/header.php';
<button class="btn btn-outline-secondary" type="submit"><i class="bi bi-search"></i></button> <button class="btn btn-outline-secondary" type="submit"><i class="bi bi-search"></i></button>
</div> </div>
</form> </form>
<?php if ($flash): ?>
<div class="alert alert-<?= h($flash['type'] === 'error' ? 'danger' : $flash['type']) ?> alert-dismissible fade show mt-3" role="alert">
<?= h($flash['message']) ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php endif; ?>
</section> </section>
<section class="surface-card"> <section class="surface-card">
@ -71,7 +141,7 @@ require __DIR__ . '/includes/header.php';
<?php if(empty($accounts)): ?> <?php if(empty($accounts)): ?>
<tr><td colspan="7" class="text-center text-muted py-4"><?= h(tr('لا توجد بيانات', 'No data found')) ?></td></tr> <tr><td colspan="7" class="text-center text-muted py-4"><?= h(tr('لا توجد بيانات', 'No data found')) ?></td></tr>
<?php endif; ?> <?php endif; ?>
<?php foreach ($accounts as $key => $account): ?> <?php foreach ($accounts as $account): ?>
<tr> <tr>
<td> <td>
<div class="fw-semibold"><?= h(current_lang() === 'ar' ? $account['name_ar'] : $account['name_en']) ?></div> <div class="fw-semibold"><?= h(current_lang() === 'ar' ? $account['name_ar'] : $account['name_en']) ?></div>
@ -83,12 +153,19 @@ require __DIR__ . '/includes/header.php';
<td><span class="badge <?= in_array($account['role'], ['owner', 'manager'], true) ? 'text-bg-light border' : 'text-bg-secondary' ?>"><?= h(in_array($account['role'], ['owner', 'manager'], true) ? tr('نعم', 'Yes') : tr('لا', 'No')) ?></span></td> <td><span class="badge <?= in_array($account['role'], ['owner', 'manager'], true) ? 'text-bg-light border' : 'text-bg-secondary' ?>"><?= h(in_array($account['role'], ['owner', 'manager'], true) ? tr('نعم', 'Yes') : tr('لا', 'No')) ?></span></td>
<td><span class="badge <?= $account['role'] === 'owner' ? 'text-bg-light border' : 'text-bg-secondary' ?>"><?= h($account['role'] === 'owner' ? tr('نعم', 'Yes') : tr('لا', 'No')) ?></span></td> <td><span class="badge <?= $account['role'] === 'owner' ? 'text-bg-light border' : 'text-bg-secondary' ?>"><?= h($account['role'] === 'owner' ? tr('نعم', 'Yes') : tr('لا', 'No')) ?></span></td>
<td> <td>
<button class="btn btn-sm btn-outline-primary rounded-circle shadow-sm" style="width: 34px; height: 34px; padding: 0;" onclick="mockEdit()" title="<?= h(tr('تعديل', 'Edit')) ?>"> <button class="btn btn-sm btn-outline-primary rounded-circle shadow-sm" style="width: 34px; height: 34px; padding: 0;"
onclick='openEditModal(<?= json_encode($account) ?>)' title="<?= h(tr('تعديل', 'Edit')) ?>">
<i class="bi bi-pencil"></i> <i class="bi bi-pencil"></i>
</button> </button>
<button class="btn btn-sm btn-outline-danger rounded-circle shadow-sm ms-1" style="width: 34px; height: 34px; padding: 0;" onclick="mockDelete()" title="<?= h(tr('حذف', 'Delete')) ?>"> <?php if ($account['id'] !== $user['id']): ?>
<i class="bi bi-trash"></i> <form method="POST" class="d-inline" onsubmit="return confirm('<?= h(tr('هل أنت متأكد؟', 'Are you sure?')) ?>');">
</button> <input type="hidden" name="action" value="delete">
<input type="hidden" name="id" value="<?= h($account['id']) ?>">
<button type="submit" class="btn btn-sm btn-outline-danger rounded-circle shadow-sm ms-1" style="width: 34px; height: 34px; padding: 0;" title="<?= h(tr('حذف', 'Delete')) ?>">
<i class="bi bi-trash"></i>
</button>
</form>
<?php endif; ?>
</td> </td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach; ?>
@ -109,35 +186,52 @@ require __DIR__ . '/includes/header.php';
<?php endif; ?> <?php endif; ?>
</section> </section>
<!-- Add User Modal --> <!-- User Modal -->
<div class="modal fade" id="addUserModal" tabindex="-1" aria-labelledby="addUserModalLabel" aria-hidden="true"> <div class="modal fade" id="userModal" tabindex="-1" aria-labelledby="userModalLabel" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog modal-lg">
<div class="modal-content"> <div class="modal-content">
<form id="addUserForm" onsubmit="handleUserSubmit(event)"> <form id="userForm" method="POST" action="users.php">
<input type="hidden" name="action" id="userAction" value="add">
<input type="hidden" name="id" id="userId" value="">
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title" id="addUserModalLabel"><?= h(tr('إضافة مستخدم جديد', 'Add New User')) ?></h5> <h5 class="modal-title" id="userModalLabel"><?= h(tr('إضافة مستخدم جديد', 'Add New User')) ?></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"> <div class="modal-body">
<div class="mb-3"> <div class="row">
<label for="userName" class="form-label"><?= h(tr('اسم المستخدم', 'Name')) ?></label> <div class="col-md-6 mb-3">
<input type="text" class="form-control" id="userName" required> <label for="userNameAr" class="form-label"><?= h(tr('الاسم (عربي)', 'Name (AR)')) ?></label>
</div> <input type="text" class="form-control" id="userNameAr" name="name_ar" required>
<div class="mb-3"> </div>
<label for="userRole" class="form-label"><?= h(tr('الدور', 'Role')) ?></label> <div class="col-md-6 mb-3">
<select class="form-select" id="userRole" required> <label for="userNameEn" class="form-label"><?= h(tr('الاسم (إنجليزي)', 'Name (EN)')) ?></label>
<option value="cashier"><?= h(tr('كاشير', 'Cashier')) ?></option> <input type="text" class="form-control" id="userNameEn" name="name_en">
<option value="manager"><?= h(tr('مدير فرع', 'Branch Manager')) ?></option> </div>
<option value="owner"><?= h(tr('مالك', 'Owner')) ?></option> <div class="col-md-6 mb-3">
</select> <label for="username" class="form-label"><?= h(tr('اسم المستخدم للدخول', 'Login Username')) ?></label>
</div> <input type="text" class="form-control" id="username" name="username" required autocomplete="new-username">
<div class="mb-3"> </div>
<label for="userBranch" class="form-label"><?= h(tr('الفرع', 'Branch')) ?></label> <div class="col-md-6 mb-3">
<select class="form-select" id="userBranch" required> <label for="password" class="form-label"><?= h(tr('كلمة المرور', 'Password')) ?> <small class="text-muted" id="passwordHelp"></small></label>
<option value="main"><?= h(tr('الرئيسي', 'Main')) ?></option> <input type="password" class="form-control" id="password" name="password" autocomplete="new-password">
<option value="north"><?= h(tr('الشمالي', 'North')) ?></option> </div>
<option value="south"><?= h(tr('الجنوبي', 'South')) ?></option> <div class="col-md-6 mb-3">
</select> <label for="userRole" class="form-label"><?= h(tr('الدور', 'Role')) ?></label>
<select class="form-select" id="userRole" name="role" required>
<option value="cashier"><?= h(tr('كاشير', 'Cashier')) ?></option>
<option value="manager"><?= h(tr('مدير فرع', 'Branch Manager')) ?></option>
<option value="owner"><?= h(tr('مالك', 'Owner')) ?></option>
</select>
</div>
<div class="col-md-6 mb-3">
<label for="userBranch" class="form-label"><?= h(tr('الفرع', 'Branch')) ?></label>
<select class="form-select" id="userBranch" name="branch_code" required>
<?php foreach ($availableBranches as $code => $b): ?>
<option value="<?= h($code) ?>"><?= h(current_lang() === 'ar' ? $b['name_ar'] : $b['name_en']) ?></option>
<?php endforeach; ?>
</select>
</div>
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
@ -150,54 +244,36 @@ require __DIR__ . '/includes/header.php';
</div> </div>
<script> <script>
function handleUserSubmit(e) { const userModal = new bootstrap.Modal(document.getElementById('userModal'));
e.preventDefault();
// Close the modal function openAddModal() {
var myModalEl = document.getElementById('addUserModal'); document.getElementById('userAction').value = 'add';
var modal = bootstrap.Modal.getInstance(myModalEl); document.getElementById('userId').value = '';
modal.hide(); document.getElementById('userForm').reset();
document.getElementById('userModalLabel').innerText = '<?= h(tr('إضافة مستخدم جديد', 'Add New User')) ?>';
// Show SweetAlert2 Success Message document.getElementById('password').required = true;
Swal.fire({ document.getElementById('passwordHelp').innerText = '';
title: '<?= h(tr('تم الحفظ!', 'Saved!')) ?>', userModal.show();
text: '<?= h(tr('تمت إضافة المستخدم بنجاح. (تجريبي)', 'User has been added successfully. (Demo)')) ?>',
icon: 'success',
confirmButtonText: '<?= h(tr('حسناً', 'OK')) ?>'
});
// Reset form
e.target.reset();
} }
function mockEdit() { function openEditModal(account) {
Swal.fire({ document.getElementById('userAction').value = 'edit';
title: '<?= h(tr('تعديل (تجريبي)', 'Edit (Demo)')) ?>', document.getElementById('userId').value = account.id;
text: '<?= h(tr('هذه الميزة غير مفعلة للبيانات التجريبية.', 'This feature is mock data and not active yet.')) ?>',
icon: 'info', document.getElementById('userNameAr').value = account.name_ar;
confirmButtonText: '<?= h(tr('حسناً', 'OK')) ?>' document.getElementById('userNameEn').value = account.name_en;
}); document.getElementById('username').value = account.username;
}
document.getElementById('userRole').value = account.role;
function mockDelete() { document.getElementById('userBranch').value = account.branch_code;
Swal.fire({
title: '<?= h(tr('هل أنت متأكد؟', 'Are you sure?')) ?>', document.getElementById('password').required = false;
text: '<?= h(tr('لن تتمكن من التراجع عن هذا!', "You won't be able to revert this!")) ?>', document.getElementById('password').value = '';
icon: 'warning', document.getElementById('passwordHelp').innerText = '(<?= h(tr('اتركه فارغاً لعدم التغيير', 'Leave blank to keep unchanged')) ?>)';
showCancelButton: true,
confirmButtonColor: '#dc3545', document.getElementById('userModalLabel').innerText = '<?= h(tr('تعديل مستخدم', 'Edit User')) ?>';
cancelButtonColor: '#6c757d', userModal.show();
confirmButtonText: '<?= h(tr('نعم، احذف', 'Yes, delete it!')) ?>',
cancelButtonText: '<?= h(tr('إلغاء', 'Cancel')) ?>'
}).then((result) => {
if (result.isConfirmed) {
Swal.fire(
'<?= h(tr('محذوف!', 'Deleted!')) ?>',
'<?= h(tr('حساب تجريبي لا يمكن حذفه.', 'Demo account cannot be deleted.')) ?>',
'success'
);
}
});
} }
</script> </script>
<?php require __DIR__ . '/includes/footer.php'; ?> <?php require __DIR__ . '/includes/footer.php'; ?>