rate editing
This commit is contained in:
parent
c850a45169
commit
9eaaf40d0f
@ -76,6 +76,7 @@ if (isset($_GET['delete'])) {
|
|||||||
if (!has_permission('ads')) {
|
if (!has_permission('ads')) {
|
||||||
$message = '<div class="alert alert-danger">Access Denied.</div>';
|
$message = '<div class="alert alert-danger">Access Denied.</div>';
|
||||||
} else {
|
} else {
|
||||||
|
try {
|
||||||
$id = $_GET['delete'];
|
$id = $_GET['delete'];
|
||||||
$stmt = $pdo->prepare("SELECT image_path FROM ads_images WHERE id = ?");
|
$stmt = $pdo->prepare("SELECT image_path FROM ads_images WHERE id = ?");
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
@ -85,9 +86,16 @@ if (isset($_GET['delete'])) {
|
|||||||
if (file_exists($fullPath) && is_file($fullPath)) unlink($fullPath);
|
if (file_exists($fullPath) && is_file($fullPath)) unlink($fullPath);
|
||||||
$pdo->prepare("DELETE FROM ads_images WHERE id = ?")->execute([$id]);
|
$pdo->prepare("DELETE FROM ads_images WHERE id = ?")->execute([$id]);
|
||||||
}
|
}
|
||||||
header("Location: ads.php");
|
header("Location: ads.php?deleted=1");
|
||||||
exit;
|
exit;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$message = '<div class="alert alert-danger">Error deleting advertisement: ' . $e->getMessage() . '</div>';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_GET['deleted'])) {
|
||||||
|
$message = '<div class="alert alert-success">Advertisement deleted successfully!</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = "SELECT * FROM ads_images ORDER BY sort_order ASC, created_at DESC";
|
$query = "SELECT * FROM ads_images ORDER BY sort_order ASC, created_at DESC";
|
||||||
|
|||||||
@ -40,23 +40,33 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle Delete
|
// Handle Delete (Soft Delete)
|
||||||
if (isset($_GET['delete'])) {
|
if (isset($_GET['delete'])) {
|
||||||
if (!has_permission('areas_del')) {
|
if (!has_permission('areas_del')) {
|
||||||
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete areas.</div>';
|
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete areas.</div>';
|
||||||
} else {
|
} else {
|
||||||
$id = $_GET['delete'];
|
try {
|
||||||
$pdo->prepare("DELETE FROM areas WHERE id = ?")->execute([$id]);
|
$id = (int)$_GET['delete'];
|
||||||
header("Location: areas.php");
|
// Soft delete to preserve relations with tables
|
||||||
|
$pdo->prepare("UPDATE areas SET is_deleted = 1 WHERE id = ?")->execute([$id]);
|
||||||
|
header("Location: areas.php?deleted=1");
|
||||||
exit;
|
exit;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$message = '<div class="alert alert-danger">Error removing area: ' . $e->getMessage() . '</div>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$outlets = $pdo->query("SELECT * FROM outlets ORDER BY name ASC")->fetchAll();
|
if (isset($_GET['deleted'])) {
|
||||||
|
$message = '<div class="alert alert-success">Area removed successfully!</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$outlets = $pdo->query("SELECT * FROM outlets WHERE is_deleted = 0 ORDER BY name ASC")->fetchAll();
|
||||||
|
|
||||||
$query = "SELECT a.*, o.name as outlet_name
|
$query = "SELECT a.*, o.name as outlet_name
|
||||||
FROM areas a
|
FROM areas a
|
||||||
LEFT JOIN outlets o ON a.outlet_id = o.id
|
LEFT JOIN outlets o ON a.outlet_id = o.id
|
||||||
|
WHERE a.is_deleted = 0
|
||||||
ORDER BY a.id DESC";
|
ORDER BY a.id DESC";
|
||||||
$areas_pagination = paginate_query($pdo, $query);
|
$areas_pagination = paginate_query($pdo, $query);
|
||||||
$areas = $areas_pagination['data'];
|
$areas = $areas_pagination['data'];
|
||||||
@ -104,7 +114,7 @@ include 'includes/header.php';
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if (has_permission('areas_del')): ?>
|
<?php if (has_permission('areas_del')): ?>
|
||||||
<a href="?delete=<?= $area['id'] ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('Delete this area and all its tables?')"><i class="bi bi-trash"></i></a>
|
<a href="?delete=<?= $area['id'] ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('<?= t('are_you_sure') ?>')"><i class="bi bi-trash"></i></a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@ -60,19 +60,28 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle Delete
|
// Handle Delete (Soft Delete)
|
||||||
if (isset($_GET['delete'])) {
|
if (isset($_GET['delete'])) {
|
||||||
if (!has_permission('categories_del')) {
|
if (!has_permission('categories_del')) {
|
||||||
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete categories.</div>';
|
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete categories.</div>';
|
||||||
} else {
|
} else {
|
||||||
$id = $_GET['delete'];
|
try {
|
||||||
$pdo->prepare("DELETE FROM categories WHERE id = ?")->execute([$id]);
|
$id = (int)$_GET['delete'];
|
||||||
header("Location: categories.php");
|
// Soft delete to avoid breaking product relations and historical order integrity
|
||||||
|
$pdo->prepare("UPDATE categories SET is_deleted = 1 WHERE id = ?")->execute([$id]);
|
||||||
|
header("Location: categories.php?deleted=1");
|
||||||
exit;
|
exit;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$message = '<div class="alert alert-danger">Error removing category: ' . $e->getMessage() . '</div>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = "SELECT * FROM categories ORDER BY name ASC";
|
if (isset($_GET['deleted'])) {
|
||||||
|
$message = '<div class="alert alert-success">Category removed successfully!</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = "SELECT * FROM categories WHERE is_deleted = 0 ORDER BY name ASC";
|
||||||
$categories_pagination = paginate_query($pdo, $query);
|
$categories_pagination = paginate_query($pdo, $query);
|
||||||
$categories = $categories_pagination['data'];
|
$categories = $categories_pagination['data'];
|
||||||
|
|
||||||
@ -135,7 +144,7 @@ include 'includes/header.php';
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if (has_permission('categories_del')): ?>
|
<?php if (has_permission('categories_del')): ?>
|
||||||
<a href="?delete=<?= $cat['id'] ?>" class="btn btn-sm btn-outline-danger rounded-pill px-3" onclick="return confirm('Delete category? Ensure no products are linked.')"><?= t('delete') ?></a>
|
<a href="?delete=<?= $cat['id'] ?>" class="btn btn-sm btn-outline-danger rounded-pill px-3" onclick="return confirm('<?= t('are_you_sure') ?>')"><?= t('delete') ?></a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@ -48,11 +48,23 @@ if (isset($_GET['delete'])) {
|
|||||||
if (!has_permission('customers_del')) {
|
if (!has_permission('customers_del')) {
|
||||||
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete customers.</div>';
|
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete customers.</div>';
|
||||||
} else {
|
} else {
|
||||||
|
try {
|
||||||
$id = $_GET['delete'];
|
$id = $_GET['delete'];
|
||||||
$pdo->prepare("DELETE FROM customers WHERE id = ?")->execute([$id]);
|
$pdo->prepare("DELETE FROM customers WHERE id = ?")->execute([$id]);
|
||||||
header("Location: customers.php");
|
header("Location: customers.php?deleted=1");
|
||||||
exit;
|
exit;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
if ($e->getCode() == '23000') {
|
||||||
|
$message = '<div class="alert alert-danger">Cannot delete this customer because they are linked to other records (e.g., orders).</div>';
|
||||||
|
} else {
|
||||||
|
$message = '<div class="alert alert-danger">Error deleting customer: ' . $e->getMessage() . '</div>';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_GET['deleted'])) {
|
||||||
|
$message = '<div class="alert alert-success">Customer deleted successfully!</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
$search = $_GET['search'] ?? '';
|
$search = $_GET['search'] ?? '';
|
||||||
@ -202,7 +214,7 @@ include 'includes/header.php';
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer border-0 p-4 pt-0">
|
<div class="modal-footer border-0 p-4 pt-0">
|
||||||
<button type="button" class="btn btn-light rounded-pill px-4" data-bs-dismiss="modal">Cancel</button>
|
<button type="button" class="btn btn-light rounded-pill px-4" data-bs-modal="modal" data-bs-dismiss="modal">Cancel</button>
|
||||||
<button type="submit" class="btn btn-primary rounded-pill px-4 fw-bold shadow-sm">Save Customer Profile</button>
|
<button type="submit" class="btn btn-primary rounded-pill px-4 fw-bold shadow-sm">Save Customer Profile</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@ -41,19 +41,28 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle Delete
|
// Handle Delete (Soft Delete)
|
||||||
if (isset($_GET['delete'])) {
|
if (isset($_GET['delete'])) {
|
||||||
if (!has_permission('expense_categories_del')) {
|
if (!has_permission('expense_categories_del')) {
|
||||||
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete expense categories.</div>';
|
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete expense categories.</div>';
|
||||||
} else {
|
} else {
|
||||||
$id = $_GET['delete'];
|
try {
|
||||||
$pdo->prepare("DELETE FROM expense_categories WHERE id = ?")->execute([$id]);
|
$id = (int)$_GET['delete'];
|
||||||
header("Location: expense_categories.php");
|
// Soft delete to preserve relations with expenses
|
||||||
|
$pdo->prepare("UPDATE expense_categories SET is_deleted = 1 WHERE id = ?")->execute([$id]);
|
||||||
|
header("Location: expense_categories.php?deleted=1");
|
||||||
exit;
|
exit;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$message = '<div class="alert alert-danger">Error removing category: ' . $e->getMessage() . '</div>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = "SELECT * FROM expense_categories ORDER BY name ASC";
|
if (isset($_GET['deleted'])) {
|
||||||
|
$message = '<div class="alert alert-success">Expense category removed successfully!</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = "SELECT * FROM expense_categories WHERE is_deleted = 0 ORDER BY name ASC";
|
||||||
$expense_categories_pagination = paginate_query($pdo, $query);
|
$expense_categories_pagination = paginate_query($pdo, $query);
|
||||||
$expense_categories = $expense_categories_pagination['data'];
|
$expense_categories = $expense_categories_pagination['data'];
|
||||||
|
|
||||||
@ -102,7 +111,7 @@ include 'includes/header.php';
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if (has_permission('expense_categories_del')): ?>
|
<?php if (has_permission('expense_categories_del')): ?>
|
||||||
<a href="?delete=<?= $cat['id'] ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('Delete this expense category?')"><i class="bi bi-trash"></i></a>
|
<a href="?delete=<?= $cat['id'] ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('<?= t('are_you_sure') ?>')"><i class="bi bi-trash"></i></a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@ -45,14 +45,18 @@ if (isset($_GET['delete'])) {
|
|||||||
if (!has_permission('expenses_del')) {
|
if (!has_permission('expenses_del')) {
|
||||||
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete expenses.</div>';
|
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete expenses.</div>';
|
||||||
} else {
|
} else {
|
||||||
|
try {
|
||||||
$id = $_GET['delete'];
|
$id = $_GET['delete'];
|
||||||
$pdo->prepare("DELETE FROM expenses WHERE id = ?")->execute([$id]);
|
$pdo->prepare("DELETE FROM expenses WHERE id = ?")->execute([$id]);
|
||||||
header("Location: expenses.php?success=deleted");
|
header("Location: expenses.php?deleted=1");
|
||||||
exit;
|
exit;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$message = '<div class="alert alert-danger">Error deleting expense: ' . $e->getMessage() . '</div>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($_GET['success']) && $_GET['success'] === 'deleted') {
|
if (isset($_GET['deleted'])) {
|
||||||
$message = '<div class="alert alert-success">Expense deleted successfully!</div>';
|
$message = '<div class="alert alert-success">Expense deleted successfully!</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -30,9 +30,9 @@ if (!$order) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fetch Order Items
|
// Fetch Order Items
|
||||||
$stmt = $pdo->prepare("SELECT oi.*, p.name as product_name, pv.name as variant_name
|
$stmt = $pdo->prepare("SELECT oi.*, COALESCE(p.name, oi.product_name) as product_name, COALESCE(pv.name, oi.variant_name) as variant_name
|
||||||
FROM order_items oi
|
FROM order_items oi
|
||||||
JOIN products p ON oi.product_id = p.id
|
LEFT JOIN products p ON oi.product_id = p.id
|
||||||
LEFT JOIN product_variants pv ON oi.variant_id = pv.id
|
LEFT JOIN product_variants pv ON oi.variant_id = pv.id
|
||||||
WHERE oi.order_id = ?");
|
WHERE oi.order_id = ?");
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
|
|||||||
@ -41,19 +41,28 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle Delete
|
// Handle Delete (Soft Delete)
|
||||||
if (isset($_GET['delete'])) {
|
if (isset($_GET['delete'])) {
|
||||||
if (!has_permission('outlets_del')) {
|
if (!has_permission('outlets_del')) {
|
||||||
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete outlets.</div>';
|
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete outlets.</div>';
|
||||||
} else {
|
} else {
|
||||||
$id = $_GET['delete'];
|
try {
|
||||||
$pdo->prepare("DELETE FROM outlets WHERE id = ?")->execute([$id]);
|
$id = (int)$_GET['delete'];
|
||||||
header("Location: outlets.php");
|
// Soft delete to preserve relations with users, expenses, and orders
|
||||||
|
$pdo->prepare("UPDATE outlets SET is_deleted = 1 WHERE id = ?")->execute([$id]);
|
||||||
|
header("Location: outlets.php?deleted=1");
|
||||||
exit;
|
exit;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$message = '<div class="alert alert-danger">Error removing outlet: ' . $e->getMessage() . '</div>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = "SELECT * FROM outlets ORDER BY id DESC";
|
if (isset($_GET['deleted'])) {
|
||||||
|
$message = '<div class="alert alert-success">Outlet removed successfully!</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = "SELECT * FROM outlets WHERE is_deleted = 0 ORDER BY id DESC";
|
||||||
$outlets_pagination = paginate_query($pdo, $query);
|
$outlets_pagination = paginate_query($pdo, $query);
|
||||||
$outlets = $outlets_pagination['data'];
|
$outlets = $outlets_pagination['data'];
|
||||||
|
|
||||||
@ -103,7 +112,7 @@ include 'includes/header.php';
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if (has_permission('outlets_del')): ?>
|
<?php if (has_permission('outlets_del')): ?>
|
||||||
<a href="?delete=<?= $outlet['id'] ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('Delete this outlet?')"><i class="bi bi-trash"></i></a>
|
<a href="?delete=<?= $outlet['id'] ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('<?= t('are_you_sure') ?>')"><i class="bi bi-trash"></i></a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@ -50,11 +50,23 @@ if (isset($_GET['delete'])) {
|
|||||||
if (!has_permission('payment_types_del')) {
|
if (!has_permission('payment_types_del')) {
|
||||||
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete payment types.</div>';
|
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete payment types.</div>';
|
||||||
} else {
|
} else {
|
||||||
|
try {
|
||||||
$id = $_GET['delete'];
|
$id = $_GET['delete'];
|
||||||
$pdo->prepare("DELETE FROM payment_types WHERE id = ?")->execute([$id]);
|
$pdo->prepare("DELETE FROM payment_types WHERE id = ?")->execute([$id]);
|
||||||
header("Location: payment_types.php");
|
header("Location: payment_types.php?deleted=1");
|
||||||
exit;
|
exit;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
if ($e->getCode() == '23000') {
|
||||||
|
$message = '<div class="alert alert-danger">Cannot delete this payment type because it is linked to other records (e.g., orders).</div>';
|
||||||
|
} else {
|
||||||
|
$message = '<div class="alert alert-danger">Error deleting payment type: ' . $e->getMessage() . '</div>';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_GET['deleted'])) {
|
||||||
|
$message = '<div class="alert alert-success">Payment type deleted successfully!</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = "SELECT * FROM payment_types ORDER BY id ASC";
|
$query = "SELECT * FROM payment_types ORDER BY id ASC";
|
||||||
|
|||||||
@ -20,16 +20,22 @@ if (!$product) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$message = '';
|
||||||
|
|
||||||
// Handle Add Variant
|
// Handle Add Variant
|
||||||
if (isset($_POST['action']) && $_POST['action'] === 'add_variant') {
|
if (isset($_POST['action']) && $_POST['action'] === 'add_variant') {
|
||||||
$name = $_POST['name'];
|
$name = $_POST['name'];
|
||||||
$name_ar = $_POST['name_ar'] ?? '';
|
$name_ar = $_POST['name_ar'] ?? '';
|
||||||
$price_adj = $_POST['price_adjustment'];
|
$price_adj = $_POST['price_adjustment'];
|
||||||
|
|
||||||
|
try {
|
||||||
$stmt = $pdo->prepare("INSERT INTO product_variants (product_id, name, name_ar, price_adjustment) VALUES (?, ?, ?, ?)");
|
$stmt = $pdo->prepare("INSERT INTO product_variants (product_id, name, name_ar, price_adjustment) VALUES (?, ?, ?, ?)");
|
||||||
$stmt->execute([$product_id, $name, $name_ar, $price_adj]);
|
$stmt->execute([$product_id, $name, $name_ar, $price_adj]);
|
||||||
header("Location: product_variants.php?product_id=$product_id");
|
header("Location: product_variants.php?product_id=$product_id&added=1");
|
||||||
exit;
|
exit;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$message = '<div class="alert alert-danger">Error adding variant: ' . $e->getMessage() . '</div>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle Edit Variant
|
// Handle Edit Variant
|
||||||
@ -39,20 +45,37 @@ if (isset($_POST['action']) && $_POST['action'] === 'edit_variant') {
|
|||||||
$name_ar = $_POST['name_ar'] ?? '';
|
$name_ar = $_POST['name_ar'] ?? '';
|
||||||
$price_adj = $_POST['price_adjustment'];
|
$price_adj = $_POST['price_adjustment'];
|
||||||
|
|
||||||
|
try {
|
||||||
$stmt = $pdo->prepare("UPDATE product_variants SET name = ?, name_ar = ?, price_adjustment = ? WHERE id = ?");
|
$stmt = $pdo->prepare("UPDATE product_variants SET name = ?, name_ar = ?, price_adjustment = ? WHERE id = ?");
|
||||||
$stmt->execute([$name, $name_ar, $price_adj, $id]);
|
$stmt->execute([$name, $name_ar, $price_adj, $id]);
|
||||||
header("Location: product_variants.php?product_id=$product_id");
|
header("Location: product_variants.php?product_id=$product_id&updated=1");
|
||||||
exit;
|
exit;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$message = '<div class="alert alert-danger">Error updating variant: ' . $e->getMessage() . '</div>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle Delete
|
// Handle Delete (Soft Delete)
|
||||||
if (isset($_GET['delete'])) {
|
if (isset($_GET['delete'])) {
|
||||||
$pdo->prepare("DELETE FROM product_variants WHERE id = ?")->execute([$_GET['delete']]);
|
try {
|
||||||
header("Location: product_variants.php?product_id=$product_id");
|
$id = (int)$_GET['delete'];
|
||||||
|
$pdo->prepare("UPDATE product_variants SET is_deleted = 1 WHERE id = ?")->execute([$id]);
|
||||||
|
header("Location: product_variants.php?product_id=$product_id&deleted=1");
|
||||||
exit;
|
exit;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$message = '<div class="alert alert-danger">Error deleting variant: ' . $e->getMessage() . '</div>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = "SELECT * FROM product_variants WHERE product_id = ? ORDER BY price_adjustment ASC";
|
if (isset($_GET['added'])) {
|
||||||
|
$message = '<div class="alert alert-success">Variant added successfully!</div>';
|
||||||
|
} elseif (isset($_GET['updated'])) {
|
||||||
|
$message = '<div class="alert alert-success">Variant updated successfully!</div>';
|
||||||
|
} elseif (isset($_GET['deleted'])) {
|
||||||
|
$message = '<div class="alert alert-success">Variant removed successfully!</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = "SELECT * FROM product_variants WHERE product_id = ? AND is_deleted = 0 ORDER BY price_adjustment ASC";
|
||||||
$variants_pagination = paginate_query($pdo, $query, [$product_id]);
|
$variants_pagination = paginate_query($pdo, $query, [$product_id]);
|
||||||
$variants = $variants_pagination['data'];
|
$variants = $variants_pagination['data'];
|
||||||
|
|
||||||
@ -74,6 +97,8 @@ $effective_base_price = get_product_price($product);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<?= $message ?>
|
||||||
|
|
||||||
<div class="card border-0 shadow-sm">
|
<div class="card border-0 shadow-sm">
|
||||||
<div class="card-body p-0">
|
<div class="card-body p-0">
|
||||||
<!-- Pagination Controls -->
|
<!-- Pagination Controls -->
|
||||||
|
|||||||
@ -11,39 +11,22 @@ $message = '';
|
|||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
||||||
$action = $_POST['action'];
|
$action = $_POST['action'];
|
||||||
$id = isset($_POST['id']) ? (int)$_POST['id'] : null;
|
$id = isset($_POST['id']) ? (int)$_POST['id'] : null;
|
||||||
|
|
||||||
if ($action === 'cancel_promotion' && $id) {
|
|
||||||
if (!has_permission('products_edit')) {
|
|
||||||
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to edit products.</div>';
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
$stmt = $pdo->prepare("UPDATE products SET promo_discount_percent = NULL, promo_date_from = NULL, promo_date_to = NULL WHERE id = ?");
|
|
||||||
$stmt->execute([$id]);
|
|
||||||
$message = '<div class="alert alert-success">Promotion cancelled successfully!</div>';
|
|
||||||
} catch (PDOException $e) {
|
|
||||||
$message = '<div class="alert alert-danger">Database error: ' . $e->getMessage() . '</div>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$name = $_POST['name'];
|
$name = $_POST['name'];
|
||||||
$name_ar = $_POST['name_ar'] ?? '';
|
$name_ar = $_POST['name_ar'] ?? '';
|
||||||
$category_id = $_POST['category_id'];
|
$category_id = (int)$_POST['category_id'];
|
||||||
$price = $_POST['price'];
|
$price = (float)$_POST['price'];
|
||||||
$cost_price = $_POST['cost_price'] ?: 0;
|
$cost_price = (float)($_POST['cost_price'] ?? 0);
|
||||||
$stock_quantity = $_POST['stock_quantity'] ?: 0;
|
$stock_quantity = (int)($_POST['stock_quantity'] ?? 0);
|
||||||
$description = $_POST['description'];
|
$description = $_POST['description'] ?? '';
|
||||||
|
$promo_discount_percent = !empty($_POST['promo_discount_percent']) ? (float)$_POST['promo_discount_percent'] : null;
|
||||||
$promo_discount_percent = $_POST['promo_discount_percent'] !== '' ? $_POST['promo_discount_percent'] : null;
|
$promo_date_from = !empty($_POST['promo_date_from']) ? $_POST['promo_date_from'] : null;
|
||||||
$promo_date_from = $_POST['promo_date_from'] !== '' ? $_POST['promo_date_from'] : null;
|
$promo_date_to = !empty($_POST['promo_date_to']) ? $_POST['promo_date_to'] : null;
|
||||||
$promo_date_to = $_POST['promo_date_to'] !== '' ? $_POST['promo_date_to'] : null;
|
|
||||||
|
|
||||||
$image_url = null;
|
$image_url = null;
|
||||||
if ($id) {
|
if ($id) {
|
||||||
$stmt = $pdo->prepare("SELECT image_url FROM products WHERE id = ?");
|
$stmt = $pdo->prepare("SELECT image_url FROM products WHERE id = ?");
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$image_url = $stmt->fetchColumn();
|
$image_url = $stmt->fetchColumn();
|
||||||
} else {
|
|
||||||
$image_url = 'https://placehold.co/400x300?text=' . urlencode($name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($_FILES['image']) && $_FILES['image']['error'] === UPLOAD_ERR_OK) {
|
if (isset($_FILES['image']) && $_FILES['image']['error'] === UPLOAD_ERR_OK) {
|
||||||
@ -61,8 +44,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if ($action === 'edit_product' && $id) {
|
if ($action === 'edit_product' && $id) {
|
||||||
// Check for edit OR add (for backward compatibility)
|
if (!has_permission('products_edit')) {
|
||||||
if (!has_permission('products_edit') && !has_permission('products_add')) {
|
|
||||||
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to edit products.</div>';
|
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to edit products.</div>';
|
||||||
} else {
|
} else {
|
||||||
$stmt = $pdo->prepare("UPDATE products SET name = ?, name_ar = ?, category_id = ?, price = ?, cost_price = ?, stock_quantity = ?, description = ?, image_url = ?, promo_discount_percent = ?, promo_date_from = ?, promo_date_to = ? WHERE id = ?");
|
$stmt = $pdo->prepare("UPDATE products SET name = ?, name_ar = ?, category_id = ?, price = ?, cost_price = ?, stock_quantity = ?, description = ?, image_url = ?, promo_discount_percent = ?, promo_date_from = ?, promo_date_to = ? WHERE id = ?");
|
||||||
@ -81,46 +63,56 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
|||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
$message = '<div class="alert alert-danger">Database error: ' . $e->getMessage() . '</div>';
|
$message = '<div class="alert alert-danger">Database error: ' . $e->getMessage() . '</div>';
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle Delete
|
// Handle Delete (Soft Delete)
|
||||||
if (isset($_GET['delete'])) {
|
if (isset($_GET['delete'])) {
|
||||||
if (!has_permission('products_del')) {
|
if (!has_permission('products_del')) {
|
||||||
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete products.</div>';
|
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete products.</div>';
|
||||||
} else {
|
} else {
|
||||||
$id = $_GET['delete'];
|
try {
|
||||||
$pdo->prepare("DELETE FROM products WHERE id = ?")->execute([$id]);
|
$id = (int)$_GET['delete'];
|
||||||
header("Location: products.php");
|
// Use Soft Delete to preserve data integrity for orders
|
||||||
|
$pdo->prepare("UPDATE products SET is_deleted = 1 WHERE id = ?")->execute([$id]);
|
||||||
|
$pdo->prepare("UPDATE product_variants SET is_deleted = 1 WHERE product_id = ?")->execute([$id]);
|
||||||
|
header("Location: products.php?deleted=1");
|
||||||
exit;
|
exit;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$message = '<div class="alert alert-danger">Error deleting product: ' . $e->getMessage() . '</div>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$categories = $pdo->query("SELECT * FROM categories ORDER BY name")->fetchAll();
|
if (isset($_GET['deleted'])) {
|
||||||
|
$message = '<div class="alert alert-success">Product removed successfully!</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$categories = $pdo->query("SELECT * FROM categories WHERE is_deleted = 0 ORDER BY name ASC")->fetchAll();
|
||||||
|
|
||||||
|
// Build Query with Filters
|
||||||
|
$params = [];
|
||||||
|
$where = ["p.is_deleted = 0"]; // Base filter for soft delete
|
||||||
|
|
||||||
$search = $_GET['search'] ?? '';
|
$search = $_GET['search'] ?? '';
|
||||||
$category_filter = $_GET['category_filter'] ?? '';
|
$category_filter = $_GET['category_filter'] ?? '';
|
||||||
$params = [];
|
|
||||||
$where = [];
|
|
||||||
|
|
||||||
$query = "SELECT p.*, c.name as category_name
|
|
||||||
FROM products p
|
|
||||||
LEFT JOIN categories c ON p.category_id = c.id";
|
|
||||||
|
|
||||||
if ($search) {
|
if ($search) {
|
||||||
$where[] = "(p.name LIKE ? OR p.name_ar LIKE ? OR p.description LIKE ?)";
|
$where[] = "(p.name LIKE :search OR p.name_ar LIKE :search OR p.description LIKE :search)";
|
||||||
$params[] = "%$search%";
|
$params[':search'] = "%$search%";
|
||||||
$params[] = "%$search%";
|
|
||||||
$params[] = "%$search%";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($category_filter) {
|
if ($category_filter) {
|
||||||
$where[] = "p.category_id = ?";
|
$where[] = "p.category_id = :category_id";
|
||||||
$params[] = $category_filter;
|
$params[':category_id'] = $category_filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($where)) $query .= " WHERE " . implode(" AND ", $where);
|
$where_clause = !empty($where) ? 'WHERE ' . implode(' AND ', $where) : '';
|
||||||
$query .= " ORDER BY p.id DESC";
|
|
||||||
|
$query = "SELECT p.*, c.name as category_name
|
||||||
|
FROM products p
|
||||||
|
LEFT JOIN categories c ON p.category_id = c.id
|
||||||
|
$where_clause
|
||||||
|
ORDER BY p.name ASC";
|
||||||
|
|
||||||
$products_pagination = paginate_query($pdo, $query, $params);
|
$products_pagination = paginate_query($pdo, $query, $params);
|
||||||
$products = $products_pagination['data'];
|
$products = $products_pagination['data'];
|
||||||
@ -131,7 +123,7 @@ include 'includes/header.php';
|
|||||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
<div>
|
<div>
|
||||||
<h2 class="fw-bold mb-1"><?= t('products') ?></h2>
|
<h2 class="fw-bold mb-1"><?= t('products') ?></h2>
|
||||||
<p class="text-muted mb-0">Manage items, stock, and pricing</p>
|
<p class="text-muted mb-0">Manage your menu items and stock</p>
|
||||||
</div>
|
</div>
|
||||||
<?php if (has_permission('products_add')): ?>
|
<?php if (has_permission('products_add')): ?>
|
||||||
<button class="btn btn-primary btn-lg shadow-sm" data-bs-toggle="modal" data-bs-target="#productModal" onclick="prepareAddForm()" style="border-radius: 12px;">
|
<button class="btn btn-primary btn-lg shadow-sm" data-bs-toggle="modal" data-bs-target="#productModal" onclick="prepareAddForm()" style="border-radius: 12px;">
|
||||||
@ -142,128 +134,135 @@ include 'includes/header.php';
|
|||||||
|
|
||||||
<?= $message ?>
|
<?= $message ?>
|
||||||
|
|
||||||
<div class="filter-bar mb-4 p-3 bg-white rounded-4 shadow-sm">
|
<!-- Filters -->
|
||||||
<form method="GET" class="row g-3 align-items-center">
|
<div class="card border-0 shadow-sm mb-4">
|
||||||
|
<div class="card-body bg-light">
|
||||||
|
<form method="GET" class="row g-3 align-items-end">
|
||||||
<div class="col-md-5">
|
<div class="col-md-5">
|
||||||
|
<label class="form-label small fw-bold text-muted"><?= t('search') ?></label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<span class="input-group-text bg-light border-0 text-muted"><i class="bi bi-search"></i></span>
|
<span class="input-group-text bg-white border-end-0"><i class="bi bi-search text-muted"></i></span>
|
||||||
<input type="text" name="search" class="form-control border-0 bg-light" placeholder="<?= t('search') ?>..." value="<?= htmlspecialchars($search) ?>" style="border-radius: 0 10px 10px 0;">
|
<input type="text" name="search" class="form-control border-start-0" placeholder="Search by name or description..." value="<?= htmlspecialchars($search) ?>">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-4">
|
||||||
<select name="category_filter" class="form-select border-0 bg-light rounded-3" onchange="this.form.submit()">
|
<label class="form-label small fw-bold text-muted"><?= t('category') ?></label>
|
||||||
|
<select name="category_filter" class="form-select">
|
||||||
<option value=""><?= t('all') ?> <?= t('categories') ?></option>
|
<option value=""><?= t('all') ?> <?= t('categories') ?></option>
|
||||||
<?php foreach ($categories as $cat): ?>
|
<?php foreach ($categories as $cat): ?>
|
||||||
<option value="<?= $cat['id'] ?>" <?= $category_filter == $cat['id'] ? 'selected' : '' ?>><?= htmlspecialchars($cat['name']) ?></option>
|
<option value="<?= $cat['id'] ?>" <?= $category_filter == $cat['id'] ? 'selected' : '' ?>>
|
||||||
|
<?= htmlspecialchars($cat['name']) ?>
|
||||||
|
</option>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="d-flex gap-2">
|
||||||
|
<button type="submit" class="btn btn-primary w-100">
|
||||||
|
<i class="bi bi-filter"></i> <?= t('filter') ?>
|
||||||
|
</button>
|
||||||
|
<a href="products.php" class="btn btn-outline-secondary" title="Clear Filters">
|
||||||
|
<i class="bi bi-arrow-counterclockwise"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php if (empty($products)): ?>
|
<div class="card border-0 shadow-sm rounded-4 overflow-hidden">
|
||||||
<div class="text-center py-5 bg-white rounded-4 shadow-sm">
|
<div class="card-body p-0">
|
||||||
<i class="bi bi-box-seam display-1 text-muted opacity-25 mb-3 d-block"></i>
|
<!-- Pagination Controls -->
|
||||||
<h4 class="text-dark"><?= t('none') ?></h4>
|
<div class="p-3 border-bottom bg-light">
|
||||||
<p class="text-muted">Try adjusting your filters or search terms.</p>
|
<?php render_pagination_controls($products_pagination); ?>
|
||||||
</div>
|
</div>
|
||||||
<?php else: ?>
|
|
||||||
<div class="card border-0 shadow-sm rounded-4 overflow-hidden">
|
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-hover align-middle mb-0">
|
<table class="table table-hover align-middle mb-0">
|
||||||
<thead class="bg-light">
|
<thead class="bg-light">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="ps-4"><?= t('products') ?></th>
|
<th class="ps-4"><?= t('product') ?></th>
|
||||||
<th><?= t('category') ?></th>
|
<th><?= t('category') ?></th>
|
||||||
<th><?= t('stock') ?></th>
|
|
||||||
<th><?= t('price') ?></th>
|
<th><?= t('price') ?></th>
|
||||||
<th>Promotion</th>
|
<th><?= t('stock') ?></th>
|
||||||
|
<th><?= t('promotion') ?></th>
|
||||||
<th class="text-end pe-4"><?= t('actions') ?></th>
|
<th class="text-end pe-4"><?= t('actions') ?></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php
|
<?php foreach ($products as $product): ?>
|
||||||
$today = date('Y-m-d');
|
|
||||||
foreach ($products as $product):
|
|
||||||
$is_promo_active = !empty($product['promo_discount_percent']) &&
|
|
||||||
!empty($product['promo_date_from']) &&
|
|
||||||
!empty($product['promo_date_to']) &&
|
|
||||||
$today >= $product['promo_date_from'] &&
|
|
||||||
$today <= $product['promo_date_to'];
|
|
||||||
$has_promo_data = !empty($product['promo_discount_percent']);
|
|
||||||
?>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td class="ps-4">
|
<td class="ps-4">
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center py-2">
|
||||||
<img src="<?= htmlspecialchars(strpos($product['image_url'], 'http') === 0 ? $product['image_url'] : '../' . $product['image_url']) ?>" alt="" class="rounded-3 me-3 border shadow-sm" style="width: 48px; height: 48px; object-fit: cover;">
|
<?php if ($product['image_url']): ?>
|
||||||
<div>
|
<img src="<?= htmlspecialchars(strpos($product['image_url'], 'http') === 0 ? $product['image_url'] : '../' . $product['image_url']) ?>" alt="" class="rounded-3 me-3 border shadow-sm" style="width: 50px; height: 50px; object-fit: cover;">
|
||||||
<div class="fw-bold text-dark"><?= htmlspecialchars($product['name']) ?></div>
|
|
||||||
<?php if (!empty($product['name_ar'])): ?>
|
|
||||||
<div class="text-primary small fw-semibold" dir="rtl"><?= htmlspecialchars($product['name_ar']) ?></div>
|
|
||||||
<?php endif; ?>
|
|
||||||
<div class="text-muted small text-truncate" style="max-width: 180px;"><?= htmlspecialchars($product['description'] ?? '') ?></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td><span class="badge bg-light text-dark border px-2 py-1"><?= htmlspecialchars($product['category_name'] ?? t('none')) ?></span></td>
|
|
||||||
<td>
|
|
||||||
<?php $stock = (int)$product['stock_quantity']; ?>
|
|
||||||
<span class="badge <?= $stock <= 5 ? 'bg-danger-subtle text-danger' : ($stock <= 20 ? 'bg-warning-subtle text-warning' : 'bg-success-subtle text-success') ?> px-2 py-1 border border-<?= $stock <= 5 ? 'danger' : ($stock <= 20 ? 'warning' : 'success') ?>">
|
|
||||||
<?= $stock ?> <?= t('stock') ?>
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<?php if ($is_promo_active): ?>
|
|
||||||
<div class="fw-bold text-primary"><?= format_currency($product['price'] * (1 - ($product['promo_discount_percent'] / 100))) ?></div>
|
|
||||||
<div class="text-muted small text-decoration-line-through"><?= format_currency($product['price']) ?></div>
|
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
|
<div class="bg-light rounded-3 d-flex align-items-center justify-content-center me-3 border" style="width: 50px; height: 50px;">
|
||||||
|
<i class="bi bi-image text-muted opacity-50"></i>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<div>
|
||||||
|
<div class="fw-bold text-dark fs-6"><?= htmlspecialchars($product['name']) ?></div>
|
||||||
|
<small class="text-muted"><?= htmlspecialchars($product['name_ar'] ?? '') ?></small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="badge bg-light text-dark border"><?= htmlspecialchars($product['category_name'] ?? t('none')) ?></span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
<div class="fw-bold text-dark"><?= format_currency($product['price']) ?></div>
|
<div class="fw-bold text-dark"><?= format_currency($product['price']) ?></div>
|
||||||
|
<?php if ($product['cost_price'] > 0): ?>
|
||||||
|
<small class="text-muted"><?= t('cost') ?>: <?= format_currency($product['cost_price']) ?></small>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="d-flex align-items-center gap-2">
|
<?php if ($product['stock_quantity'] <= 5): ?>
|
||||||
<?php if ($is_promo_active): ?>
|
<span class="badge bg-danger bg-opacity-10 text-danger border border-danger rounded-pill px-3"><?= $product['stock_quantity'] ?></span>
|
||||||
<span class="badge bg-success rounded-pill px-2">-<?= floatval($product['promo_discount_percent']) ?>%</span>
|
<?php else: ?>
|
||||||
<?php elseif (!empty($product['promo_discount_percent'])): ?>
|
<span class="badge bg-success bg-opacity-10 text-success border border-success rounded-pill px-3"><?= $product['stock_quantity'] ?></span>
|
||||||
<span class="badge bg-secondary rounded-pill px-2"><?= t('inactive') ?></span>
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<?php if ($product['promo_discount_percent'] > 0): ?>
|
||||||
|
<span class="badge bg-warning bg-opacity-10 text-warning border border-warning rounded-pill px-2">
|
||||||
|
<i class="bi bi-megaphone-fill me-1"></i><?= $product['promo_discount_percent'] ?>% Off
|
||||||
|
</span>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<span class="text-muted small">-</span>
|
<span class="text-muted small">-</span>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if ($has_promo_data && has_permission('products_edit')): ?>
|
|
||||||
<form method="POST" class="d-inline" onsubmit="return confirm('Cancel this promotion?')">
|
|
||||||
<input type="hidden" name="action" value="cancel_promotion">
|
|
||||||
<input type="hidden" name="id" value="<?= $product['id'] ?>">
|
|
||||||
<button type="submit" class="btn btn-link p-0 text-danger" title="Cancel Promotion">
|
|
||||||
<i class="bi bi-x-circle-fill"></i>
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
<td class="text-end pe-4">
|
<td class="text-end pe-4">
|
||||||
<div class="d-inline-flex gap-2">
|
<div class="d-inline-flex gap-2">
|
||||||
<?php if (has_permission('products_edit') || has_permission('products_add')): ?>
|
<?php if (has_permission('products_edit')): ?>
|
||||||
<button type="button" class="btn btn-sm btn-outline-primary rounded-pill px-3"
|
<button type="button" class="btn btn-sm btn-outline-primary rounded-pill px-3"
|
||||||
data-bs-toggle="modal" data-bs-target="#productModal"
|
data-bs-toggle="modal" data-bs-target="#productModal"
|
||||||
onclick='prepareEditForm(<?= htmlspecialchars(json_encode($product), ENT_QUOTES, "UTF-8") ?>)'><?= t('edit') ?></button>
|
onclick='prepareEditForm(<?= htmlspecialchars(json_encode($product), ENT_QUOTES, "UTF-8") ?>)'><?= t('edit') ?></button>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if (has_permission('products_del')): ?>
|
<?php if (has_permission('products_del')): ?>
|
||||||
<a href="?delete=<?= $product['id'] ?>" class="btn btn-sm btn-outline-danger rounded-pill px-3" onclick="return confirm('Delete this product? This action cannot be undone.')"><?= t('delete') ?></a>
|
<a href="?delete=<?= $product['id'] ?>" class="btn btn-sm btn-outline-danger rounded-pill px-3" onclick="return confirm('<?= t('are_you_sure') ?>')"><?= t('delete') ?></a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
|
<?php if (empty($products)): ?>
|
||||||
|
<tr>
|
||||||
|
<td colspan="6" class="text-center py-5 text-muted">
|
||||||
|
<i class="bi bi-inbox fs-1 d-block mb-2 opacity-25"></i>
|
||||||
|
<?= t('none') ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endif; ?>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Bottom Pagination -->
|
||||||
<div class="p-3 border-top bg-light">
|
<div class="p-3 border-top bg-light">
|
||||||
<?php render_pagination_controls($products_pagination); ?>
|
<?php render_pagination_controls($products_pagination); ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
</div>
|
||||||
|
|
||||||
<!-- Product Modal -->
|
<!-- Product Modal -->
|
||||||
<?php if (has_permission('products_add') || has_permission('products_edit')): ?>
|
<?php if (has_permission('products_add') || has_permission('products_edit')): ?>
|
||||||
@ -279,89 +278,81 @@ include 'includes/header.php';
|
|||||||
<input type="hidden" name="action" id="productAction" value="add_product">
|
<input type="hidden" name="action" id="productAction" value="add_product">
|
||||||
<input type="hidden" name="id" id="productId">
|
<input type="hidden" name="id" id="productId">
|
||||||
|
|
||||||
<div class="row g-3 mb-4">
|
<div class="row g-3">
|
||||||
<div class="col-md-8">
|
<div class="col-md-6">
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label small fw-bold text-muted d-flex justify-content-between">
|
<label class="form-label small fw-bold text-muted d-flex justify-content-between">
|
||||||
<span><?= t('name') ?> (EN) <span class="text-danger">*</span></span>
|
<span><?= t('name') ?> (EN) <span class="text-danger">*</span></span>
|
||||||
<a href="javascript:void(0)" onclick="translateTo('English')" class="text-decoration-none small text-primary fw-bold" id="translateBtnEn">
|
<a href="javascript:void(0)" onclick="translateTo('English')" class="text-decoration-none small text-primary fw-bold" id="translateBtnEn">
|
||||||
<i class="bi bi-translate me-1"></i> Auto-translate
|
<i class="bi bi-translate me-1"></i> Auto-translate
|
||||||
</a>
|
</a>
|
||||||
</label>
|
</label>
|
||||||
<input type="text" name="name" id="productName" class="form-control rounded-3" required>
|
<input type="text" name="name" id="productName" class="form-control rounded-3 border-0 bg-light" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="col-md-6">
|
||||||
<label class="form-label small fw-bold text-muted d-flex justify-content-between">
|
<label class="form-label small fw-bold text-muted d-flex justify-content-between">
|
||||||
<span><?= t('arabic_name') ?></span>
|
<span><?= t('arabic_name') ?></span>
|
||||||
<a href="javascript:void(0)" onclick="translateTo('Arabic')" class="text-decoration-none small text-primary fw-bold" id="translateBtnAr">
|
<a href="javascript:void(0)" onclick="translateTo('Arabic')" class="text-decoration-none small text-primary fw-bold" id="translateBtnAr">
|
||||||
<i class="bi bi-translate me-1"></i> Auto-translate
|
<i class="bi bi-translate me-1"></i> Auto-translate
|
||||||
</a>
|
</a>
|
||||||
</label>
|
</label>
|
||||||
<div class="input-group">
|
<input type="text" name="name_ar" id="productNameAr" class="form-control rounded-3 border-0 bg-light" dir="rtl">
|
||||||
<input type="text" name="name_ar" id="productNameAr" class="form-control rounded-3 text-end" dir="rtl" placeholder="الاسم بالعربية">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="row g-3">
|
<div class="col-md-6">
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
<label class="form-label small fw-bold text-muted"><?= t('category') ?> <span class="text-danger">*</span></label>
|
<label class="form-label small fw-bold text-muted"><?= t('category') ?> <span class="text-danger">*</span></label>
|
||||||
<select name="category_id" id="productCategoryId" class="form-select rounded-3" required>
|
<select name="category_id" id="productCategoryId" class="form-select rounded-3 border-0 bg-light" required>
|
||||||
|
<option value=""><?= t('select') ?> <?= t('category') ?></option>
|
||||||
<?php foreach ($categories as $cat): ?>
|
<?php foreach ($categories as $cat): ?>
|
||||||
<option value="<?= $cat['id'] ?>"><?= htmlspecialchars($cat['name']) ?></option>
|
<option value="<?= $cat['id'] ?>"><?= htmlspecialchars($cat['name']) ?></option>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
|
<div class="col-md-3">
|
||||||
<label class="form-label small fw-bold text-muted"><?= t('price') ?> <span class="text-danger">*</span></label>
|
<label class="form-label small fw-bold text-muted"><?= t('price') ?> <span class="text-danger">*</span></label>
|
||||||
<div class="input-group">
|
|
||||||
<span class="input-group-text bg-light border-0"><?= get_company_settings()['currency_symbol'] ?></span>
|
|
||||||
<input type="number" step="0.01" name="price" id="productPrice" class="form-control rounded-3 border-0 bg-light" required>
|
<input type="number" step="0.01" name="price" id="productPrice" class="form-control rounded-3 border-0 bg-light" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
<div class="col-md-3">
|
||||||
<div class="row g-3">
|
<label class="form-label small fw-bold text-muted"><?= t('cost') ?> <?= t('price') ?></label>
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
<label class="form-label small fw-bold text-muted">COST PRICE</label>
|
|
||||||
<input type="number" step="0.01" name="cost_price" id="productCostPrice" class="form-control rounded-3 border-0 bg-light">
|
<input type="number" step="0.01" name="cost_price" id="productCostPrice" class="form-control rounded-3 border-0 bg-light">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
<label class="form-label small fw-bold text-muted"><?= t('stock') ?></label>
|
<div class="col-md-4">
|
||||||
|
<label class="form-label small fw-bold text-muted"><?= t('stock') ?> <?= t('quantity') ?></label>
|
||||||
<input type="number" name="stock_quantity" id="productStockQuantity" class="form-control rounded-3 border-0 bg-light">
|
<input type="number" name="stock_quantity" id="productStockQuantity" class="form-control rounded-3 border-0 bg-light">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<div class="card bg-light border-0 h-100 rounded-4">
|
|
||||||
<div class="card-body">
|
|
||||||
<h6 class="fw-bold mb-3"><i class="bi bi-percent me-2 text-primary"></i>Promotion</h6>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label small fw-bold text-muted">DISCOUNT (%)</label>
|
|
||||||
<input type="number" step="0.01" name="promo_discount_percent" id="productPromoDiscount" class="form-control border-0 rounded-3">
|
|
||||||
</div>
|
|
||||||
<div class="mb-2">
|
|
||||||
<label class="form-label small fw-bold text-muted">START DATE</label>
|
|
||||||
<input type="date" name="promo_date_from" id="productPromoFrom" class="form-control border-0 rounded-3">
|
|
||||||
</div>
|
|
||||||
<div class="mb-0">
|
|
||||||
<label class="form-label small fw-bold text-muted">END DATE</label>
|
|
||||||
<input type="date" name="promo_date_to" id="productPromoTo" class="form-control border-0 rounded-3">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-4">
|
<div class="col-md-8">
|
||||||
<label class="form-label small fw-bold text-muted"><?= t('description') ?></label>
|
<label class="form-label small fw-bold text-muted"><?= t('description') ?></label>
|
||||||
<textarea name="description" id="productDescription" class="form-control rounded-3" rows="3" placeholder="Describe your product..."></textarea>
|
<input type="text" name="description" id="productDescription" class="form-control rounded-3 border-0 bg-light">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-0">
|
<div class="col-12">
|
||||||
<label class="form-label small fw-bold text-muted">PRODUCT IMAGE</label>
|
<label class="form-label small fw-bold text-muted"><?= t('image') ?></label>
|
||||||
<div class="d-flex align-items-center gap-3 bg-light p-3 rounded-4 border border-dashed">
|
<div class="d-flex align-items-center gap-3 bg-light p-3 rounded-4 border border-dashed">
|
||||||
<img src="" id="productImagePreview" class="rounded-3 border shadow-sm" style="width: 64px; height: 64px; object-fit: cover; display: none;">
|
<img src="" id="productImagePreview" class="rounded-3 border shadow-sm" style="width: 60px; height: 60px; object-fit: cover; display: none;">
|
||||||
<div class="flex-grow-1">
|
<div class="flex-grow-1">
|
||||||
<input type="file" name="image" class="form-control border-0 bg-transparent" accept="image/*">
|
<input type="file" name="image" class="form-control border-0 bg-transparent" accept="image/*">
|
||||||
<small class="text-muted">Recommended: Square image, max 2MB.</small>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 mt-4">
|
||||||
|
<h6 class="fw-bold border-bottom pb-2 mb-3"><i class="bi bi-percent me-1"></i> Promotion Settings</h6>
|
||||||
|
<div class="row g-3">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label small fw-bold text-muted">Discount (%)</label>
|
||||||
|
<input type="number" step="0.1" name="promo_discount_percent" id="productPromoDiscount" class="form-control rounded-3 border-0 bg-light" min="0" max="100">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label small fw-bold text-muted">From Date</label>
|
||||||
|
<input type="date" name="promo_date_from" id="productPromoFrom" class="form-control rounded-3 border-0 bg-light">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label small fw-bold text-muted">To Date</label>
|
||||||
|
<input type="date" name="promo_date_to" id="productPromoTo" class="form-control rounded-3 border-0 bg-light">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -384,25 +375,25 @@ function prepareAddForm() {
|
|||||||
document.getElementById('productImagePreview').style.display = 'none';
|
document.getElementById('productImagePreview').style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepareEditForm(prod) {
|
function prepareEditForm(p) {
|
||||||
if (!prod) return;
|
if (!p) return;
|
||||||
document.getElementById('productModalTitle').innerText = '<?= t('edit') ?> <?= t('products') ?>: ' + prod.name;
|
document.getElementById('productModalTitle').innerText = '<?= t('edit') ?>: ' + p.name;
|
||||||
document.getElementById('productAction').value = 'edit_product';
|
document.getElementById('productAction').value = 'edit_product';
|
||||||
document.getElementById('productId').value = prod.id;
|
document.getElementById('productId').value = p.id;
|
||||||
document.getElementById('productName').value = prod.name;
|
document.getElementById('productName').value = p.name;
|
||||||
document.getElementById('productNameAr').value = prod.name_ar || '';
|
document.getElementById('productNameAr').value = p.name_ar || '';
|
||||||
document.getElementById('productCategoryId').value = prod.category_id;
|
document.getElementById('productCategoryId').value = p.category_id;
|
||||||
document.getElementById('productPrice').value = prod.price;
|
document.getElementById('productPrice').value = p.price;
|
||||||
document.getElementById('productCostPrice').value = prod.cost_price || '';
|
document.getElementById('productCostPrice').value = p.cost_price || '';
|
||||||
document.getElementById('productStockQuantity').value = prod.stock_quantity || '0';
|
document.getElementById('productStockQuantity').value = p.stock_quantity || '0';
|
||||||
document.getElementById('productDescription').value = prod.description || '';
|
document.getElementById('productDescription').value = p.description || '';
|
||||||
document.getElementById('productPromoDiscount').value = prod.promo_discount_percent || '';
|
document.getElementById('productPromoDiscount').value = p.promo_discount_percent || '';
|
||||||
document.getElementById('productPromoFrom').value = prod.promo_date_from || '';
|
document.getElementById('productPromoFrom').value = p.promo_date_from || '';
|
||||||
document.getElementById('productPromoTo').value = prod.promo_date_to || '';
|
document.getElementById('productPromoTo').value = p.promo_date_to || '';
|
||||||
|
|
||||||
if (prod.image_url) {
|
if (p.image_url) {
|
||||||
const preview = document.getElementById('productImagePreview');
|
const preview = document.getElementById('productImagePreview');
|
||||||
preview.src = prod.image_url.startsWith('http') ? prod.image_url : '../' + prod.image_url;
|
preview.src = p.image_url.startsWith('http') ? p.image_url : '../' + p.image_url;
|
||||||
preview.style.display = 'block';
|
preview.style.display = 'block';
|
||||||
} else {
|
} else {
|
||||||
document.getElementById('productImagePreview').style.display = 'none';
|
document.getElementById('productImagePreview').style.display = 'none';
|
||||||
|
|||||||
@ -81,14 +81,22 @@ if (isset($_GET['delete'])) {
|
|||||||
if (!has_permission('purchases_del')) {
|
if (!has_permission('purchases_del')) {
|
||||||
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete purchases.</div>';
|
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete purchases.</div>';
|
||||||
} else {
|
} else {
|
||||||
|
try {
|
||||||
$id = $_GET['delete'];
|
$id = $_GET['delete'];
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
$pdo->prepare("DELETE FROM purchase_items WHERE purchase_id = ?")->execute([$id]);
|
||||||
$pdo->prepare("DELETE FROM purchases WHERE id = ?")->execute([$id]);
|
$pdo->prepare("DELETE FROM purchases WHERE id = ?")->execute([$id]);
|
||||||
header("Location: purchases.php?msg=deleted");
|
$pdo->commit();
|
||||||
|
header("Location: purchases.php?deleted=1");
|
||||||
exit;
|
exit;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$pdo->rollBack();
|
||||||
|
$message = '<div class="alert alert-danger">Error deleting purchase: ' . $e->getMessage() . '</div>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($_GET['msg']) && $_GET['msg'] === 'deleted') {
|
if (isset($_GET['deleted'])) {
|
||||||
$message = '<div class="alert alert-success alert-dismissible fade show" role="alert">Purchase record deleted successfully!<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button></div>';
|
$message = '<div class="alert alert-success alert-dismissible fade show" role="alert">Purchase record deleted successfully!<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button></div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -27,11 +27,19 @@ if (isset($_GET['delete'])) {
|
|||||||
if (!has_permission('settings')) { // Use settings permission for deletion
|
if (!has_permission('settings')) { // Use settings permission for deletion
|
||||||
$message = '<div class="alert alert-danger">Access Denied.</div>';
|
$message = '<div class="alert alert-danger">Access Denied.</div>';
|
||||||
} else {
|
} else {
|
||||||
|
try {
|
||||||
$id = $_GET['delete'];
|
$id = $_GET['delete'];
|
||||||
$pdo->prepare("DELETE FROM staff_ratings WHERE id = ?")->execute([$id]);
|
$pdo->prepare("DELETE FROM staff_ratings WHERE id = ?")->execute([$id]);
|
||||||
header("Location: ratings.php");
|
header("Location: ratings.php?deleted=1");
|
||||||
exit;
|
exit;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$message = '<div class="alert alert-danger">Error deleting rating: ' . $e->getMessage() . '</div>';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_GET['deleted'])) {
|
||||||
|
$message = '<div class="alert alert-success">Rating deleted successfully!</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
$staff = $pdo->query("SELECT id, full_name, username FROM users WHERE is_ratable = 1 ORDER BY full_name ASC")->fetchAll();
|
$staff = $pdo->query("SELECT id, full_name, username FROM users WHERE is_ratable = 1 ORDER BY full_name ASC")->fetchAll();
|
||||||
|
|||||||
@ -43,19 +43,28 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle Delete
|
// Handle Delete (Soft Delete)
|
||||||
if (isset($_GET['delete'])) {
|
if (isset($_GET['delete'])) {
|
||||||
if (!has_permission('suppliers_del')) {
|
if (!has_permission('suppliers_del')) {
|
||||||
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete suppliers.</div>';
|
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete suppliers.</div>';
|
||||||
} else {
|
} else {
|
||||||
$id = $_GET['delete'];
|
try {
|
||||||
$pdo->prepare("DELETE FROM suppliers WHERE id = ?")->execute([$id]);
|
$id = (int)$_GET['delete'];
|
||||||
header("Location: suppliers.php");
|
// Soft delete to preserve data integrity for purchases
|
||||||
|
$pdo->prepare("UPDATE suppliers SET is_deleted = 1 WHERE id = ?")->execute([$id]);
|
||||||
|
header("Location: suppliers.php?deleted=1");
|
||||||
exit;
|
exit;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$message = '<div class="alert alert-danger">Error removing supplier: ' . $e->getMessage() . '</div>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = "SELECT * FROM suppliers ORDER BY name ASC";
|
if (isset($_GET['deleted'])) {
|
||||||
|
$message = '<div class="alert alert-success">Supplier removed successfully!</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = "SELECT * FROM suppliers WHERE is_deleted = 0 ORDER BY name ASC";
|
||||||
$suppliers_pagination = paginate_query($pdo, $query);
|
$suppliers_pagination = paginate_query($pdo, $query);
|
||||||
$suppliers = $suppliers_pagination['data'];
|
$suppliers = $suppliers_pagination['data'];
|
||||||
|
|
||||||
@ -109,7 +118,7 @@ include 'includes/header.php';
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if (has_permission('suppliers_del')): ?>
|
<?php if (has_permission('suppliers_del')): ?>
|
||||||
<a href="?delete=<?= $supplier['id'] ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('Delete this supplier?')"><i class="bi bi-trash"></i></a>
|
<a href="?delete=<?= $supplier['id'] ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('<?= t('are_you_sure') ?>')"><i class="bi bi-trash"></i></a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@ -42,23 +42,33 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle Delete
|
// Handle Delete (Soft Delete)
|
||||||
if (isset($_GET['delete'])) {
|
if (isset($_GET['delete'])) {
|
||||||
if (!has_permission('tables_del')) {
|
if (!has_permission('tables_del')) {
|
||||||
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete tables.</div>';
|
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete tables.</div>';
|
||||||
} else {
|
} else {
|
||||||
$id = $_GET['delete'];
|
try {
|
||||||
$pdo->prepare("DELETE FROM tables WHERE id = ?")->execute([$id]);
|
$id = (int)$_GET['delete'];
|
||||||
header("Location: tables.php");
|
// Soft delete to avoid breaking historical order integrity
|
||||||
|
$pdo->prepare("UPDATE tables SET is_deleted = 1 WHERE id = ?")->execute([$id]);
|
||||||
|
header("Location: tables.php?deleted=1");
|
||||||
exit;
|
exit;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$message = '<div class="alert alert-danger">Error removing table: ' . $e->getMessage() . '</div>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$areas = $pdo->query("SELECT * FROM areas ORDER BY name ASC")->fetchAll();
|
if (isset($_GET['deleted'])) {
|
||||||
|
$message = '<div class="alert alert-success">Table removed successfully!</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$areas = $pdo->query("SELECT * FROM areas WHERE is_deleted = 0 ORDER BY name ASC")->fetchAll();
|
||||||
|
|
||||||
$query = "SELECT t.*, a.name as area_name
|
$query = "SELECT t.*, a.name as area_name
|
||||||
FROM tables t
|
FROM tables t
|
||||||
LEFT JOIN areas a ON t.area_id = a.id
|
LEFT JOIN areas a ON t.area_id = a.id
|
||||||
|
WHERE t.is_deleted = 0
|
||||||
ORDER BY a.name ASC, t.table_number ASC";
|
ORDER BY a.name ASC, t.table_number ASC";
|
||||||
$tables_pagination = paginate_query($pdo, $query);
|
$tables_pagination = paginate_query($pdo, $query);
|
||||||
$tables = $tables_pagination['data'];
|
$tables = $tables_pagination['data'];
|
||||||
@ -119,7 +129,7 @@ include 'includes/header.php';
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if (has_permission('tables_del')): ?>
|
<?php if (has_permission('tables_del')): ?>
|
||||||
<a href="?delete=<?= $table['id'] ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('Delete this table?')"><i class="bi bi-trash"></i></a>
|
<a href="?delete=<?= $table['id'] ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('<?= t('are_you_sure') ?>')"><i class="bi bi-trash"></i></a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@ -33,6 +33,7 @@ if (isset($_GET['delete'])) {
|
|||||||
if (!has_permission('user_groups_del')) {
|
if (!has_permission('user_groups_del')) {
|
||||||
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete user groups.</div>';
|
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete user groups.</div>';
|
||||||
} else {
|
} else {
|
||||||
|
try {
|
||||||
$id = $_GET['delete'];
|
$id = $_GET['delete'];
|
||||||
// Don't allow deleting Administrator group
|
// Don't allow deleting Administrator group
|
||||||
$stmt = $pdo->prepare("SELECT name FROM user_groups WHERE id = ?");
|
$stmt = $pdo->prepare("SELECT name FROM user_groups WHERE id = ?");
|
||||||
@ -43,10 +44,21 @@ if (isset($_GET['delete'])) {
|
|||||||
$message = '<div class="alert alert-danger">The Administrator group cannot be deleted.</div>';
|
$message = '<div class="alert alert-danger">The Administrator group cannot be deleted.</div>';
|
||||||
} else {
|
} else {
|
||||||
$pdo->prepare("DELETE FROM user_groups WHERE id = ?")->execute([$id]);
|
$pdo->prepare("DELETE FROM user_groups WHERE id = ?")->execute([$id]);
|
||||||
header("Location: user_groups.php");
|
header("Location: user_groups.php?deleted=1");
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
if ($e->getCode() == '23000') {
|
||||||
|
$message = '<div class="alert alert-danger">Cannot delete this group because it is linked to users.</div>';
|
||||||
|
} else {
|
||||||
|
$message = '<div class="alert alert-danger">Error deleting group: ' . $e->getMessage() . '</div>';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_GET['deleted'])) {
|
||||||
|
$message = '<div class="alert alert-success">User group deleted successfully!</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
$availablePermissions = [
|
$availablePermissions = [
|
||||||
|
|||||||
@ -104,29 +104,39 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle Delete
|
// Handle Delete (Soft Delete)
|
||||||
if (isset($_GET['delete'])) {
|
if (isset($_GET['delete'])) {
|
||||||
if (!has_permission('users_del')) {
|
if (!has_permission('users_del')) {
|
||||||
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete users.</div>';
|
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to delete users.</div>';
|
||||||
} else {
|
} else {
|
||||||
$id = $_GET['delete'];
|
$id = (int)$_GET['delete'];
|
||||||
// Don't allow deleting current user
|
// Don't allow deleting current user
|
||||||
if ($id == $_SESSION['user']['id']) {
|
if ($id == $_SESSION['user']['id']) {
|
||||||
$message = '<div class="alert alert-danger text-center">You cannot delete your own account.</div>';
|
$message = '<div class="alert alert-danger text-center">You cannot remove your own account.</div>';
|
||||||
} else {
|
} else {
|
||||||
$pdo->prepare("DELETE FROM users WHERE id = ?")->execute([$id]);
|
try {
|
||||||
header("Location: users.php");
|
// Use Soft Delete to preserve data integrity for orders and staff ratings
|
||||||
|
$pdo->prepare("UPDATE users SET is_deleted = 1, is_active = 0 WHERE id = ?")->execute([$id]);
|
||||||
|
header("Location: users.php?deleted=1");
|
||||||
exit;
|
exit;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$message = '<div class="alert alert-danger">Error removing user: ' . $e->getMessage() . '</div>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$groups = $pdo->query("SELECT * FROM user_groups ORDER BY name ASC")->fetchAll();
|
if (isset($_GET['deleted'])) {
|
||||||
$all_outlets = $pdo->query("SELECT * FROM outlets ORDER BY name ASC")->fetchAll();
|
$message = '<div class="alert alert-success">User removed successfully!</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$groups = $pdo->query("SELECT * FROM user_groups WHERE is_deleted = 0 ORDER BY name ASC")->fetchAll();
|
||||||
|
$all_outlets = $pdo->query("SELECT * FROM outlets WHERE is_deleted = 0 ORDER BY name ASC")->fetchAll();
|
||||||
|
|
||||||
$query = "SELECT u.*, g.name as group_name
|
$query = "SELECT u.*, g.name as group_name
|
||||||
FROM users u
|
FROM users u
|
||||||
LEFT JOIN user_groups g ON u.group_id = g.id
|
LEFT JOIN user_groups g ON u.group_id = g.id
|
||||||
|
WHERE u.is_deleted = 0
|
||||||
ORDER BY u.id DESC";
|
ORDER BY u.id DESC";
|
||||||
$users_pagination = paginate_query($pdo, $query);
|
$users_pagination = paginate_query($pdo, $query);
|
||||||
$users = $users_pagination['data'];
|
$users = $users_pagination['data'];
|
||||||
@ -212,7 +222,7 @@ include 'includes/header.php';
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if (has_permission('users_del')): ?>
|
<?php if (has_permission('users_del')): ?>
|
||||||
<a href="?delete=<?= $user['id'] ?>" class="btn btn-sm btn-outline-danger rounded-pill px-3" onclick="return confirm('Permanently delete this user account?')">
|
<a href="?delete=<?= $user['id'] ?>" class="btn btn-sm btn-outline-danger rounded-pill px-3" onclick="return confirm('<?= t('are_you_sure') ?>')">
|
||||||
<i class="bi bi-trash"></i>
|
<i class="bi bi-trash"></i>
|
||||||
</a>
|
</a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|||||||
@ -15,10 +15,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
|||||||
$stmt = $pdo->prepare("
|
$stmt = $pdo->prepare("
|
||||||
SELECT
|
SELECT
|
||||||
o.id, o.table_number, o.order_type, o.status, o.created_at, o.customer_name,
|
o.id, o.table_number, o.order_type, o.status, o.created_at, o.customer_name,
|
||||||
oi.quantity, p.name as product_name, v.name as variant_name
|
oi.quantity, COALESCE(p.name, oi.product_name) as product_name, COALESCE(v.name, oi.variant_name) as variant_name
|
||||||
FROM orders o
|
FROM orders o
|
||||||
JOIN order_items oi ON o.id = oi.order_id
|
JOIN order_items oi ON o.id = oi.order_id
|
||||||
JOIN products p ON oi.product_id = p.id
|
LEFT JOIN products p ON oi.product_id = p.id
|
||||||
LEFT JOIN product_variants v ON oi.variant_id = v.id
|
LEFT JOIN product_variants v ON oi.variant_id = v.id
|
||||||
WHERE o.status IN ('pending', 'preparing', 'ready')
|
WHERE o.status IN ('pending', 'preparing', 'ready')
|
||||||
AND o.outlet_id = :outlet_id
|
AND o.outlet_id = :outlet_id
|
||||||
|
|||||||
@ -164,13 +164,15 @@ try {
|
|||||||
|
|
||||||
$unit_price = get_product_price($product);
|
$unit_price = get_product_price($product);
|
||||||
|
|
||||||
|
$variant_name = null;
|
||||||
// Add variant adjustment
|
// Add variant adjustment
|
||||||
if ($vid) {
|
if ($vid) {
|
||||||
$vStmt = $pdo->prepare("SELECT price_adjustment FROM product_variants WHERE id = ? AND product_id = ?");
|
$vStmt = $pdo->prepare("SELECT name, price_adjustment FROM product_variants WHERE id = ? AND product_id = ?");
|
||||||
$vStmt->execute([$vid, $pid]);
|
$vStmt->execute([$vid, $pid]);
|
||||||
$vAdjustment = $vStmt->fetchColumn();
|
$variant = $vStmt->fetch(PDO::FETCH_ASSOC);
|
||||||
if ($vAdjustment !== false) {
|
if ($variant) {
|
||||||
$unit_price += floatval($vAdjustment);
|
$unit_price += floatval($variant['price_adjustment']);
|
||||||
|
$variant_name = $variant['name'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,10 +181,11 @@ try {
|
|||||||
|
|
||||||
$processed_items[] = [
|
$processed_items[] = [
|
||||||
'product_id' => $pid,
|
'product_id' => $pid,
|
||||||
|
'product_name' => $product['name'],
|
||||||
'variant_id' => $vid,
|
'variant_id' => $vid,
|
||||||
|
'variant_name' => $variant_name,
|
||||||
'quantity' => $qty,
|
'quantity' => $qty,
|
||||||
'unit_price' => $unit_price,
|
'unit_price' => $unit_price
|
||||||
'name' => $product['name']
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -251,23 +254,20 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Insert Items and Update Stock
|
// Insert Items and Update Stock
|
||||||
$item_stmt = $pdo->prepare("INSERT INTO order_items (order_id, product_id, variant_id, quantity, unit_price) VALUES (?, ?, ?, ?, ?)");
|
$item_stmt = $pdo->prepare("INSERT INTO order_items (order_id, product_id, product_name, variant_id, variant_name, quantity, unit_price) VALUES (?, ?, ?, ?, ?, ?, ?)");
|
||||||
$stock_stmt = $pdo->prepare("UPDATE products SET stock_quantity = stock_quantity - ? WHERE id = ?");
|
$stock_stmt = $pdo->prepare("UPDATE products SET stock_quantity = stock_quantity - ? WHERE id = ?");
|
||||||
$varNameStmt = $pdo->prepare("SELECT name FROM product_variants WHERE id = ?");
|
|
||||||
|
|
||||||
$order_items_list = [];
|
$order_items_list = [];
|
||||||
|
|
||||||
foreach ($processed_items as $pi) {
|
foreach ($processed_items as $pi) {
|
||||||
$item_stmt->execute([$order_id, $pi['product_id'], $pi['variant_id'], $pi['quantity'], $pi['unit_price']]);
|
$item_stmt->execute([$order_id, $pi['product_id'], $pi['product_name'], $pi['variant_id'], $pi['variant_name'], $pi['quantity'], $pi['unit_price']]);
|
||||||
|
|
||||||
// Decrement Stock
|
// Decrement Stock
|
||||||
$stock_stmt->execute([$pi['quantity'], $pi['product_id']]);
|
$stock_stmt->execute([$pi['quantity'], $pi['product_id']]);
|
||||||
|
|
||||||
$pName = $pi['name'];
|
$pName = $pi['product_name'];
|
||||||
if ($pi['variant_id']) {
|
if ($pi['variant_name']) {
|
||||||
$varNameStmt->execute([$pi['variant_id']]);
|
$pName .= " ({$pi['variant_name']})";
|
||||||
$vName = $varNameStmt->fetchColumn();
|
|
||||||
if ($vName) $pName .= " ($vName)";
|
|
||||||
}
|
}
|
||||||
$order_items_list[] = "{$pi['quantity']} x $pName";
|
$order_items_list[] = "{$pi['quantity']} x $pName";
|
||||||
}
|
}
|
||||||
|
|||||||
11
db/migrations/035_soft_delete_system.sql
Normal file
11
db/migrations/035_soft_delete_system.sql
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
-- Soft Delete System
|
||||||
|
ALTER TABLE categories ADD COLUMN is_deleted TINYINT(1) DEFAULT 0;
|
||||||
|
ALTER TABLE products ADD COLUMN is_deleted TINYINT(1) DEFAULT 0;
|
||||||
|
ALTER TABLE outlets ADD COLUMN is_deleted TINYINT(1) DEFAULT 0;
|
||||||
|
ALTER TABLE tables ADD COLUMN is_deleted TINYINT(1) DEFAULT 0;
|
||||||
|
ALTER TABLE areas ADD COLUMN is_deleted TINYINT(1) DEFAULT 0;
|
||||||
|
ALTER TABLE users ADD COLUMN is_deleted TINYINT(1) DEFAULT 0;
|
||||||
|
ALTER TABLE user_groups ADD COLUMN is_deleted TINYINT(1) DEFAULT 0;
|
||||||
|
ALTER TABLE suppliers ADD COLUMN is_deleted TINYINT(1) DEFAULT 0;
|
||||||
|
ALTER TABLE expense_categories ADD COLUMN is_deleted TINYINT(1) DEFAULT 0;
|
||||||
|
ALTER TABLE payment_types ADD COLUMN is_deleted TINYINT(1) DEFAULT 0;
|
||||||
2
db/migrations/036_soft_delete_variants.sql
Normal file
2
db/migrations/036_soft_delete_variants.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
-- Soft delete for product variants
|
||||||
|
ALTER TABLE product_variants ADD COLUMN is_deleted TINYINT(1) DEFAULT 0;
|
||||||
11
db/migrations/037_order_items_preservation.sql
Normal file
11
db/migrations/037_order_items_preservation.sql
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
-- Preserve names in order_items for historical data
|
||||||
|
ALTER TABLE order_items ADD COLUMN product_name VARCHAR(255) AFTER product_id;
|
||||||
|
ALTER TABLE order_items ADD COLUMN variant_name VARCHAR(255) AFTER variant_id;
|
||||||
|
|
||||||
|
-- Populate existing names
|
||||||
|
UPDATE order_items oi JOIN products p ON oi.product_id = p.id SET oi.product_name = p.name;
|
||||||
|
UPDATE order_items oi JOIN product_variants pv ON oi.variant_id = pv.id SET oi.variant_name = pv.name;
|
||||||
|
|
||||||
|
-- Modify foreign key to allow hard delete while preserving historical info
|
||||||
|
ALTER TABLE order_items DROP FOREIGN KEY order_items_ibfk_2;
|
||||||
|
ALTER TABLE order_items ADD CONSTRAINT order_items_ibfk_2 FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE SET NULL;
|
||||||
12
pos.php
12
pos.php
@ -18,12 +18,12 @@ $currentUser = get_logged_user();
|
|||||||
|
|
||||||
// Fetch outlets based on user assignment
|
// Fetch outlets based on user assignment
|
||||||
if (has_permission('all')) {
|
if (has_permission('all')) {
|
||||||
$outlets = $pdo->query("SELECT * FROM outlets ORDER BY name")->fetchAll();
|
$outlets = $pdo->query("SELECT * FROM outlets WHERE is_deleted = 0 ORDER BY name")->fetchAll();
|
||||||
} else {
|
} else {
|
||||||
$stmt = $pdo->prepare("
|
$stmt = $pdo->prepare("
|
||||||
SELECT o.* FROM outlets o
|
SELECT o.* FROM outlets o
|
||||||
JOIN user_outlets uo ON o.id = uo.outlet_id
|
JOIN user_outlets uo ON o.id = uo.outlet_id
|
||||||
WHERE uo.user_id = ?
|
WHERE uo.user_id = ? AND o.is_deleted = 0
|
||||||
ORDER BY o.name
|
ORDER BY o.name
|
||||||
");
|
");
|
||||||
$stmt->execute([$currentUser['id']]);
|
$stmt->execute([$currentUser['id']]);
|
||||||
@ -46,12 +46,12 @@ if (!has_permission('all')) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$categories = $pdo->query("SELECT * FROM categories ORDER BY sort_order")->fetchAll();
|
$categories = $pdo->query("SELECT * FROM categories WHERE is_deleted = 0 ORDER BY sort_order")->fetchAll();
|
||||||
$all_products = $pdo->query("SELECT p.*, c.name as category_name, c.name_ar as category_name_ar FROM products p JOIN categories c ON p.category_id = c.id")->fetchAll();
|
$all_products = $pdo->query("SELECT p.*, c.name as category_name, c.name_ar as category_name_ar FROM products p JOIN categories c ON p.category_id = c.id WHERE p.is_deleted = 0 AND c.is_deleted = 0")->fetchAll();
|
||||||
$payment_types = $pdo->query("SELECT * FROM payment_types WHERE is_active = 1 ORDER BY id")->fetchAll();
|
$payment_types = $pdo->query("SELECT * FROM payment_types WHERE is_active = 1 AND is_deleted = 0 ORDER BY id")->fetchAll();
|
||||||
|
|
||||||
// Fetch variants
|
// Fetch variants
|
||||||
$variants_raw = $pdo->query("SELECT * FROM product_variants ORDER BY price_adjustment ASC")->fetchAll();
|
$variants_raw = $pdo->query("SELECT * FROM product_variants WHERE is_deleted = 0 ORDER BY price_adjustment ASC")->fetchAll();
|
||||||
$variants_by_product = [];
|
$variants_by_product = [];
|
||||||
foreach ($variants_raw as $v) {
|
foreach ($variants_raw as $v) {
|
||||||
$variants_by_product[$v['product_id']][] = $v;
|
$variants_by_product[$v['product_id']][] = $v;
|
||||||
|
|||||||
9
rate.php
9
rate.php
@ -51,6 +51,9 @@ $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css" rel="stylesheet">
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&family=Noto+Sans+Arabic:wght@400;600;700&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&family=Noto+Sans+Arabic:wght@400;600;700&display=swap" rel="stylesheet">
|
||||||
|
<?php if ($success): ?>
|
||||||
|
<meta http-equiv="refresh" content="3;url=rate.php">
|
||||||
|
<?php endif; ?>
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--primary-color: #007bff;
|
--primary-color: #007bff;
|
||||||
@ -265,7 +268,7 @@ $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
<i class="bi bi-check-circle-fill success-icon"></i>
|
<i class="bi bi-check-circle-fill success-icon"></i>
|
||||||
<h2 data-t="thank_you">Thank You!</h2>
|
<h2 data-t="thank_you">Thank You!</h2>
|
||||||
<p data-t="success_msg">Your rating has been submitted successfully.</p>
|
<p data-t="success_msg">Your rating has been submitted successfully.</p>
|
||||||
<a href="index.php" class="btn btn-outline-primary rounded-pill px-4 mt-3" data-t="back_home">Back to Home</a>
|
<a href="rate.php" class="btn btn-outline-primary rounded-pill px-4 mt-3" data-t="back_home">Rate Again</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
@ -359,7 +362,7 @@ const translations = {
|
|||||||
main_instruction: "We value your feedback! What would you like to rate?",
|
main_instruction: "We value your feedback! What would you like to rate?",
|
||||||
thank_you: "Thank You!",
|
thank_you: "Thank You!",
|
||||||
success_msg: "Your rating has been submitted successfully.",
|
success_msg: "Your rating has been submitted successfully.",
|
||||||
back_home: "Back to Home",
|
back_home: "Rate Again",
|
||||||
rate_services: "Rate Our Services",
|
rate_services: "Rate Our Services",
|
||||||
service_subtitle: "How was your overall experience with us?",
|
service_subtitle: "How was your overall experience with us?",
|
||||||
or_rate_staff: "OR RATE OUR STAFF",
|
or_rate_staff: "OR RATE OUR STAFF",
|
||||||
@ -380,7 +383,7 @@ const translations = {
|
|||||||
main_instruction: "نحن نقدر رأيك! ما الذي تود تقييمه؟",
|
main_instruction: "نحن نقدر رأيك! ما الذي تود تقييمه؟",
|
||||||
thank_you: "شكراً لك!",
|
thank_you: "شكراً لك!",
|
||||||
success_msg: "تم إرسال تقييمك بنجاح.",
|
success_msg: "تم إرسال تقييمك بنجاح.",
|
||||||
back_home: "العودة للرئيسية",
|
back_home: "تقييم مرة أخرى",
|
||||||
rate_services: "قيم خدماتنا",
|
rate_services: "قيم خدماتنا",
|
||||||
service_subtitle: "كيف كانت تجربتك العامة معنا؟",
|
service_subtitle: "كيف كانت تجربتك العامة معنا؟",
|
||||||
or_rate_staff: "أو قيم موظفينا",
|
or_rate_staff: "أو قيم موظفينا",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user