321 lines
15 KiB
PHP
321 lines
15 KiB
PHP
<?php
|
|
require_once __DIR__ . '/includes/app.php';
|
|
$user = require_permission('expenses', 'show');
|
|
$pageTitle = tr('المصروفات', 'Expenses');
|
|
$activeNav = 'expenses';
|
|
|
|
$pdo = db();
|
|
|
|
// Fetch Categories for dropdowns
|
|
$catStmt = $pdo->query("SELECT id, name_ar, name_en FROM expense_categories ORDER BY name_ar");
|
|
$categories = $catStmt->fetchAll();
|
|
|
|
$branchesStmt = $pdo->query("SELECT code, name_ar, name_en FROM branches ORDER BY name_ar");
|
|
$branches = $branchesStmt->fetchAll();
|
|
|
|
// Check if user is restricted to a branch
|
|
$userBranch = $user['branch_code'] ?? '';
|
|
$isOwner = $user['role'] === 'owner';
|
|
|
|
// Handle Form Submission
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$action = $_POST['action'] ?? '';
|
|
|
|
if ($action === 'create' && has_permission('expenses', 'add')) {
|
|
$branch_code = $isOwner ? ($_POST['branch_code'] ?? null) : $userBranch;
|
|
$stmt = $pdo->prepare('INSERT INTO expenses (branch_code, category_id, amount, expense_date, description, created_by) VALUES (?, ?, ?, ?, ?, ?)');
|
|
$stmt->execute([
|
|
$branch_code === '' ? null : $branch_code,
|
|
$_POST['category_id'],
|
|
$_POST['amount'],
|
|
$_POST['expense_date'],
|
|
$_POST['description'] ?? '',
|
|
$user['id']
|
|
]);
|
|
set_flash('success', tr('تمت إضافة المصروف بنجاح', 'Expense added successfully'));
|
|
redirect_to('expenses.php');
|
|
} elseif ($action === 'edit' && has_permission('expenses', 'edit')) {
|
|
$branch_code = $isOwner ? ($_POST['branch_code'] ?? null) : $userBranch;
|
|
$stmt = $pdo->prepare('UPDATE expenses SET branch_code = ?, category_id = ?, amount = ?, expense_date = ?, description = ? WHERE id = ?');
|
|
$stmt->execute([
|
|
$branch_code === '' ? null : $branch_code,
|
|
$_POST['category_id'],
|
|
$_POST['amount'],
|
|
$_POST['expense_date'],
|
|
$_POST['description'] ?? '',
|
|
$_POST['id']
|
|
]);
|
|
set_flash('success', tr('تم التحديث بنجاح', 'Updated successfully'));
|
|
redirect_to('expenses.php');
|
|
} elseif ($action === 'delete' && has_permission('expenses', 'del')) {
|
|
$stmt = $pdo->prepare('DELETE FROM expenses WHERE id = ?');
|
|
$stmt->execute([$_POST['id']]);
|
|
set_flash('success', tr('تم الحذف بنجاح', 'Deleted successfully'));
|
|
redirect_to('expenses.php');
|
|
}
|
|
}
|
|
|
|
// Pagination & Search
|
|
$page = max(1, (int)($_GET['p'] ?? 1));
|
|
$limit = 10;
|
|
$offset = ($page - 1) * $limit;
|
|
$search = $_GET['q'] ?? '';
|
|
|
|
$where = '1=1';
|
|
$params = [];
|
|
if ($search) {
|
|
$where .= ' AND (e.description LIKE ?)';
|
|
$params[] = "%$search%";
|
|
}
|
|
|
|
if (!$isOwner && $userBranch) {
|
|
$where .= ' AND (e.branch_code = ? OR e.branch_code IS NULL)';
|
|
$params[] = $userBranch;
|
|
}
|
|
|
|
$totalStmt = $pdo->prepare("SELECT COUNT(*) FROM expenses e WHERE $where");
|
|
$totalStmt->execute($params);
|
|
$total = $totalStmt->fetchColumn();
|
|
$totalPages = ceil($total / $limit);
|
|
|
|
$queryStmt = $pdo->prepare("
|
|
SELECT e.*,
|
|
c.name_ar as category_ar, c.name_en as category_en,
|
|
b.name_ar as branch_ar, b.name_en as branch_en,
|
|
u.name_ar as user_ar, u.name_en as user_en
|
|
FROM expenses e
|
|
LEFT JOIN expense_categories c ON e.category_id = c.id
|
|
LEFT JOIN branches b ON e.branch_code = b.code
|
|
LEFT JOIN users u ON e.created_by = u.id
|
|
WHERE $where
|
|
ORDER BY e.expense_date DESC, e.id DESC
|
|
LIMIT $limit OFFSET $offset
|
|
");
|
|
$queryStmt->execute($params);
|
|
$items = $queryStmt->fetchAll();
|
|
|
|
require __DIR__ . '/includes/header.php';
|
|
?>
|
|
|
|
<section class="surface-card mb-4">
|
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
<div>
|
|
<h3 class="h5 mb-2"><i class="bi bi-wallet2 me-2"></i><?= h($pageTitle) ?></h3>
|
|
<p class="text-muted mb-0"><?= h(tr('إدارة المصروفات وتسجيلها', 'Manage and record expenses')) ?></p>
|
|
</div>
|
|
<?php if(has_permission('expenses', 'add')): ?>
|
|
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addModal">
|
|
<i class="bi bi-plus-lg"></i> <?= h(tr('إضافة مصروف', 'Add Expense')) ?>
|
|
</button>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<form class="d-flex mb-3" method="GET" action="expenses.php">
|
|
<div class="input-group" style="max-width: 400px;">
|
|
<input type="text" name="q" class="form-control" placeholder="<?= h(tr('بحث بالوصف...', 'Search by description...')) ?>" value="<?= h($search) ?>">
|
|
<button class="btn btn-outline-secondary" type="submit"><i class="bi bi-search"></i></button>
|
|
</div>
|
|
</form>
|
|
</section>
|
|
|
|
<section class="surface-card">
|
|
<div class="table-responsive shadow-sm" style="border-radius: 12px; overflow: hidden; border: 1px solid rgba(0,0,0,0.05);">
|
|
<table class="table table-hover align-middle mb-0 text-center" style="background-color: #fff;">
|
|
<thead style="background: linear-gradient(90deg, #0d6efd, #0dcaf0);">
|
|
<tr>
|
|
<th class="text-white border-0 py-3 fw-semibold bg-transparent"><?= h(tr('التاريخ', 'Date')) ?></th>
|
|
<th class="text-white border-0 py-3 fw-semibold bg-transparent"><?= h(tr('التصنيف', 'Category')) ?></th>
|
|
<th class="text-white border-0 py-3 fw-semibold bg-transparent"><?= h(tr('المبلغ', 'Amount')) ?></th>
|
|
<th class="text-white border-0 py-3 fw-semibold bg-transparent"><?= h(tr('الفرع', 'Branch')) ?></th>
|
|
<th class="text-white border-0 py-3 fw-semibold bg-transparent"><?= h(tr('الوصف', 'Description')) ?></th>
|
|
<th class="text-white border-0 py-3 fw-semibold bg-transparent"><?= h(tr('إجراءات', 'Actions')) ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="border-top-0">
|
|
<?php if(empty($items)): ?>
|
|
<tr><td colspan="6" class="text-center text-muted py-4"><?= h(tr('لا توجد بيانات', 'No data found')) ?></td></tr>
|
|
<?php endif; ?>
|
|
<?php foreach ($items as $item): ?>
|
|
<tr>
|
|
<td><?= h($item['expense_date']) ?></td>
|
|
<td><?= h(current_lang() == 'ar' ? $item['category_ar'] : $item['category_en']) ?></td>
|
|
<td><?= h(number_format($item['amount'], 2)) ?></td>
|
|
<td><?= $item['branch_code'] ? h(current_lang() == 'ar' ? $item['branch_ar'] : $item['branch_en']) : '<span class="badge bg-secondary">'.h(tr('عام', 'General')).'</span>' ?></td>
|
|
<td><?= h($item['description']) ?></td>
|
|
<td>
|
|
<?php if(has_permission('expenses', 'edit')): ?>
|
|
<button class="btn btn-sm btn-outline-primary rounded-circle shadow-sm" style="width: 34px; height: 34px; padding: 0;" onclick="editItem(<?= htmlspecialchars(json_encode($item)) ?>)" title="<?= h(tr('تعديل', 'Edit')) ?>">
|
|
<i class="bi bi-pencil"></i>
|
|
</button>
|
|
<?php endif; ?>
|
|
<?php if(has_permission('expenses', 'del')): ?>
|
|
<button class="btn btn-sm btn-outline-danger rounded-circle shadow-sm ms-1" style="width: 34px; height: 34px; padding: 0;" onclick="deleteItem(<?= $item['id'] ?>)" title="<?= h(tr('حذف', 'Delete')) ?>">
|
|
<i class="bi bi-trash"></i>
|
|
</button>
|
|
<?php endif; ?>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<?php if ($totalPages > 1): ?>
|
|
<nav class="mt-4">
|
|
<ul class="pagination justify-content-center mb-0">
|
|
<?php for($i=1; $i<=$totalPages; $i++): ?>
|
|
<li class="page-item <?= $i === $page ? 'active' : '' ?>">
|
|
<a class="page-link" href="<?= h(url_for('expenses.php', ['p' => $i, 'q' => $search])) ?>"><?= $i ?></a>
|
|
</li>
|
|
<?php endfor; ?>
|
|
</ul>
|
|
</nav>
|
|
<?php endif; ?>
|
|
</section>
|
|
|
|
<!-- Add Modal -->
|
|
<div class="modal fade" id="addModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<form method="POST" action="expenses.php">
|
|
<input type="hidden" name="action" value="create">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title"><?= h(tr('إضافة مصروف', 'Add Expense')) ?></h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="mb-3">
|
|
<label class="form-label"><?= h(tr('التاريخ', 'Date')) ?> <span class="text-danger">*</span></label>
|
|
<input type="date" name="expense_date" class="form-control" value="<?= date('Y-m-d') ?>" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label"><?= h(tr('التصنيف', 'Category')) ?> <span class="text-danger">*</span></label>
|
|
<select name="category_id" class="form-select" required>
|
|
<option value=""><?= h(tr('-- اختر التصنيف --', '-- Select Category --')) ?></option>
|
|
<?php foreach($categories as $cat): ?>
|
|
<option value="<?= $cat['id'] ?>"><?= h(current_lang() == 'ar' ? $cat['name_ar'] : $cat['name_en']) ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label"><?= h(tr('المبلغ', 'Amount')) ?> <span class="text-danger">*</span></label>
|
|
<input type="number" step="0.001" name="amount" class="form-control" required>
|
|
</div>
|
|
<?php if($isOwner): ?>
|
|
<div class="mb-3">
|
|
<label class="form-label"><?= h(tr('الفرع', 'Branch')) ?></label>
|
|
<select name="branch_code" class="form-select">
|
|
<option value=""><?= h(tr('مصروف عام (بدون فرع)', 'General (No branch)')) ?></option>
|
|
<?php foreach($branches as $b): ?>
|
|
<option value="<?= h($b['code']) ?>"><?= h(current_lang() == 'ar' ? $b['name_ar'] : $b['name_en']) ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<?php endif; ?>
|
|
<div class="mb-3">
|
|
<label class="form-label"><?= h(tr('الوصف', 'Description')) ?></label>
|
|
<textarea name="description" class="form-control"></textarea>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?= h(tr('إلغاء', 'Cancel')) ?></button>
|
|
<button type="submit" class="btn btn-primary"><?= h(tr('حفظ', 'Save')) ?></button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Edit Modal -->
|
|
<div class="modal fade" id="editModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<form method="POST" action="expenses.php">
|
|
<input type="hidden" name="action" value="edit">
|
|
<input type="hidden" name="id" id="edit_id">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title"><?= h(tr('تعديل', 'Edit')) ?></h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="mb-3">
|
|
<label class="form-label"><?= h(tr('التاريخ', 'Date')) ?> <span class="text-danger">*</span></label>
|
|
<input type="date" name="expense_date" id="edit_expense_date" class="form-control" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label"><?= h(tr('التصنيف', 'Category')) ?> <span class="text-danger">*</span></label>
|
|
<select name="category_id" id="edit_category_id" class="form-select" required>
|
|
<option value=""><?= h(tr('-- اختر التصنيف --', '-- Select Category --')) ?></option>
|
|
<?php foreach($categories as $cat): ?>
|
|
<option value="<?= $cat['id'] ?>"><?= h(current_lang() == 'ar' ? $cat['name_ar'] : $cat['name_en']) ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label"><?= h(tr('المبلغ', 'Amount')) ?> <span class="text-danger">*</span></label>
|
|
<input type="number" step="0.001" name="amount" id="edit_amount" class="form-control" required>
|
|
</div>
|
|
<?php if($isOwner): ?>
|
|
<div class="mb-3">
|
|
<label class="form-label"><?= h(tr('الفرع', 'Branch')) ?></label>
|
|
<select name="branch_code" id="edit_branch_code" class="form-select">
|
|
<option value=""><?= h(tr('مصروف عام (بدون فرع)', 'General (No branch)')) ?></option>
|
|
<?php foreach($branches as $b): ?>
|
|
<option value="<?= h($b['code']) ?>"><?= h(current_lang() == 'ar' ? $b['name_ar'] : $b['name_en']) ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<?php endif; ?>
|
|
<div class="mb-3">
|
|
<label class="form-label"><?= h(tr('الوصف', 'Description')) ?></label>
|
|
<textarea name="description" id="edit_description" class="form-control"></textarea>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?= h(tr('إلغاء', 'Cancel')) ?></button>
|
|
<button type="submit" class="btn btn-primary"><?= h(tr('حفظ', 'Save')) ?></button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Delete Form -->
|
|
<form id="deleteForm" method="POST" action="expenses.php" style="display:none;">
|
|
<input type="hidden" name="action" value="delete">
|
|
<input type="hidden" name="id" id="delete_id">
|
|
</form>
|
|
|
|
<script>
|
|
function editItem(item) {
|
|
document.getElementById('edit_id').value = item.id;
|
|
document.getElementById('edit_expense_date').value = item.expense_date;
|
|
document.getElementById('edit_category_id').value = item.category_id;
|
|
document.getElementById('edit_amount').value = parseFloat(item.amount);
|
|
if(document.getElementById('edit_branch_code')) {
|
|
document.getElementById('edit_branch_code').value = item.branch_code || '';
|
|
}
|
|
document.getElementById('edit_description').value = item.description || '';
|
|
new bootstrap.Modal(document.getElementById('editModal')).show();
|
|
}
|
|
|
|
function deleteItem(id) {
|
|
Swal.fire({
|
|
title: '<?= h(tr('هل أنت متأكد؟', 'Are you sure?')) ?>',
|
|
text: '<?= h(tr('لن تتمكن من التراجع عن هذا!', "You won't be able to revert this!")) ?>',
|
|
icon: 'warning',
|
|
showCancelButton: true,
|
|
confirmButtonColor: '#dc3545',
|
|
cancelButtonColor: '#6c757d',
|
|
confirmButtonText: '<?= h(tr('نعم، احذف', 'Yes, delete it!')) ?>',
|
|
cancelButtonText: '<?= h(tr('إلغاء', 'Cancel')) ?>'
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
document.getElementById('delete_id').value = id;
|
|
document.getElementById('deleteForm').submit();
|
|
}
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<?php require __DIR__ . '/includes/footer.php'; ?>
|