updating service

This commit is contained in:
Flatlogic Bot 2026-03-03 10:35:21 +00:00
parent 1de3f1d7d1
commit 538704f9d0
7 changed files with 351 additions and 131 deletions

View File

@ -111,7 +111,7 @@ body {
/* Print Styles */
@media print {
.sidebar, .navbar, .no-print, .btn, .card form {
.sidebar, .navbar, .no-print, .btn, .card form, header, .breadcrumb, footer {
display: none !important;
}
body {
@ -121,7 +121,9 @@ body {
}
.main-content {
margin-left: 0 !important;
margin-right: 0 !important;
width: 100% !important;
padding: 0 !important;
}
.card {
box-shadow: none !important;
@ -136,4 +138,4 @@ body {
max-width: 100% !important;
height: auto !important;
}
}
}

View File

@ -92,6 +92,14 @@ foreach ($transactions as &$t) {
$t['running_balance'] = $balance;
}
// Fallback values if database is empty
$display_company_name = ($lang === 'ar' ? ($company_info['name_ar'] ?: $company_info['name_en']) : $company_info['name_en']) ?: 'Laundry Brand';
$display_address = ($lang === 'ar' ? ($company_info['address_ar'] ?: $company_info['address_en']) : $company_info['address_en']);
$display_phone = $company_info['phone'];
$display_email = $company_info['email'];
$display_vat = $company_info['vat_no'] ?: $company_info['vat_number'];
$display_ctr = $company_info['ctr_no'];
?>
<div class="d-print-none mb-4">
@ -130,27 +138,46 @@ foreach ($transactions as &$t) {
<div class="d-none d-print-block mb-5">
<div class="row align-items-center mb-4">
<div class="col-7">
<?php if ($company_info['logo']): ?>
<?php if (!empty($company_info['logo'])): ?>
<img src="<?= $company_info['logo'] ?>" alt="Logo" style="max-height: 100px;" class="mb-3">
<?php else: ?>
<div class="mb-3 d-flex align-items-center text-primary">
<i class="bi bi-tsunami fs-1 me-2"></i>
<span class="fs-4 fw-bold">Laundry Management</span>
</div>
<?php endif; ?>
<h2 class="fw-bold mb-1"><?= htmlspecialchars(is_arabic() ? $company_info['name_ar'] : $company_info['name_en']) ?></h2>
<p class="mb-0 text-muted">
<?= is_arabic() ? ($company_info['address_ar'] ?? '') : ($company_info['address_en'] ?? '') ?><br>
<?= __('phone') ?>: <?= $company_info['phone'] ?? '' ?> | <?= __('email') ?>: <?= $company_info['email'] ?? '' ?><br>
<?php if ($company_info['vat_no']): ?>
<?= __('vat_no') ?>: <?= $company_info['vat_no'] ?>
<h2 class="fw-bold mb-1"><?= htmlspecialchars($display_company_name) ?></h2>
<div class="mb-0 text-muted small">
<?php if ($display_address): ?>
<?= htmlspecialchars($display_address) ?><br>
<?php endif; ?>
<?php if ($company_info['ctr_no']): ?>
| <?= __('ctr_no') ?>: <?= $company_info['ctr_no'] ?>
<?php if ($display_phone): ?>
<?= __('phone') ?>: <?= htmlspecialchars($display_phone) ?>
<?php endif; ?>
</p>
<?php if ($display_email): ?>
<?= $display_phone ? ' | ' : '' ?><?= __('email') ?>: <?= htmlspecialchars($display_email) ?><br>
<?php elseif($display_phone): ?>
<br>
<?php endif; ?>
<?php if ($display_vat): ?>
<?= __('vat_no') ?>: <?= htmlspecialchars($display_vat) ?>
<?php endif; ?>
<?php if ($display_ctr): ?>
<?= $display_vat ? ' | ' : '' ?><?= __('ctr_no') ?>: <?= htmlspecialchars($display_ctr) ?>
<?php endif; ?>
</div>
</div>
<div class="col-5 text-end">
<h1 class="fw-bold text-uppercase mb-2" style="color: #0d6efd;"><?= __('statement') ?></h1>
<div class="mt-3">
<p class="mb-0 fw-bold"><?= __('date') ?>: <?= date('d/m/Y') ?></p>
<p class="mb-0 text-muted small"><?= __('cashier') ?>: <?= htmlspecialchars($_SESSION['full_name'] ?? 'System Admin') ?></p>
<?php if ($from_date || $to_date): ?>
<p class="mb-0 text-muted small">
<p class="mb-0 text-muted small mt-1">
<?= $from_date ? __('from_date') . ': ' . date('d/m/Y', strtotime($from_date)) : '' ?>
<?= $to_date ? ' ' . __('to_date') . ': ' . date('d/m/Y', strtotime($to_date)) : '' ?>
</p>
@ -161,9 +188,9 @@ foreach ($transactions as &$t) {
<div class="row p-3 bg-light rounded-3 mb-4 mx-0 border">
<div class="col-12">
<h6 class="fw-bold text-muted text-uppercase mb-2"><?= __('customer_details') ?></h6>
<h6 class="fw-bold text-muted text-uppercase mb-2 small"><?= __('customer_details') ?></h6>
<h4 class="fw-bold mb-1"><?= $lang === 'ar' ? ($customer['name_ar'] ?: $customer['name_en']) : $customer['name_en'] ?></h4>
<p class="mb-0 text-muted"><?= $customer['phone'] ?> | <?= $customer['email'] ?></p>
<p class="mb-0 text-muted small"><?= $customer['phone'] ?> <?= $customer['email'] ? ' | ' . $customer['email'] : '' ?></p>
</div>
</div>
</div>
@ -171,7 +198,7 @@ foreach ($transactions as &$t) {
<!-- Screen Header -->
<div class="d-print-none mb-4">
<h4 class="fw-bold mb-1"><?= $lang === 'ar' ? ($customer['name_ar'] ?: $customer['name_en']) : $customer['name_en'] ?></h4>
<p class="text-muted mb-0"><?= $customer['phone'] ?> | <?= $customer['email'] ?></p>
<p class="text-muted mb-0"><?= $customer['phone'] ?> <?= $customer['email'] ? ' | ' . $customer['email'] : '' ?></p>
</div>
<div class="table-responsive">
@ -221,34 +248,53 @@ foreach ($transactions as &$t) {
<div class="col-md-5 ms-auto">
<div class="card bg-white border" style="border-radius: 15px;">
<div class="card-body p-4">
<h5 class="fw-bold mb-4 border-bottom pb-2"><?= __('summary') ?? 'Summary' ?></h5>
<h5 class="fw-bold mb-4 border-bottom pb-2 small text-uppercase text-muted"><?= __('summary') ?? 'Summary' ?></h5>
<div class="d-flex justify-content-between mb-2">
<span class="text-muted"><?= __('total_debit') ?>:</span>
<span class="fw-bold"><?= format_amount($total_debit) ?></span>
<span class="text-muted small"><?= __('total_debit') ?>:</span>
<span class="fw-bold small"><?= format_amount($total_debit) ?></span>
</div>
<div class="d-flex justify-content-between mb-2">
<span class="text-muted"><?= __('total_credit') ?>:</span>
<span class="fw-bold"><?= format_amount($total_credit) ?></span>
<span class="text-muted small"><?= __('total_credit') ?>:</span>
<span class="fw-bold small"><?= format_amount($total_credit) ?></span>
</div>
<div class="d-flex justify-content-between pt-2 mt-2 border-top">
<span class="fw-bold fs-5"><?= __('closing_balance') ?>:</span>
<span class="fw-bold text-primary fs-5"><?= format_amount($balance) ?></span>
<span class="fw-bold fs-6"><?= __('closing_balance') ?>:</span>
<span class="fw-bold text-primary fs-6"><?= format_amount($balance) ?></span>
</div>
</div>
</div>
</div>
</div>
<!-- Print Footer -->
<div class="d-none d-print-block mt-5 pt-4 border-top">
<div class="row text-center small text-muted">
<div class="col-4">
<div class="mb-4">_______________________</div>
<div><?= __('customer_signature') ?? 'Customer Signature' ?></div>
</div>
<div class="col-4">
<div class="mb-4"><?= date('d/m/Y H:i') ?></div>
<div><?= __('print_date') ?? 'Print Date' ?></div>
</div>
<div class="col-4">
<div class="mb-4">_______________________</div>
<div><?= __('authorized_signature') ?? 'Authorized Signature' ?></div>
</div>
</div>
</div>
</div>
<style>
@media print {
@page {
size: auto;
margin: 15mm;
margin: 10mm 15mm;
}
body {
background-color: white !important;
font-size: 11px;
-webkit-print-color-adjust: exact;
}
.main-content {
padding: 0 !important;
@ -294,10 +340,6 @@ foreach ($transactions as &$t) {
background-color: #212529 !important;
color: white !important;
}
/* Hide Browser Headers/Footers */
title, .navbar {
display: none !important;
}
}
</style>

View File

@ -221,7 +221,7 @@ if ($current_user_id && $current_page !== 'login.php' && $current_page !== 'logo
<div class="container-fluid">
<div class="row">
<!-- Sidebar -->
<nav class="col-md-3 col-lg-2 d-md-block sidebar collapse">
<nav class="col-md-3 col-lg-2 d-md-block sidebar collapse no-print">
<div class="position-sticky">
<div class="px-4 mb-4 mt-2 text-center">
<?php if ($company_info['logo']): ?>
@ -337,7 +337,7 @@ if ($current_user_id && $current_page !== 'login.php' && $current_page !== 'logo
<!-- Main Content -->
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4 main-content">
<header class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
<header class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom no-print">
<h1 class="h2"><?= __($title ?? 'dashboard') ?></h1>
<div class="mb-2 mb-md-0">
<div class="d-flex align-items-center">
@ -472,4 +472,4 @@ if ($current_user_id && $current_page !== 'login.php' && $current_page !== 'logo
</div>
</div>
</div>
</header>
</header>

225
items.php
View File

@ -67,9 +67,64 @@ function deleteOldImage($imageUrl) {
}
}
// Helper to render category list HTML for AJAX
function renderCategoryList($lang) {
$categories = db()->query("SELECT * FROM categories ORDER BY name_en ASC")->fetchAll();
$html = '';
foreach($categories as $cat) {
$html .= '<tr>
<td>
<strong>' . htmlspecialchars($cat['name_en']) . '</strong><br>
<small class="text-muted">' . htmlspecialchars($cat['name_ar']) . '</small>
</td>
<td class="text-end">
';
if (has_permission('edit')) {
$html .= '<button type="button" class="btn btn-sm btn-light p-2 me-1" style="border-radius: 8px;" onclick="editCategory(' . htmlspecialchars(json_encode($cat), ENT_QUOTES) . ')">
<i class="bi bi-pencil text-primary"></i>
</button>';
}
if (has_permission('delete')) {
$html .= '<button type="button" class="btn btn-sm btn-light p-2" style="border-radius: 8px;" onclick="confirmDeleteAjax(\'category\', ' . $cat['id'] . ')">
<i class="bi bi-trash text-danger"></i>
</button>';
}
$html .= '</td></tr>';
}
return $html;
}
// Helper to render service list HTML for AJAX
function renderServiceList($lang) {
$services = db()->query("SELECT * FROM services ORDER BY name_en ASC")->fetchAll();
$html = '';
foreach($services as $svc) {
$html .= '<tr>
<td>
<strong>' . htmlspecialchars($svc['name_en']) . '</strong><br>
<small class="text-muted">' . htmlspecialchars($svc['name_ar']) . '</small>
</td>
<td class="text-end">
';
if (has_permission('edit')) {
$html .= '<button type="button" class="btn btn-sm btn-light p-2 me-1" style="border-radius: 8px;" onclick="editService(' . htmlspecialchars(json_encode($svc), ENT_QUOTES) . ')">
<i class="bi bi-pencil text-primary"></i>
</button>';
}
if (has_permission('delete')) {
$html .= '<button type="button" class="btn btn-sm btn-light p-2" style="border-radius: 8px;" onclick="confirmDeleteAjax(\'service\', ' . $svc['id'] . ')">
<i class="bi bi-trash text-danger"></i>
</button>';
}
$html .= '</td></tr>';
}
return $html;
}
// Handle Actions
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
$action = $_POST['action'];
$isAjax = isset($_POST['ajax']);
// Permission mapping for actions
$required_permission = 'view';
@ -78,7 +133,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
if (strpos($action, 'delete_') === 0) $required_permission = 'delete';
if (!has_permission($required_permission)) {
if (isset($_POST['ajax'])) {
if ($isAjax) {
header('Content-Type: application/json');
echo json_encode(['success' => false, 'error' => 'Forbidden']);
exit;
@ -140,6 +195,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
$name_ar = $_POST['cat_name_ar'];
$stmt = db()->prepare("INSERT INTO categories (name_en, name_ar) VALUES (?, ?)");
$stmt->execute([$name_en, $name_ar]);
if ($isAjax) {
header('Content-Type: application/json');
echo json_encode(['success' => true, 'html' => renderCategoryList($lang)]);
exit;
}
header('Location: items.php?success=category_added');
exit;
} elseif ($action === 'edit_category') {
@ -148,12 +209,24 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
$name_ar = $_POST['cat_name_ar'];
$stmt = db()->prepare("UPDATE categories SET name_en = ?, name_ar = ? WHERE id = ?");
$stmt->execute([$name_en, $name_ar, $id]);
if ($isAjax) {
header('Content-Type: application/json');
echo json_encode(['success' => true, 'html' => renderCategoryList($lang)]);
exit;
}
header('Location: items.php?success=category_updated');
exit;
} elseif ($action === 'delete_category') {
$id = $_POST['id'];
$stmt = db()->prepare("DELETE FROM categories WHERE id = ?");
$stmt->execute([$id]);
if ($isAjax) {
header('Content-Type: application/json');
echo json_encode(['success' => true, 'html' => renderCategoryList($lang)]);
exit;
}
header('Location: items.php?success=category_deleted');
exit;
} elseif ($action === 'add_service') {
@ -161,6 +234,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
$name_ar = $_POST['svc_name_ar'];
$stmt = db()->prepare("INSERT INTO services (name_en, name_ar) VALUES (?, ?)");
$stmt->execute([$name_en, $name_ar]);
if ($isAjax) {
header('Content-Type: application/json');
echo json_encode(['success' => true, 'html' => renderServiceList($lang)]);
exit;
}
header('Location: items.php?success=service_added');
exit;
} elseif ($action === 'edit_service') {
@ -169,12 +248,24 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
$name_ar = $_POST['svc_name_ar'];
$stmt = db()->prepare("UPDATE services SET name_en = ?, name_ar = ? WHERE id = ?");
$stmt->execute([$name_en, $name_ar, $id]);
if ($isAjax) {
header('Content-Type: application/json');
echo json_encode(['success' => true, 'html' => renderServiceList($lang)]);
exit;
}
header('Location: items.php?success=service_updated');
exit;
} elseif ($action === 'delete_service') {
$id = $_POST['id'];
$stmt = db()->prepare("DELETE FROM services WHERE id = ?");
$stmt->execute([$id]);
if ($isAjax) {
header('Content-Type: application/json');
echo json_encode(['success' => true, 'html' => renderServiceList($lang)]);
exit;
}
header('Location: items.php?success=service_deleted');
exit;
} elseif ($action === 'update_price') {
@ -341,16 +432,16 @@ foreach ($prices_raw as $p) {
<div class="bg-light rounded-3 me-3 d-flex align-items-center justify-content-center" style="width: 48px; height: 48px; overflow: hidden;">
<?php if($item['image_url']): ?>
<img src="<?= $item['image_url'] ?>?v=<?= time() ?>" alt="" style="width: 100%; height: 100%; object-fit: cover;">
<?php else: ?>
<i class="bi bi-image text-muted"></i>
<?php else:
?><i class="bi bi-image text-muted"></i>
<?php endif; ?>
</div>
<div>
<div class="fw-bold"><?= $lang === 'ar' ? ($item['name_ar'] ?: $item['name_en']) : $item['name_en'] ?></div>
<?php if($lang === 'ar' && $item['name_ar']): ?>
<small class="text-muted"><?= $item['name_en'] ?></small>
<?php elseif($lang === 'en' && $item['name_ar']): ?>
<small class="text-muted"><?= $item['name_ar'] ?></small>
<?php if($lang === 'ar' && $item['name_ar']):
?><small class="text-muted"><?= $item['name_en'] ?></small>
<?php elseif($lang === 'en' && $item['name_ar']):
?><small class="text-muted"><?= $item['name_ar'] ?></small>
<?php endif; ?>
</div>
</div>
@ -368,7 +459,7 @@ foreach ($prices_raw as $p) {
</td>
<td class="pe-4 text-end">
<?php if (has_permission('edit')): ?>
<button class="btn btn-sm btn-light p-2 me-1" style="border-radius: 10px;" onclick="openItemModal(<?= htmlspecialchars(json_encode($item)) ?>)">
<button class="btn btn-sm btn-light p-2 me-1" style="border-radius: 10px;" onclick="openItemModal(<?= htmlspecialchars(json_encode($item), ENT_QUOTES) ?>)">
<i class="bi bi-pencil text-primary"></i>
</button>
<?php endif; ?>
@ -477,6 +568,7 @@ foreach ($prices_raw as $p) {
<form id="categoryForm" method="POST">
<input type="hidden" name="action" id="catAction" value="add_category">
<input type="hidden" name="id" id="catId">
<input type="hidden" name="ajax" value="1">
<div class="mb-3">
<label class="form-label small"><?= __('name_en') ?></label>
<div class="input-group"><input type="text" name="cat_name_en" id="catNameEn" class="form-control" required style="border-top-left-radius: 12px; border-bottom-left-radius: 12px;"><button type="button" class="btn btn-outline-secondary" style="border-top-right-radius: 12px; border-bottom-right-radius: 12px;" onclick="translateField('catNameEn', 'catNameAr', 'en-ar')"><i class="bi bi-translate"></i></button></div>
@ -499,34 +591,15 @@ foreach ($prices_raw as $p) {
</div>
<div class="col-md-7">
<div class="table-responsive" style="max-height: 400px; overflow-y: auto;">
<table class="table table-sm align-middle">
<thead>
<table class="table table-hover align-middle">
<thead class="bg-light">
<tr>
<th><?= __('name') ?></th>
<th class="text-end"><?= __('actions') ?></th>
</tr>
</thead>
<tbody>
<?php foreach($categories as $cat):
?><tr>
<td>
<strong><?= $cat['name_en'] ?></strong><br>
<small class="text-muted"><?= $cat['name_ar'] ?></small>
</td>
<td class="text-end">
<?php if (has_permission('edit')):
?><button class="btn btn-sm btn-link text-primary" onclick="editCategory(<?= htmlspecialchars(json_encode($cat)) ?>)">
<i class="bi bi-pencil"></i>
</button>
<?php endif; ?>
<?php if (has_permission('delete')):
?><button class="btn btn-sm btn-link text-danger" onclick="confirmDelete('category', <?= $cat['id'] ?>)">
<i class="bi bi-trash"></i>
</button>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
<tbody id="categoryTableBody">
<?= renderCategoryList($lang) ?>
</tbody>
</table>
</div>
@ -554,6 +627,7 @@ foreach ($prices_raw as $p) {
<form id="serviceForm" method="POST">
<input type="hidden" name="action" id="svcAction" value="add_service">
<input type="hidden" name="id" id="svcId">
<input type="hidden" name="ajax" value="1">
<div class="mb-3">
<label class="form-label small"><?= __('name_en') ?></label>
<div class="input-group"><input type="text" name="svc_name_en" id="svcNameEn" class="form-control" required style="border-top-left-radius: 12px; border-bottom-left-radius: 12px;"><button type="button" class="btn btn-outline-secondary" style="border-top-right-radius: 12px; border-bottom-right-radius: 12px;" onclick="translateField('svcNameEn', 'svcNameAr', 'en-ar')"><i class="bi bi-translate"></i></button></div>
@ -576,34 +650,15 @@ foreach ($prices_raw as $p) {
</div>
<div class="col-md-7">
<div class="table-responsive" style="max-height: 400px; overflow-y: auto;">
<table class="table table-sm align-middle">
<thead>
<table class="table table-hover align-middle">
<thead class="bg-light">
<tr>
<th><?= __('name') ?></th>
<th class="text-end"><?= __('actions') ?></th>
</tr>
</thead>
<tbody>
<?php foreach($services as $svc):
?><tr>
<td>
<strong><?= $svc['name_en'] ?></strong><br>
<small class="text-muted"><?= $svc['name_ar'] ?></small>
</td>
<td class="text-end">
<?php if (has_permission('edit')):
?><button class="btn btn-sm btn-link text-primary" onclick="editService(<?= htmlspecialchars(json_encode($svc)) ?>)">
<i class="bi bi-pencil"></i>
</button>
<?php endif; ?>
<?php if (has_permission('delete')):
?><button class="btn btn-sm btn-link text-danger" onclick="confirmDelete('service', <?= $svc['id'] ?>)">
<i class="bi bi-trash"></i>
</button>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
<tbody id="serviceTableBody">
<?= renderServiceList($lang) ?>
</tbody>
</table>
</div>
@ -702,7 +757,7 @@ async function translateField(sourceId, targetId, direction) {
const data = await resp.json();
if (data.success) targetEl.value = data.translation;
} catch (e) { console.error(e); }
finally { btn.disabled = false; btn.innerHTML = originalHtml; }
finally { btn.disabled = false; btn.innerHTML = originalHtml; }
}
function openItemModal(item = null) {
const modal = new bootstrap.Modal(document.getElementById('itemModal'));
@ -784,6 +839,64 @@ function confirmDelete(type, id) {
}
}
async function confirmDeleteAjax(type, id) {
if (confirm("<?= __('are_you_sure') ?>")) {
const formData = new FormData();
formData.append('action', 'delete_' + type);
formData.append('id', id);
formData.append('ajax', '1');
try {
const response = await fetch('items.php', { method: 'POST', body: formData });
const data = await response.json();
if (data.success) {
if (type === 'category') document.getElementById('categoryTableBody').innerHTML = data.html;
if (type === 'service') document.getElementById('serviceTableBody').innerHTML = data.html;
} else {
alert(data.error || 'Failed to delete');
}
} catch (error) {
console.error('Error deleting:', error);
}
}
}
// Category Form AJAX
document.getElementById('categoryForm').addEventListener('submit', async function(e) {
e.preventDefault();
const formData = new FormData(this);
try {
const response = await fetch('items.php', { method: 'POST', body: formData });
const data = await response.json();
if (data.success) {
document.getElementById('categoryTableBody').innerHTML = data.html;
resetCatForm();
} else {
alert(data.error || 'Failed to save category');
}
} catch (error) {
console.error('Error saving category:', error);
}
});
// Service Form AJAX
document.getElementById('serviceForm').addEventListener('submit', async function(e) {
e.preventDefault();
const formData = new FormData(this);
try {
const response = await fetch('items.php', { method: 'POST', body: formData });
const data = await response.json();
if (data.success) {
document.getElementById('serviceTableBody').innerHTML = data.html;
resetSvcForm();
} else {
alert(data.error || 'Failed to save service');
}
} catch (error) {
console.error('Error saving service:', error);
}
});
// AJAX logic for prices
document.querySelectorAll('.price-input').forEach(input => {
let timeout = null;
@ -841,4 +954,4 @@ document.getElementById('itemImageFile').addEventListener('change', function(e)
});
</script>
<?php require_once __DIR__ . '/includes/footer.php'; ?>
<?php require_once __DIR__ . '/includes/footer.php'; ?>

View File

@ -51,6 +51,12 @@ function b_label($key) {
return '<span class="label-en">' . $en . '</span> / <span class="label-ar">' . $ar . '</span>';
}
// Fallbacks
$display_company_name_en = $company['name_en'] ?: 'Laundry Brand';
$display_company_name_ar = $company['name_ar'] ?: 'علامة غسيل';
$display_vat = $company['vat_no'] ?: $company['vat_number'];
$display_ctr = $company['ctr_no'];
?>
<!DOCTYPE html>
<html lang="en" dir="ltr">
@ -200,10 +206,12 @@ function b_label($key) {
<div class="text-center receipt-header">
<?php if ($company['logo']): ?>
<img src="<?= $company['logo'] ?>" alt="Logo" class="logo">
<?php else: ?>
<div class="mb-2" style="font-size: 24px; color: #0d6efd;"></div>
<?php endif; ?>
<h3 class="fw-bold"><?= $company['name_en'] ?></h3>
<h3 class="fw-bold arabic-text"><?= $company['name_ar'] ?></h3>
<h3 class="fw-bold"><?= htmlspecialchars($display_company_name_en) ?></h3>
<h3 class="fw-bold arabic-text"><?= htmlspecialchars($display_company_name_ar) ?></h3>
<div class="mt-1">
<div class="fw-bold"><?= $order['branch_name_en'] ?></div>
@ -220,17 +228,17 @@ function b_label($key) {
<span><?= $order['branch_phone'] ?></span>
</div>
<?php if (!empty($company['ctr_no'])): ?>
<?php if (!empty($display_ctr)): ?>
<div>
<span><?= $translations['en']['ctr_no'] ?> / <?= $translations['ar']['ctr_no'] ?>:</span>
<span><?= $company['ctr_no'] ?></span>
<span><?= htmlspecialchars($display_ctr) ?></span>
</div>
<?php endif; ?>
<?php if (!empty($company['vat_no']) || !empty($company['vat_number'])): ?>
<?php if (!empty($display_vat)): ?>
<div>
<span><?= $translations['en']['vat_no'] ?> / <?= $translations['ar']['vat_no'] ?>:</span>
<span><?= $company['vat_no'] ?: $company['vat_number'] ?></span>
<span><?= htmlspecialchars($display_vat) ?></span>
</div>
<?php endif; ?>
</div>
@ -326,4 +334,4 @@ function b_label($key) {
}
</script>
</body>
</html>
</html>

View File

@ -122,6 +122,14 @@ if ($user_filter !== 'all') {
}
}
// Fallback values if database is empty
$display_company_name = ($lang === 'ar' ? ($company_info['name_ar'] ?: $company_info['name_en']) : $company_info['name_en']) ?: 'Laundry Brand';
$display_address = ($lang === 'ar' ? ($company_info['address_ar'] ?: $company_info['address_en']) : $company_info['address_en']);
$display_phone = $company_info['phone'];
$display_email = $company_info['email'];
$display_vat = $company_info['vat_no'] ?: $company_info['vat_number'];
$display_ctr = $company_info['ctr_no'];
?>
<div class="d-flex justify-content-between align-items-center mb-4 no-print">
@ -206,16 +214,50 @@ document.getElementById('customerSearch').addEventListener('input', function() {
</script>
<!-- Print Header -->
<div class="d-none d-print-block mb-4 border-bottom pb-3">
<div class="row">
<div class="col-6">
<h2 class="fw-bold mb-0"><?= __('reports') ?></h2>
<p class="text-muted mb-0"><?= date('Y-m-d H:i') ?></p>
<div class="d-none d-print-block mb-5 border-bottom pb-4">
<div class="row align-items-center">
<div class="col-7">
<?php if (!empty($company_info['logo'])): ?>
<img src="<?= $company_info['logo'] ?>" alt="Logo" style="max-height: 80px;" class="mb-3">
<?php else: ?>
<div class="mb-3 d-flex align-items-center text-primary">
<i class="bi bi-tsunami fs-1 me-2"></i>
<span class="fs-4 fw-bold">Laundry Management</span>
</div>
<?php endif; ?>
<h2 class="fw-bold mb-1"><?= htmlspecialchars($display_company_name) ?></h2>
<div class="text-muted small">
<?php if ($display_address): ?>
<?= htmlspecialchars($display_address) ?><br>
<?php endif; ?>
<?php if ($display_phone): ?>
<?= __('phone') ?>: <?= htmlspecialchars($display_phone) ?>
<?php endif; ?>
<?php if ($display_email): ?>
<?= $display_phone ? ' | ' : '' ?><?= __('email') ?>: <?= htmlspecialchars($display_email) ?><br>
<?php elseif($display_phone): ?>
<br>
<?php endif; ?>
<?php if ($display_vat): ?>
<?= __('vat_no') ?>: <?= htmlspecialchars($display_vat) ?>
<?php endif; ?>
<?php if ($display_ctr): ?>
<?= $display_vat ? ' | ' : '' ?><?= __('ctr_no') ?>: <?= htmlspecialchars($display_ctr) ?>
<?php endif; ?>
</div>
</div>
<div class="col-6 text-end">
<p class="mb-0"><strong><?= __('date_range') ?>:</strong> <?= $from_date ?> - <?= $to_date ?></p>
<p class="mb-0"><strong><?= __('outlet') ?>:</strong> <?= $branch_name ?></p>
<p class="mb-0"><strong><?= __('cashier') ?>:</strong> <?= $user_name ?></p>
<div class="col-5 text-end">
<h1 class="fw-bold text-uppercase mb-2" style="color: #0d6efd;"><?= __('reports') ?></h1>
<div class="mt-3 small">
<p class="mb-0"><strong><?= __('date_range') ?>:</strong> <?= $from_date ?> - <?= $to_date ?></p>
<p class="mb-0"><strong><?= __('outlet') ?>:</strong> <?= $branch_name ?></p>
<p class="mb-0"><strong><?= __('cashier') ?>:</strong> <?= $user_name ?></p>
<p class="mb-0 text-muted mt-1"><?= __('print_date') ?? 'Print Date' ?>: <?= date('d/m/Y H:i') ?></p>
</div>
</div>
</div>
</div>

View File

@ -14,6 +14,23 @@ if (!has_permission('view', 'users.php')) {
exit;
}
$manageable_pages = [
'admin.php' => 'dashboard',
'pos.php' => 'pos',
'orders.php' => 'orders',
'lab.php' => 'lab',
'customers.php' => 'customers',
'customer_statement.php' => 'customer_statement',
'reports.php' => 'reports',
'items.php' => 'items',
'branches.php' => 'branches',
'users.php' => 'users',
'profile.php' => 'user_profile',
'company_profile.php' => 'company_profile',
'order_details.php' => 'order_details',
'receipt.php' => 'receipt'
];
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
if ($_POST['action'] === 'add_user' && has_permission('add', 'users.php')) {
$username = $_POST['username'];
@ -38,9 +55,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
// Seed default permissions based on role for the new user
$default_pages = [
'super_admin' => ['admin.php', 'pos.php', 'orders.php', 'lab.php', 'customers.php', 'reports.php', 'items.php', 'branches.php', 'users.php', 'profile.php', 'company_profile.php', 'order_details.php', 'receipt.php'],
'branch_manager' => ['admin.php', 'pos.php', 'orders.php', 'lab.php', 'customers.php', 'reports.php', 'items.php', 'branches.php', 'profile.php', 'order_details.php', 'receipt.php'],
'cashier' => ['admin.php', 'pos.php', 'orders.php', 'lab.php', 'customers.php', 'profile.php', 'order_details.php', 'receipt.php'],
'super_admin' => array_keys($manageable_pages),
'branch_manager' => ['admin.php', 'pos.php', 'orders.php', 'lab.php', 'customers.php', 'customer_statement.php', 'reports.php', 'items.php', 'branches.php', 'profile.php', 'order_details.php', 'receipt.php'],
'cashier' => ['admin.php', 'pos.php', 'orders.php', 'lab.php', 'customers.php', 'customer_statement.php', 'profile.php', 'order_details.php', 'receipt.php'],
'limited_viewer' => ['admin.php', 'profile.php']
];
@ -107,9 +124,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
$stmt = db()->prepare("DELETE FROM user_permissions WHERE user_id = ?");
$stmt->execute([$target_user_id]);
$all_pages = ['admin.php', 'pos.php', 'orders.php', 'lab.php', 'customers.php', 'reports.php', 'items.php', 'branches.php', 'users.php', 'profile.php', 'company_profile.php', 'order_details.php', 'receipt.php'];
$all_pages_to_save = array_keys($manageable_pages);
foreach ($all_pages as $page) {
foreach ($all_pages_to_save as $page) {
$can_view = isset($permissions[$page]['view']) ? 1 : 0;
$can_add = isset($permissions[$page]['add']) ? 1 : 0;
$can_edit = isset($permissions[$page]['edit']) ? 1 : 0;
@ -147,21 +164,6 @@ while ($row = $ub_id_stmt->fetch()) {
$user_branch_ids_mapping[$row['user_id']][] = (int)$row['branch_id'];
}
$all_pages = [
'admin.php' => 'dashboard',
'pos.php' => 'pos',
'orders.php' => 'orders',
'lab.php' => 'lab',
'customers.php' => 'customers',
'reports.php' => 'reports',
'items.php' => 'items',
'branches.php' => 'branches',
'users.php' => 'users',
'profile.php' => 'user_profile',
'company_profile.php' => 'company_profile',
'order_details.php' => 'order_details',
'receipt.php' => 'receipt'
];
?>
<div class="row">
@ -366,7 +368,7 @@ $all_pages = [
</tr>
</thead>
<tbody id="permsTableBody">
<?php foreach($all_pages as $file => $label): ?>
<?php foreach($manageable_pages as $file => $label): ?>
<tr>
<td class="fw-bold small"><?= __($label) ?></td>
<td class="text-center">
@ -408,15 +410,26 @@ function openPermissions(userId, username) {
fetch('api/get_user_permissions.php?user_id=' + userId)
.then(response => response.json())
.then(data => {
data.forEach(p => {
const pageId = p.page.replace('.', '_');
if (p.can_view == 1) document.getElementById('v_' + pageId).checked = true;
if (p.can_add == 1) document.getElementById('a_' + pageId).checked = true;
if (p.can_edit == 1) document.getElementById('e_' + pageId).checked = true;
if (p.can_delete == 1) document.getElementById('d_' + pageId).checked = true;
});
if (data && Array.isArray(data)) {
data.forEach(p => {
const pageId = p.page.replace('.', '_');
const v = document.getElementById('v_' + pageId);
const a = document.getElementById('a_' + pageId);
const e = document.getElementById('e_' + pageId);
const d = document.getElementById('d_' + pageId);
if (v && p.can_view == 1) v.checked = true;
if (a && p.can_add == 1) a.checked = true;
if (e && p.can_edit == 1) e.checked = true;
if (d && p.can_delete == 1) d.checked = true;
});
}
const modal = new bootstrap.Modal(document.getElementById('permissionsModal'));
modal.show();
})
.catch(err => {
console.error('Error fetching permissions:', err);
alert('Failed to load permissions. Please try again.');
});
}