updating service
This commit is contained in:
parent
1de3f1d7d1
commit
538704f9d0
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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>
|
||||
|
||||
|
||||
@ -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
225
items.php
@ -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'; ?>
|
||||
22
receipt.php
22
receipt.php
@ -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>
|
||||
|
||||
60
reports.php
60
reports.php
@ -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>
|
||||
|
||||
69
users.php
69
users.php
@ -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.');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user