update sales id
This commit is contained in:
parent
9b7ec271a9
commit
1ac0f55ef8
@ -166,4 +166,38 @@ body.auth-body {
|
||||
[dir="rtl"] .form-select-lg {
|
||||
padding-right: 1rem;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,4 +2,4 @@
|
||||
# https://curl.se/docs/http-cookies.html
|
||||
# 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
|
||||
|
||||
@ -46,6 +46,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
} else {
|
||||
$normalized = [];
|
||||
$subtotal = 0.0;
|
||||
$totalVat = 0.0;
|
||||
$itemCount = 0;
|
||||
foreach ($items as $item) {
|
||||
$sku = (string) ($item['sku'] ?? '');
|
||||
@ -56,6 +57,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$product = $catalog[$sku];
|
||||
$price = (float) $product['price'];
|
||||
$lineTotal = $price * $qty;
|
||||
|
||||
$vatPercent = (float) ($product['vat'] ?? 0);
|
||||
$itemVat = $lineTotal - ($lineTotal / (1 + ($vatPercent / 100)));
|
||||
$totalVat += $itemVat;
|
||||
|
||||
$normalized[] = [
|
||||
'sku' => $sku,
|
||||
'name_ar' => $product['name_ar'],
|
||||
@ -63,6 +69,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
'qty' => $qty,
|
||||
'price' => $price,
|
||||
'line_total' => $lineTotal,
|
||||
'vat_percent' => $vatPercent,
|
||||
'vat_amount' => $itemVat
|
||||
];
|
||||
$subtotal += $lineTotal;
|
||||
$itemCount += $qty;
|
||||
@ -79,6 +87,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
items_json = :items_json,
|
||||
item_count = :item_count,
|
||||
subtotal = :subtotal,
|
||||
vat_amount = :vat_amount,
|
||||
total_amount = :total_amount,
|
||||
status = :status,
|
||||
notes = :notes
|
||||
@ -380,8 +389,8 @@ require __DIR__ . '/includes/header.php';
|
||||
<span id="displaySubtotal" class="fw-medium">0.000</span>
|
||||
</div>
|
||||
<div class="totals-row">
|
||||
<span><?= h(tr('الضريبة (' . get_setting('vat_percentage', 5) . '%)', 'VAT (' . get_setting('vat_percentage', 5) . '%)')) ?></span>
|
||||
<span class="text-success small"><?= h(tr('مشمولة', 'Included')) ?></span>
|
||||
<span><?= h(tr('الضريبة (مشمولة)', 'VAT (Included)')) ?></span>
|
||||
<span id="displayVat" class="text-muted">0.000</span>
|
||||
</div>
|
||||
<div class="totals-row grand-total">
|
||||
<span><?= h(tr('الإجمالي', 'Total')) ?></span>
|
||||
@ -633,18 +642,24 @@ function renderInvoice() {
|
||||
if (skus.length === 0) {
|
||||
tbody.innerHTML = '';
|
||||
tbody.appendChild(emptyRow);
|
||||
updateTotals(0);
|
||||
updateTotals(0, 0);
|
||||
cartJson.value = '[]';
|
||||
return;
|
||||
}
|
||||
|
||||
tbody.innerHTML = '';
|
||||
let totalAmount = 0;
|
||||
let totalVat = 0;
|
||||
const cartData = [];
|
||||
|
||||
skus.forEach(sku => {
|
||||
const item = invoiceItems[sku];
|
||||
const lineTotal = item.qty * item.price;
|
||||
|
||||
const vatPercent = parseFloat(catalogData[sku].vat) || 0;
|
||||
const itemVat = lineTotal - (lineTotal / (1 + (vatPercent / 100)));
|
||||
totalVat += itemVat;
|
||||
|
||||
totalAmount += lineTotal;
|
||||
cartData.push({ sku: item.sku, qty: item.qty });
|
||||
|
||||
@ -668,12 +683,14 @@ function renderInvoice() {
|
||||
tbody.appendChild(tr);
|
||||
});
|
||||
|
||||
updateTotals(totalAmount);
|
||||
updateTotals(totalAmount, totalVat);
|
||||
cartJson.value = JSON.stringify(cartData);
|
||||
}
|
||||
|
||||
function updateTotals(total) {
|
||||
document.getElementById('displaySubtotal').innerText = total.toFixed(3);
|
||||
function updateTotals(total, vat) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -115,35 +115,6 @@ function branch_label(string $code): string
|
||||
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
|
||||
{
|
||||
@ -162,18 +133,21 @@ function current_user(): ?array
|
||||
|
||||
function login_attempt(string $username, string $password): bool
|
||||
{
|
||||
$users = demo_users();
|
||||
if (!isset($users[$username])) {
|
||||
require_once __DIR__ . "/../db/config.php";
|
||||
$stmt = db()->prepare("SELECT * FROM users WHERE username = ?");
|
||||
$stmt->execute([$username]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if (!$user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$user = $users[$username];
|
||||
if ($user['password'] !== $password) {
|
||||
return false;
|
||||
if (password_verify($password, $user["password"])) {
|
||||
$_SESSION["auth_user"] = $user;
|
||||
return true;
|
||||
}
|
||||
|
||||
$_SESSION['auth_user'] = $user;
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function logout_user(): void
|
||||
@ -525,7 +499,7 @@ function purchase_pipeline(): array
|
||||
|
||||
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
|
||||
|
||||
@ -31,6 +31,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
} else {
|
||||
$normalized = [];
|
||||
$subtotal = 0.0;
|
||||
$totalVat = 0.0;
|
||||
$itemCount = 0;
|
||||
foreach ($items as $item) {
|
||||
$sku = (string) ($item['sku'] ?? '');
|
||||
@ -41,6 +42,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$product = $catalog[$sku];
|
||||
$price = (float) $product['price'];
|
||||
$lineTotal = $price * $qty;
|
||||
|
||||
$vatPercent = (float) ($product['vat'] ?? 0);
|
||||
// Assuming price is inclusive of VAT:
|
||||
$itemVat = $lineTotal - ($lineTotal / (1 + ($vatPercent / 100)));
|
||||
$totalVat += $itemVat;
|
||||
|
||||
$normalized[] = [
|
||||
'sku' => $sku,
|
||||
'name_ar' => $product['name_ar'],
|
||||
@ -48,6 +55,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
'qty' => $qty,
|
||||
'price' => $price,
|
||||
'line_total' => $lineTotal,
|
||||
'vat_percent' => $vatPercent,
|
||||
'vat_amount' => $itemVat
|
||||
];
|
||||
$subtotal += $lineTotal;
|
||||
$itemCount += $qty;
|
||||
@ -68,7 +77,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
'payment_method' => $paymentMethod,
|
||||
'items' => $normalized,
|
||||
'item_count' => $itemCount,
|
||||
'subtotal' => $subtotal,
|
||||
'subtotal' => $subtotal - $totalVat,
|
||||
'vat_amount' => $totalVat,
|
||||
'total_amount' => $subtotal,
|
||||
'status' => $saleStatus,
|
||||
'notes' => $notes !== '' ? $notes : null,
|
||||
@ -360,8 +370,8 @@ require __DIR__ . '/header.php';
|
||||
<span id="displaySubtotal" class="fw-medium">0.000</span>
|
||||
</div>
|
||||
<div class="totals-row">
|
||||
<span><?= h(tr('الضريبة (' . get_setting('vat_percentage', 5) . '%)', 'VAT (' . get_setting('vat_percentage', 5) . '%)')) ?></span>
|
||||
<span class="text-success small"><?= h(tr('مشمولة', 'Included')) ?></span>
|
||||
<span><?= h(tr('الضريبة (مشمولة)', 'VAT (Included)')) ?></span>
|
||||
<span id="displayVat" class="text-muted">0.000</span>
|
||||
</div>
|
||||
<div class="totals-row grand-total">
|
||||
<span><?= h(tr('الإجمالي', 'Total')) ?></span>
|
||||
@ -601,18 +611,24 @@ function renderInvoice() {
|
||||
if (skus.length === 0) {
|
||||
tbody.innerHTML = '';
|
||||
tbody.appendChild(emptyRow);
|
||||
updateTotals(0);
|
||||
updateTotals(0, 0);
|
||||
cartJson.value = '[]';
|
||||
return;
|
||||
}
|
||||
|
||||
tbody.innerHTML = '';
|
||||
let totalAmount = 0;
|
||||
let totalVat = 0;
|
||||
const cartData = [];
|
||||
|
||||
skus.forEach(sku => {
|
||||
const item = invoiceItems[sku];
|
||||
const lineTotal = item.qty * item.price;
|
||||
|
||||
const vatPercent = parseFloat(catalogData[sku].vat) || 0;
|
||||
const itemVat = lineTotal - (lineTotal / (1 + (vatPercent / 100)));
|
||||
totalVat += itemVat;
|
||||
|
||||
totalAmount += lineTotal;
|
||||
cartData.push({ sku: item.sku, qty: item.qty });
|
||||
|
||||
@ -636,12 +652,14 @@ function renderInvoice() {
|
||||
tbody.appendChild(tr);
|
||||
});
|
||||
|
||||
updateTotals(totalAmount);
|
||||
updateTotals(totalAmount, totalVat);
|
||||
cartJson.value = JSON.stringify(cartData);
|
||||
}
|
||||
|
||||
function updateTotals(total) {
|
||||
document.getElementById('displaySubtotal').innerText = total.toFixed(3);
|
||||
function updateTotals(total, vat) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
21
login.php
21
login.php
@ -35,7 +35,7 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? '';
|
||||
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
|
||||
$projectName = $_SERVER['PROJECT_NAME'] ?? app_name();
|
||||
$assetVersion = date('YmdHi');
|
||||
$accounts = demo_users();
|
||||
$accounts = [];
|
||||
?>
|
||||
<!doctype html>
|
||||
<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>
|
||||
</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>
|
||||
|
||||
@ -248,8 +248,8 @@ $registerNo = 'REG-01';
|
||||
<span><?= number_format((float)$sale['subtotal'], 3) ?></span>
|
||||
</div>
|
||||
<div class="totals-row">
|
||||
<span><?= h(tr('ضريبة القيمة المضافة (' . get_setting('vat_percentage', 5) . '%)', 'VAT (' . get_setting('vat_percentage', 5) . '%)')) ?></span>
|
||||
<span><?= h(tr('شامل', 'Inclusive')) ?></span>
|
||||
<span><?= h(tr('ضريبة القيمة المضافة (مشمولة)', 'VAT (Inclusive)')) ?></span>
|
||||
<span><?= number_format((float)($sale['vat_amount'] ?? 0), 3) ?></span>
|
||||
</div>
|
||||
<div class="totals-row grand-total">
|
||||
<span><?= h(tr('الإجمالي', 'Total')) ?></span>
|
||||
|
||||
331
reports.php
331
reports.php
@ -3,50 +3,301 @@ require_once __DIR__ . '/includes/app.php';
|
||||
$user = require_roles(['owner', 'manager']);
|
||||
$pageTitle = tr('التقارير', 'Reports');
|
||||
$activeNav = 'reports';
|
||||
|
||||
$tab = $_GET['tab'] ?? 'summary';
|
||||
$dbError = null;
|
||||
$report = ['gross' => 0.0, 'branch_totals' => [], 'payment_totals' => [], 'product_totals' => [], 'sales_count' => 0];
|
||||
try {
|
||||
$report = report_metrics();
|
||||
} catch (Throwable $e) {
|
||||
$dbError = $e->getMessage();
|
||||
|
||||
if ($tab === 'sales') {
|
||||
$dateFrom = $_GET['date_from'] ?? date('Y-m-01');
|
||||
$dateTo = $_GET['date_to'] ?? date('Y-m-t');
|
||||
$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';
|
||||
?>
|
||||
<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="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">
|
||||
<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 class="d-flex justify-content-between align-items-center mb-4 d-print-none">
|
||||
<div>
|
||||
<h1 class="h3 mb-0"><?= h($pageTitle) ?></h1>
|
||||
</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>
|
||||
|
||||
<ul class="nav nav-tabs mb-4 d-print-none">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= $tab === 'summary' ? 'active' : '' ?>" href="reports.php?tab=summary"><?= h(tr('ملخص عام', 'General Summary')) ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= $tab === 'sales' ? 'active' : '' ?>" href="reports.php?tab=sales"><?= h(tr('تقرير المبيعات', 'Sales Report')) ?></a>
|
||||
</li>
|
||||
<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>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<?php require __DIR__ . '/includes/footer.php'; ?>
|
||||
|
||||
<div class="d-none d-print-block mb-4 text-center">
|
||||
<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'; ?>
|
||||
4
sale.php
4
sale.php
@ -424,8 +424,8 @@ require __DIR__ . '/includes/header.php';
|
||||
<td class="total-amount"><?= h(number_format((float) $sale['subtotal'], 3)) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="total-label"><?= h(tr('ضريبة القيمة المضافة (' . get_setting('vat_percentage', 5) . '%)', 'VAT (' . get_setting('vat_percentage', 5) . '%)')) ?></td>
|
||||
<td class="total-amount"><?= h(tr('شامل', 'Inclusive')) ?></td>
|
||||
<td class="total-label"><?= h(tr('ضريبة القيمة المضافة (مشمولة)', 'VAT (Inclusive)')) ?></td>
|
||||
<td class="total-amount"><?= number_format((float)($sale['vat_amount'] ?? 0), 3) ?></td>
|
||||
</tr>
|
||||
<tr class="grand-total-row">
|
||||
<td class="total-label"><?= h(tr('الإجمالي', 'Total')) ?></td>
|
||||
|
||||
@ -14,7 +14,8 @@ if (isset($_GET['mark_paid']) && is_numeric($_GET['mark_paid'])) {
|
||||
$id = (int)$_GET['mark_paid'];
|
||||
db()->prepare("UPDATE sales_orders SET status = 'completed' WHERE id = ?")->execute([$id]);
|
||||
} catch(Throwable $e) {}
|
||||
header("Location: sales.php");
|
||||
$redirect = $_GET["redirect"] ?? "sales.php";
|
||||
header("Location: " . $redirect);
|
||||
exit;
|
||||
}
|
||||
|
||||
@ -99,7 +100,7 @@ require __DIR__ . '/includes/header.php';
|
||||
<input type="hidden" name="mode" value="<?= h($mode) ?>">
|
||||
<?php endif; ?>
|
||||
<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="completed" <?= $statusFilter === 'completed' ? 'selected' : '' ?>><?= h(tr('مدفوع', 'Paid')) ?></option>
|
||||
<option value="order" <?= $statusFilter === 'order' ? 'selected' : '' ?>><?= h(tr('طلب حجز', 'Order')) ?></option>
|
||||
|
||||
256
users.php
256
users.php
@ -4,25 +4,86 @@ $user = require_roles(['owner']);
|
||||
$pageTitle = tr('المستخدمون والأدوار', 'Users & Roles');
|
||||
$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 = $_GET['q'] ?? '';
|
||||
$filteredAccounts = [];
|
||||
$searchQuery = "%{$search}%";
|
||||
|
||||
if ($search) {
|
||||
$lowerSearch = strtolower($search);
|
||||
foreach ($allAccounts as $key => $acc) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
$stmt = db()->prepare("SELECT * FROM users WHERE name_ar LIKE ? OR name_en LIKE ? OR username LIKE ? ORDER BY id DESC");
|
||||
$stmt->execute([$searchQuery, $searchQuery, $searchQuery]);
|
||||
} else {
|
||||
$filteredAccounts = $allAccounts;
|
||||
$stmt = db()->query("SELECT * FROM users ORDER BY id DESC");
|
||||
}
|
||||
$filteredAccounts = $stmt->fetchAll();
|
||||
|
||||
// Pagination logic
|
||||
$page = max(1, (int)($_GET['p'] ?? 1));
|
||||
@ -32,15 +93,17 @@ $totalPages = max(1, ceil($total / $limit));
|
||||
$offset = ($page - 1) * $limit;
|
||||
$accounts = array_slice($filteredAccounts, $offset, $limit, true);
|
||||
|
||||
$availableBranches = branches();
|
||||
|
||||
require __DIR__ . '/includes/header.php';
|
||||
?>
|
||||
<section class="surface-card mb-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<div>
|
||||
<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>
|
||||
<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')) ?>
|
||||
</button>
|
||||
</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>
|
||||
</div>
|
||||
</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 class="surface-card">
|
||||
@ -71,7 +141,7 @@ require __DIR__ . '/includes/header.php';
|
||||
<?php if(empty($accounts)): ?>
|
||||
<tr><td colspan="7" class="text-center text-muted py-4"><?= h(tr('لا توجد بيانات', 'No data found')) ?></td></tr>
|
||||
<?php endif; ?>
|
||||
<?php foreach ($accounts as $key => $account): ?>
|
||||
<?php foreach ($accounts as $account): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<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 <?= $account['role'] === 'owner' ? 'text-bg-light border' : 'text-bg-secondary' ?>"><?= h($account['role'] === 'owner' ? tr('نعم', 'Yes') : tr('لا', 'No')) ?></span></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>
|
||||
</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')) ?>">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
<?php if ($account['id'] !== $user['id']): ?>
|
||||
<form method="POST" class="d-inline" onsubmit="return confirm('<?= h(tr('هل أنت متأكد؟', 'Are you sure?')) ?>');">
|
||||
<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>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
@ -109,35 +186,52 @@ require __DIR__ . '/includes/header.php';
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
|
||||
<!-- Add User Modal -->
|
||||
<div class="modal fade" id="addUserModal" tabindex="-1" aria-labelledby="addUserModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<!-- User Modal -->
|
||||
<div class="modal fade" id="userModal" tabindex="-1" aria-labelledby="userModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<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">
|
||||
<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>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label for="userName" class="form-label"><?= h(tr('اسم المستخدم', 'Name')) ?></label>
|
||||
<input type="text" class="form-control" id="userName" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="userRole" class="form-label"><?= h(tr('الدور', 'Role')) ?></label>
|
||||
<select class="form-select" id="userRole" 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="mb-3">
|
||||
<label for="userBranch" class="form-label"><?= h(tr('الفرع', 'Branch')) ?></label>
|
||||
<select class="form-select" id="userBranch" required>
|
||||
<option value="main"><?= h(tr('الرئيسي', 'Main')) ?></option>
|
||||
<option value="north"><?= h(tr('الشمالي', 'North')) ?></option>
|
||||
<option value="south"><?= h(tr('الجنوبي', 'South')) ?></option>
|
||||
</select>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="userNameAr" class="form-label"><?= h(tr('الاسم (عربي)', 'Name (AR)')) ?></label>
|
||||
<input type="text" class="form-control" id="userNameAr" name="name_ar" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="userNameEn" class="form-label"><?= h(tr('الاسم (إنجليزي)', 'Name (EN)')) ?></label>
|
||||
<input type="text" class="form-control" id="userNameEn" name="name_en">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="username" class="form-label"><?= h(tr('اسم المستخدم للدخول', 'Login Username')) ?></label>
|
||||
<input type="text" class="form-control" id="username" name="username" required autocomplete="new-username">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="password" class="form-label"><?= h(tr('كلمة المرور', 'Password')) ?> <small class="text-muted" id="passwordHelp"></small></label>
|
||||
<input type="password" class="form-control" id="password" name="password" autocomplete="new-password">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<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 class="modal-footer">
|
||||
@ -150,54 +244,36 @@ require __DIR__ . '/includes/header.php';
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function handleUserSubmit(e) {
|
||||
e.preventDefault();
|
||||
// Close the modal
|
||||
var myModalEl = document.getElementById('addUserModal');
|
||||
var modal = bootstrap.Modal.getInstance(myModalEl);
|
||||
modal.hide();
|
||||
|
||||
// Show SweetAlert2 Success Message
|
||||
Swal.fire({
|
||||
title: '<?= h(tr('تم الحفظ!', 'Saved!')) ?>',
|
||||
text: '<?= h(tr('تمت إضافة المستخدم بنجاح. (تجريبي)', 'User has been added successfully. (Demo)')) ?>',
|
||||
icon: 'success',
|
||||
confirmButtonText: '<?= h(tr('حسناً', 'OK')) ?>'
|
||||
});
|
||||
|
||||
// Reset form
|
||||
e.target.reset();
|
||||
const userModal = new bootstrap.Modal(document.getElementById('userModal'));
|
||||
|
||||
function openAddModal() {
|
||||
document.getElementById('userAction').value = 'add';
|
||||
document.getElementById('userId').value = '';
|
||||
document.getElementById('userForm').reset();
|
||||
document.getElementById('userModalLabel').innerText = '<?= h(tr('إضافة مستخدم جديد', 'Add New User')) ?>';
|
||||
document.getElementById('password').required = true;
|
||||
document.getElementById('passwordHelp').innerText = '';
|
||||
userModal.show();
|
||||
}
|
||||
|
||||
function mockEdit() {
|
||||
Swal.fire({
|
||||
title: '<?= h(tr('تعديل (تجريبي)', 'Edit (Demo)')) ?>',
|
||||
text: '<?= h(tr('هذه الميزة غير مفعلة للبيانات التجريبية.', 'This feature is mock data and not active yet.')) ?>',
|
||||
icon: 'info',
|
||||
confirmButtonText: '<?= h(tr('حسناً', 'OK')) ?>'
|
||||
});
|
||||
}
|
||||
|
||||
function mockDelete() {
|
||||
Swal.fire({
|
||||
title: '<?= h(tr('هل أنت متأكد؟', 'Are you sure?')) ?>',
|
||||
text: '<?= h(tr('لن تتمكن من التراجع عن هذا!', "You won't be able to revert this!")) ?>',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#dc3545',
|
||||
cancelButtonColor: '#6c757d',
|
||||
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'
|
||||
);
|
||||
}
|
||||
});
|
||||
function openEditModal(account) {
|
||||
document.getElementById('userAction').value = 'edit';
|
||||
document.getElementById('userId').value = account.id;
|
||||
|
||||
document.getElementById('userNameAr').value = account.name_ar;
|
||||
document.getElementById('userNameEn').value = account.name_en;
|
||||
document.getElementById('username').value = account.username;
|
||||
|
||||
document.getElementById('userRole').value = account.role;
|
||||
document.getElementById('userBranch').value = account.branch_code;
|
||||
|
||||
document.getElementById('password').required = false;
|
||||
document.getElementById('password').value = '';
|
||||
document.getElementById('passwordHelp').innerText = '(<?= h(tr('اتركه فارغاً لعدم التغيير', 'Leave blank to keep unchanged')) ?>)';
|
||||
|
||||
document.getElementById('userModalLabel').innerText = '<?= h(tr('تعديل مستخدم', 'Edit User')) ?>';
|
||||
userModal.show();
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php require __DIR__ . '/includes/footer.php'; ?>
|
||||
<?php require __DIR__ . '/includes/footer.php'; ?>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user