Autosave: 20260321-173937

This commit is contained in:
Flatlogic Bot 2026-03-21 17:39:37 +00:00
parent a6e75b0397
commit 1cb1f89067
18 changed files with 2162 additions and 888 deletions

32
api/inventory.php Normal file
View File

@ -0,0 +1,32 @@
<?php
require_once __DIR__ . '/../db/config.php';
require_once __DIR__ . '/../helpers.php';
require_once __DIR__ . '/../includes/auth.php';
header('Content-Type: application/json');
if (!is_logged_in()) {
http_response_code(403);
echo json_encode(['error' => 'Unauthorized']);
exit;
}
$action = $_GET['action'] ?? '';
$db = db();
if ($action === 'get_batches') {
$item_id = $_GET['item_id'] ?? 0;
if (!$item_id) {
echo json_encode([]);
exit;
}
$stmt = $db->prepare("SELECT id, batch_number, quantity, expiry_date, cost_price FROM inventory_batches WHERE item_id = ? AND quantity > 0 ORDER BY expiry_date ASC");
$stmt->execute([$item_id]);
$batches = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode($batches);
exit;
}
echo json_encode(['error' => 'Invalid action']);

View File

@ -0,0 +1,52 @@
CREATE TABLE IF NOT EXISTS inventory_categories (
id INT AUTO_INCREMENT PRIMARY KEY,
name_en VARCHAR(255) NOT NULL,
name_ar VARCHAR(255) NOT NULL,
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS inventory_items (
id INT AUTO_INCREMENT PRIMARY KEY,
category_id INT,
name_en VARCHAR(255) NOT NULL,
name_ar VARCHAR(255) NOT NULL,
description TEXT,
sku VARCHAR(100) UNIQUE,
unit VARCHAR(50) DEFAULT 'piece',
min_level INT DEFAULT 10,
reorder_level INT DEFAULT 20,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (category_id) REFERENCES inventory_categories(id) ON DELETE SET NULL
);
CREATE TABLE IF NOT EXISTS inventory_batches (
id INT AUTO_INCREMENT PRIMARY KEY,
item_id INT NOT NULL,
batch_number VARCHAR(100),
expiry_date DATE,
quantity INT NOT NULL DEFAULT 0,
cost_price DECIMAL(10, 2) DEFAULT 0.00,
supplier_id INT,
received_date DATE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (item_id) REFERENCES inventory_items(id) ON DELETE CASCADE,
FOREIGN KEY (supplier_id) REFERENCES suppliers(id) ON DELETE SET NULL
);
CREATE TABLE IF NOT EXISTS inventory_transactions (
id INT AUTO_INCREMENT PRIMARY KEY,
item_id INT NOT NULL,
batch_id INT,
transaction_type ENUM('in', 'out', 'adjustment') NOT NULL,
quantity INT NOT NULL,
reference_type VARCHAR(50), -- 'purchase', 'consumption', 'manual_adjustment'
reference_id INT,
user_id INT,
transaction_date DATETIME DEFAULT CURRENT_TIMESTAMP,
notes TEXT,
FOREIGN KEY (item_id) REFERENCES inventory_items(id) ON DELETE CASCADE,
FOREIGN KEY (batch_id) REFERENCES inventory_batches(id) ON DELETE SET NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
);

View File

@ -113,29 +113,31 @@ $site_favicon = !empty($site_settings['company_favicon']) ? $site_settings['comp
<?php endif; ?>
</div>
<nav class="mt-3">
<?php if (has_permission('dashboard')): ?>
<a href="dashboard.php" class="sidebar-link <?php echo $section === 'dashboard' ? 'active' : ''; ?>"><i class="bi bi-speedometer2 me-2"></i> <?php echo __('dashboard'); ?></a>
<?php endif; ?>
<?php if (has_role('admin') || has_role('doctor') || has_role('nurse') || has_role('receptionist')): ?>
<?php if (has_permission('patients')): ?>
<a href="patients.php" class="sidebar-link <?php echo $section === 'patients' ? 'active' : ''; ?>"><i class="bi bi-people me-2"></i> <?php echo __('patients'); ?></a>
<?php endif; ?>
<?php if (has_role('admin') || has_role('doctor') || has_role('nurse')): ?>
<?php if (has_permission('visits')): ?>
<a href="visits.php" class="sidebar-link <?php echo $section === 'visits' ? 'active' : ''; ?>"><i class="bi bi-clipboard2-pulse me-2"></i> <?php echo __('visits'); ?></a>
<?php endif; ?>
<?php if (has_role('admin') || has_role('doctor') || has_role('receptionist')): ?>
<?php if (has_permission('appointments')): ?>
<a href="appointments.php" class="sidebar-link <?php echo $section === "appointments" ? "active" : ""; ?>"><i class="bi bi-calendar-event me-2"></i> <?php echo __("appointments"); ?></a>
<?php endif; ?>
<?php if (has_role('admin') || has_role('doctor') || has_role('nurse')): ?>
<?php if (has_permission('home_visits')): ?>
<a href="home_visits.php" class="sidebar-link <?php echo $section === 'home_visits' ? 'active' : ''; ?>"><i class="bi bi-house-heart me-2"></i> <?php echo __('home_visits'); ?></a>
<?php endif; ?>
<?php if (has_role('admin') || has_role('receptionist') || has_role('nurse')): ?>
<?php if (has_permission('queue')): ?>
<a href="queue.php" class="sidebar-link <?php echo $section === 'queue' ? 'active' : ''; ?>"><i class="bi bi-list-ol me-2"></i> <?php echo __('queue_management'); ?></a>
<?php endif; ?>
<?php if (has_role('admin') || has_role('laboratorial')): ?>
<?php if (has_permission('laboratory')): ?>
<a href="#labSubmenu" data-bs-toggle="collapse" class="sidebar-link <?php echo in_array($section, ['laboratory_tests', 'test_groups', 'laboratory_inquiries']) ? 'active' : ''; ?> d-flex justify-content-between align-items-center">
<span><i class="bi bi-prescription2 me-2"></i> <?php echo __('laboratory'); ?></span>
<i class="bi bi-chevron-down small"></i>
@ -149,7 +151,7 @@ $site_favicon = !empty($site_settings['company_favicon']) ? $site_settings['comp
</div>
<?php endif; ?>
<?php if (has_role('admin') || has_role('radiologic')): ?>
<?php if (has_permission('xray')): ?>
<!-- X-Ray Module -->
<a href="#xraySubmenu" data-bs-toggle="collapse" class="sidebar-link <?php echo in_array($section, ['xray_tests', 'xray_groups', 'xray_inquiries']) ? 'active' : ''; ?> d-flex justify-content-between align-items-center">
<span><i class="bi bi-x-diamond me-2"></i> <?php echo __('xray'); ?></span>
@ -164,7 +166,7 @@ $site_favicon = !empty($site_settings['company_favicon']) ? $site_settings['comp
</div>
<?php endif; ?>
<?php if (has_role('admin') || has_role('doctor')): ?>
<?php if (has_permission('pharmacy')): ?>
<!-- Pharmacy Module -->
<a href="#pharmacySubmenu" data-bs-toggle="collapse" class="sidebar-link <?php echo in_array($section, ['pharmacy_inventory', 'pharmacy_pos', 'pharmacy_sales', 'drugs', 'drugs_groups', 'suppliers', 'pharmacy_purchases', 'pharmacy_purchase_returns', 'pharmacy_alerts', 'pharmacy_reports']) ? 'active' : ''; ?> d-flex justify-content-between align-items-center">
<span><i class="bi bi-capsule me-2"></i> <?php echo __('pharmacy'); ?></span>
@ -187,21 +189,55 @@ $site_favicon = !empty($site_settings['company_favicon']) ? $site_settings['comp
</div>
<?php endif; ?>
<?php if (has_permission('inventory')): ?>
<!-- Stock Management Module -->
<a href="#inventorySubmenu" data-bs-toggle="collapse" class="sidebar-link <?php echo in_array($section, ['inventory_dashboard', 'inventory_items', 'inventory_categories', 'inventory_transactions', 'inventory_reports']) ? 'active' : ''; ?> d-flex justify-content-between align-items-center">
<span><i class="bi bi-box-seam me-2"></i> <?php echo __('stock_management'); ?></span>
<i class="bi bi-chevron-down small"></i>
</a>
<div class="collapse <?php echo in_array($section, ['inventory_dashboard', 'inventory_items', 'inventory_categories', 'inventory_transactions', 'inventory_reports']) ? 'show' : ''; ?>" id="inventorySubmenu">
<div class="sidebar-submenu">
<a href="inventory_dashboard.php" class="sidebar-link py-2 <?php echo $section === 'inventory_dashboard' ? 'active' : ''; ?>"><i class="bi bi-speedometer2 me-2"></i> <?php echo __('dashboard'); ?></a>
<a href="inventory_items.php" class="sidebar-link py-2 <?php echo $section === 'inventory_items' ? 'active' : ''; ?>"><i class="bi bi-boxes me-2"></i> <?php echo __('items'); ?></a>
<a href="inventory_categories.php" class="sidebar-link py-2 <?php echo $section === 'inventory_categories' ? 'active' : ''; ?>"><i class="bi bi-tags me-2"></i> <?php echo __('categories'); ?></a>
<a href="inventory_transactions.php" class="sidebar-link py-2 <?php echo $section === 'inventory_transactions' ? 'active' : ''; ?>"><i class="bi bi-arrow-left-right me-2"></i> <?php echo __('transactions'); ?></a>
<a href="inventory_reports.php" class="sidebar-link py-2 <?php echo $section === 'inventory_reports' ? 'active' : ''; ?>"><i class="bi bi-file-earmark-bar-graph me-2"></i> <?php echo __('reports'); ?></a>
</div>
</div>
<?php endif; ?>
<?php if (has_role('admin') || has_role('receptionist')): ?>
<?php if (has_permission('billing')): ?>
<a href="billing.php" class="sidebar-link <?php echo $section === 'billing' ? 'active' : ''; ?>"><i class="bi bi-receipt me-2"></i> <?php echo __('billing'); ?></a>
<?php endif; ?>
<?php if (has_permission('insurance')): ?>
<a href="insurance.php" class="sidebar-link <?php echo $section === 'insurance' ? 'active' : ''; ?>"><i class="bi bi-shield-check me-2"></i> <?php echo __('insurance'); ?></a>
<?php endif; ?>
<?php if (has_role('admin')): ?>
<?php if (has_permission('doctors')): ?>
<a href="doctors.php" class="sidebar-link <?php echo $section === 'doctors' ? 'active' : ''; ?>"><i class="bi bi-person-badge me-2"></i> <?php echo __('doctors'); ?></a>
<a href="doctor_holidays.php" class="sidebar-link <?php echo $section === 'doctor_holidays' ? 'active' : ''; ?>"><i class="bi bi-calendar-x me-2"></i> <?php echo __('doctor_holidays'); ?></a>
<a href="nurses.php" class="sidebar-link <?php echo $section === 'nurses' ? 'active' : ''; ?>"><i class="bi bi-person-heart me-2"></i> <?php echo __('nurses'); ?></a>
<?php endif; ?>
<?php if (has_permission('reports')): ?>
<a href="reports.php" class="sidebar-link <?php echo $section === 'reports' ? 'active' : ''; ?>"><i class="bi bi-bar-chart-line me-2"></i> <?php echo __('admin_reports'); ?></a>
<?php endif; ?>
<?php if (has_role('admin')): ?>
<?php if (has_permission('users')): ?>
<a href="#usersSubmenu" data-bs-toggle="collapse" class="sidebar-link <?php echo in_array($section, ['users', 'roles']) ? 'active' : ''; ?> d-flex justify-content-between align-items-center">
<span><i class="bi bi-people-fill me-2"></i> <?php echo __('users_management'); ?></span>
<i class="bi bi-chevron-down small"></i>
</a>
<div class="collapse <?php echo in_array($section, ['users', 'roles']) ? 'show' : ''; ?>" id="usersSubmenu">
<div class="sidebar-submenu">
<a href="users.php" class="sidebar-link py-2 <?php echo $section === 'users' ? 'active' : ''; ?>"><i class="bi bi-person me-2"></i> <?php echo __('users'); ?></a>
<a href="roles.php" class="sidebar-link py-2 <?php echo $section === 'roles' ? 'active' : ''; ?>"><i class="bi bi-shield-lock me-2"></i> <?php echo __('roles'); ?></a>
</div>
</div>
<?php endif; ?>
<?php if (has_permission('settings')): ?>
<a href="#settingsSubmenu" data-bs-toggle="collapse" class="sidebar-link <?php echo in_array($section, ['employees', 'positions', 'company_profile', 'cities', 'services', 'departments', 'queue_ads']) ? 'active' : ''; ?> d-flex justify-content-between align-items-center">
<span><i class="bi bi-gear me-2"></i> <?php echo __('settings'); ?></span>
<i class="bi bi-chevron-down small"></i>

View File

@ -0,0 +1,183 @@
<?php
// Handle Create/Update/Delete Logic
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['action'])) {
if ($_POST['action'] === 'add_category') {
$name_en = $_POST['name_en'] ?? '';
$name_ar = $_POST['name_ar'] ?? '';
$description = $_POST['description'] ?? '';
if ($name_en && $name_ar) {
$stmt = $db->prepare("INSERT INTO inventory_categories (name_en, name_ar, description) VALUES (?, ?, ?)");
$stmt->execute([$name_en, $name_ar, $description]);
$_SESSION['flash_message'] = '<div class="alert alert-success">' . __('category_added_successfully') . '</div>';
} else {
$_SESSION['flash_message'] = '<div class="alert alert-danger">' . __('fill_all_required_fields') . '</div>';
}
} elseif ($_POST['action'] === 'delete_category') {
$id = $_POST['id'] ?? 0;
// Check if used
$stmt = $db->prepare("SELECT COUNT(*) FROM inventory_items WHERE category_id = ?");
$stmt->execute([$id]);
if ($stmt->fetchColumn() > 0) {
$_SESSION['flash_message'] = '<div class="alert alert-danger">' . __('cannot_delete_category_in_use') . '</div>';
} else {
$stmt = $db->prepare("DELETE FROM inventory_categories WHERE id = ?");
$stmt->execute([$id]);
$_SESSION['flash_message'] = '<div class="alert alert-success">' . __('category_deleted_successfully') . '</div>';
}
} elseif ($_POST['action'] === 'edit_category') {
$id = $_POST['id'] ?? 0;
$name_en = $_POST['name_en'] ?? '';
$name_ar = $_POST['name_ar'] ?? '';
$description = $_POST['description'] ?? '';
if ($name_en && $name_ar) {
$stmt = $db->prepare("UPDATE inventory_categories SET name_en = ?, name_ar = ?, description = ? WHERE id = ?");
$stmt->execute([$name_en, $name_ar, $description, $id]);
$_SESSION['flash_message'] = '<div class="alert alert-success">' . __('category_updated_successfully') . '</div>';
}
}
// Redirect to avoid resubmission
header("Location: inventory_categories.php");
exit;
}
}
// Fetch Categories
$categories = $db->query("SELECT * FROM inventory_categories ORDER BY id DESC")->fetchAll(PDO::FETCH_ASSOC);
?>
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="mb-0 fw-bold text-dark"><?php echo __('inventory_categories'); ?></h2>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addCategoryModal">
<i class="bi bi-plus-lg me-1"></i> <?php echo __('add_category'); ?>
</button>
</div>
<div class="card shadow-sm border-0">
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead class="table-light">
<tr>
<th>#</th>
<th><?php echo __('name_en'); ?></th>
<th><?php echo __('name_ar'); ?></th>
<th><?php echo __('description'); ?></th>
<th class="text-end"><?php echo __('actions'); ?></th>
</tr>
</thead>
<tbody>
<?php if (empty($categories)): ?>
<tr>
<td colspan="5" class="text-center py-4 text-muted"><?php echo __('no_data_available'); ?></td>
</tr>
<?php else: ?>
<?php foreach ($categories as $cat): ?>
<tr>
<td><?php echo $cat['id']; ?></td>
<td><?php echo htmlspecialchars($cat['name_en']); ?></td>
<td><?php echo htmlspecialchars($cat['name_ar']); ?></td>
<td><?php echo htmlspecialchars($cat['description'] ?? ''); ?></td>
<td class="text-end">
<button class="btn btn-sm btn-outline-primary me-1"
onclick="editCategory(<?php echo htmlspecialchars(json_encode($cat)); ?>)">
<i class="bi bi-pencil"></i>
</button>
<form method="POST" class="d-inline" onsubmit="return confirm('<?php echo __('are_you_sure'); ?>');">
<input type="hidden" name="action" value="delete_category">
<input type="hidden" name="id" value="<?php echo $cat['id']; ?>">
<button type="submit" class="btn btn-sm btn-outline-danger">
<i class="bi bi-trash"></i>
</button>
</form>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
<!-- Add Category Modal -->
<div class="modal fade" id="addCategoryModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<form method="POST">
<div class="modal-header">
<h5 class="modal-title"><?php echo __('add_category'); ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<input type="hidden" name="action" value="add_category">
<div class="mb-3">
<label class="form-label"><?php echo __('name_en'); ?> <span class="text-danger">*</span></label>
<input type="text" name="name_en" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label"><?php echo __('name_ar'); ?> <span class="text-danger">*</span></label>
<input type="text" name="name_ar" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label"><?php echo __('description'); ?></label>
<textarea name="description" class="form-control" rows="3"></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo __('cancel'); ?></button>
<button type="submit" class="btn btn-primary"><?php echo __('save'); ?></button>
</div>
</form>
</div>
</div>
</div>
<!-- Edit Category Modal -->
<div class="modal fade" id="editCategoryModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<form method="POST">
<div class="modal-header">
<h5 class="modal-title"><?php echo __('edit_category'); ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<input type="hidden" name="action" value="edit_category">
<input type="hidden" name="id" id="edit_id">
<div class="mb-3">
<label class="form-label"><?php echo __('name_en'); ?> <span class="text-danger">*</span></label>
<input type="text" name="name_en" id="edit_name_en" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label"><?php echo __('name_ar'); ?> <span class="text-danger">*</span></label>
<input type="text" name="name_ar" id="edit_name_ar" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label"><?php echo __('description'); ?></label>
<textarea name="description" id="edit_description" class="form-control" rows="3"></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo __('cancel'); ?></button>
<button type="submit" class="btn btn-primary"><?php echo __('update'); ?></button>
</div>
</form>
</div>
</div>
</div>
<script>
function editCategory(cat) {
document.getElementById('edit_id').value = cat.id;
document.getElementById('edit_name_en').value = cat.name_en;
document.getElementById('edit_name_ar').value = cat.name_ar;
document.getElementById('edit_description').value = cat.description || '';
var myModal = new bootstrap.Modal(document.getElementById('editCategoryModal'));
myModal.show();
}
</script>

View File

@ -0,0 +1,137 @@
<?php
// Statistics
$total_items = $db->query("SELECT COUNT(*) FROM inventory_items WHERE is_active = 1")->fetchColumn();
$total_value_stmt = $db->query("SELECT SUM(quantity * cost_price) FROM inventory_batches");
$total_value = $total_value_stmt->fetchColumn() ?: 0;
// Low Stock
$low_stock_count = $db->query("
SELECT COUNT(*)
FROM inventory_items i
WHERE (SELECT SUM(quantity) FROM inventory_batches b WHERE b.item_id = i.id) <= i.min_level
")->fetchColumn();
// Expiring Soon (30 days)
$expiring_count = $db->query("
SELECT COUNT(*)
FROM inventory_batches
WHERE expiry_date BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 30 DAY)
AND quantity > 0
")->fetchColumn();
// Recent Transactions
$recent_transactions = $db->query("
SELECT t.*, i.name_en as item_name
FROM inventory_transactions t
JOIN inventory_items i ON t.item_id = i.id
ORDER BY t.transaction_date DESC
LIMIT 5
")->fetchAll(PDO::FETCH_ASSOC);
?>
<h2 class="mb-4 fw-bold text-dark"><?php echo __('inventory_dashboard'); ?></h2>
<div class="row g-4 mb-4">
<div class="col-md-3">
<div class="card shadow-sm border-0 h-100">
<div class="card-body text-center">
<div class="text-primary mb-2"><i class="bi bi-box-seam fs-1"></i></div>
<h5 class="card-title text-muted"><?php echo __('total_items'); ?></h5>
<h2 class="fw-bold"><?php echo number_format($total_items); ?></h2>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card shadow-sm border-0 h-100">
<div class="card-body text-center">
<div class="text-success mb-2"><i class="bi bi-cash-stack fs-1"></i></div>
<h5 class="card-title text-muted"><?php echo __('total_value'); ?></h5>
<h2 class="fw-bold"><?php echo number_format($total_value, 2); ?></h2>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card shadow-sm border-0 h-100">
<div class="card-body text-center">
<div class="text-warning mb-2"><i class="bi bi-exclamation-triangle fs-1"></i></div>
<h5 class="card-title text-muted"><?php echo __('low_stock_items'); ?></h5>
<h2 class="fw-bold"><?php echo number_format($low_stock_count); ?></h2>
<a href="inventory_items.php" class="small text-decoration-none stretched-link"><?php echo __('view_details'); ?></a>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card shadow-sm border-0 h-100">
<div class="card-body text-center">
<div class="text-danger mb-2"><i class="bi bi-calendar-x fs-1"></i></div>
<h5 class="card-title text-muted"><?php echo __('expiring_soon'); ?></h5>
<h2 class="fw-bold"><?php echo number_format($expiring_count); ?></h2>
<a href="inventory_reports.php?report=expiry" class="small text-decoration-none stretched-link"><?php echo __('view_details'); ?></a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8">
<div class="card shadow-sm border-0">
<div class="card-header bg-white">
<h5 class="mb-0 fw-bold text-dark"><?php echo __('recent_transactions'); ?></h5>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover mb-0 align-middle">
<thead class="table-light">
<tr>
<th><?php echo __('date'); ?></th>
<th><?php echo __('item'); ?></th>
<th><?php echo __('type'); ?></th>
<th><?php echo __('qty'); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($recent_transactions as $t): ?>
<tr>
<td><?php echo date('M d, H:i', strtotime($t['transaction_date'])); ?></td>
<td><?php echo htmlspecialchars($t['item_name']); ?></td>
<td>
<?php if ($t['transaction_type'] === 'in'): ?>
<span class="badge bg-success-subtle text-success">IN</span>
<?php else: ?>
<span class="badge bg-danger-subtle text-danger">OUT</span>
<?php endif; ?>
</td>
<td><?php echo $t['quantity']; ?></td>
</tr>
<?php endforeach; ?>
<?php if (empty($recent_transactions)): ?>
<tr><td colspan="4" class="text-center text-muted py-3"><?php echo __('no_recent_transactions'); ?></td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
<div class="card-footer bg-white text-center">
<a href="inventory_transactions.php" class="text-decoration-none"><?php echo __('view_all_transactions'); ?></a>
</div>
</div>
</div>
<div class="col-md-4">
<!-- Quick Actions -->
<div class="card shadow-sm border-0 mb-4">
<div class="card-header bg-white">
<h5 class="mb-0 fw-bold text-dark"><?php echo __('quick_actions'); ?></h5>
</div>
<div class="card-body">
<div class="d-grid gap-2">
<a href="inventory_items.php" class="btn btn-outline-primary"><i class="bi bi-plus-lg me-2"></i> <?php echo __('add_new_item'); ?></a>
<a href="inventory_transactions.php" class="btn btn-outline-success"><i class="bi bi-box-arrow-in-down me-2"></i> <?php echo __('receive_stock'); ?></a>
<a href="inventory_transactions.php" class="btn btn-outline-danger"><i class="bi bi-box-arrow-up me-2"></i> <?php echo __('issue_stock'); ?></a>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,282 @@
<?php
// Handle Actions
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['action'])) {
if ($_POST['action'] === 'add_item') {
$name_en = $_POST['name_en'] ?? '';
$name_ar = $_POST['name_ar'] ?? '';
$category_id = $_POST['category_id'] ?? null;
$sku = $_POST['sku'] ?? '';
$unit = $_POST['unit'] ?? 'piece';
$min_level = $_POST['min_level'] ?? 10;
$reorder_level = $_POST['reorder_level'] ?? 20;
$description = $_POST['description'] ?? '';
if ($name_en && $category_id) {
try {
$stmt = $db->prepare("INSERT INTO inventory_items (name_en, name_ar, category_id, sku, unit, min_level, reorder_level, description) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([$name_en, $name_ar, $category_id, $sku, $unit, $min_level, $reorder_level, $description]);
$_SESSION['flash_message'] = '<div class="alert alert-success">' . __('item_added_successfully') . '</div>';
} catch (PDOException $e) {
$_SESSION['flash_message'] = '<div class="alert alert-danger">' . __('error_adding_item') . ': ' . $e->getMessage() . '</div>';
}
} else {
$_SESSION['flash_message'] = '<div class="alert alert-danger">' . __('fill_all_required_fields') . '</div>';
}
} elseif ($_POST['action'] === 'edit_item') {
$id = $_POST['id'] ?? 0;
$name_en = $_POST['name_en'] ?? '';
$name_ar = $_POST['name_ar'] ?? '';
$category_id = $_POST['category_id'] ?? null;
$sku = $_POST['sku'] ?? '';
$unit = $_POST['unit'] ?? 'piece';
$min_level = $_POST['min_level'] ?? 10;
$reorder_level = $_POST['reorder_level'] ?? 20;
$description = $_POST['description'] ?? '';
if ($name_en && $category_id) {
try {
$stmt = $db->prepare("UPDATE inventory_items SET name_en = ?, name_ar = ?, category_id = ?, sku = ?, unit = ?, min_level = ?, reorder_level = ?, description = ? WHERE id = ?");
$stmt->execute([$name_en, $name_ar, $category_id, $sku, $unit, $min_level, $reorder_level, $description, $id]);
$_SESSION['flash_message'] = '<div class="alert alert-success">' . __('item_updated_successfully') . '</div>';
} catch (PDOException $e) {
$_SESSION['flash_message'] = '<div class="alert alert-danger">' . __('error_updating_item') . ': ' . $e->getMessage() . '</div>';
}
}
} elseif ($_POST['action'] === 'delete_item') {
$id = $_POST['id'] ?? 0;
// Check usage
$stmt = $db->prepare("SELECT COUNT(*) FROM inventory_batches WHERE item_id = ? AND quantity > 0");
$stmt->execute([$id]);
if ($stmt->fetchColumn() > 0) {
$_SESSION['flash_message'] = '<div class="alert alert-danger">' . __('cannot_delete_item_with_stock') . '</div>';
} else {
$stmt = $db->prepare("DELETE FROM inventory_items WHERE id = ?");
$stmt->execute([$id]);
$_SESSION['flash_message'] = '<div class="alert alert-success">' . __('item_deleted_successfully') . '</div>';
}
}
header("Location: inventory_items.php");
exit;
}
}
// Fetch Items with Stock
$items = $db->query("
SELECT i.*, c.name_en as category_name,
COALESCE((SELECT SUM(quantity) FROM inventory_batches b WHERE b.item_id = i.id), 0) as current_stock
FROM inventory_items i
LEFT JOIN inventory_categories c ON i.category_id = c.id
ORDER BY i.name_en ASC
")->fetchAll(PDO::FETCH_ASSOC);
// Fetch Categories for Dropdown
$categories = $db->query("SELECT * FROM inventory_categories ORDER BY name_en ASC")->fetchAll(PDO::FETCH_ASSOC);
?>
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="mb-0 fw-bold text-dark"><?php echo __('inventory_items'); ?></h2>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addItemModal">
<i class="bi bi-plus-lg me-1"></i> <?php echo __('add_item'); ?>
</button>
</div>
<div class="card shadow-sm border-0">
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead class="table-light">
<tr>
<th><?php echo __('sku'); ?></th>
<th><?php echo __('item_name'); ?></th>
<th><?php echo __('category'); ?></th>
<th><?php echo __('unit'); ?></th>
<th><?php echo __('min_level'); ?></th>
<th><?php echo __('current_stock'); ?></th>
<th class="text-end"><?php echo __('actions'); ?></th>
</tr>
</thead>
<tbody>
<?php if (empty($items)): ?>
<tr>
<td colspan="7" class="text-center py-4 text-muted"><?php echo __('no_items_found'); ?></td>
</tr>
<?php else: ?>
<?php foreach ($items as $item): ?>
<tr class="<?php echo ($item['current_stock'] <= $item['min_level']) ? 'table-warning' : ''; ?>">
<td><span class="badge bg-secondary"><?php echo htmlspecialchars($item['sku'] ?? '-'); ?></span></td>
<td>
<div class="fw-bold"><?php echo htmlspecialchars($item['name_en']); ?></div>
<small class="text-muted"><?php echo htmlspecialchars($item['name_ar']); ?></small>
</td>
<td><?php echo htmlspecialchars($item['category_name'] ?? '-'); ?></td>
<td><?php echo htmlspecialchars($item['unit']); ?></td>
<td><?php echo $item['min_level']; ?></td>
<td>
<?php if ($item['current_stock'] == 0): ?>
<span class="badge bg-danger"><?php echo __('out_of_stock'); ?></span>
<?php elseif ($item['current_stock'] <= $item['min_level']): ?>
<span class="badge bg-warning text-dark"><?php echo $item['current_stock']; ?> (Low)</span>
<?php else: ?>
<span class="badge bg-success"><?php echo $item['current_stock']; ?></span>
<?php endif; ?>
</td>
<td class="text-end">
<button class="btn btn-sm btn-outline-primary me-1"
onclick='editItem(<?php echo json_encode($item, JSON_HEX_APOS | JSON_HEX_QUOT); ?>)'>
<i class="bi bi-pencil"></i>
</button>
<form method="POST" class="d-inline" onsubmit="return confirm('<?php echo __('are_you_sure'); ?>');">
<input type="hidden" name="action" value="delete_item">
<input type="hidden" name="id" value="<?php echo $item['id']; ?>">
<button type="submit" class="btn btn-sm btn-outline-danger">
<i class="bi bi-trash"></i>
</button>
</form>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
<!-- Add Item Modal -->
<div class="modal fade" id="addItemModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<form method="POST">
<div class="modal-header">
<h5 class="modal-title"><?php echo __('add_item'); ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<input type="hidden" name="action" value="add_item">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label"><?php echo __('name_en'); ?> <span class="text-danger">*</span></label>
<input type="text" name="name_en" class="form-control" required>
</div>
<div class="col-md-6">
<label class="form-label"><?php echo __('name_ar'); ?></label>
<input type="text" name="name_ar" class="form-control">
</div>
<div class="col-md-6">
<label class="form-label"><?php echo __('category'); ?> <span class="text-danger">*</span></label>
<select name="category_id" class="form-select" required>
<option value=""><?php echo __('select_category'); ?></option>
<?php foreach ($categories as $cat): ?>
<option value="<?php echo $cat['id']; ?>"><?php echo htmlspecialchars($cat['name_en']); ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-6">
<label class="form-label"><?php echo __('sku'); ?></label>
<input type="text" name="sku" class="form-control">
</div>
<div class="col-md-4">
<label class="form-label"><?php echo __('unit'); ?></label>
<input type="text" name="unit" class="form-control" value="piece">
</div>
<div class="col-md-4">
<label class="form-label"><?php echo __('min_level'); ?></label>
<input type="number" name="min_level" class="form-control" value="10">
</div>
<div class="col-md-4">
<label class="form-label"><?php echo __('reorder_level'); ?></label>
<input type="number" name="reorder_level" class="form-control" value="20">
</div>
<div class="col-12">
<label class="form-label"><?php echo __('description'); ?></label>
<textarea name="description" class="form-control" rows="2"></textarea>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo __('cancel'); ?></button>
<button type="submit" class="btn btn-primary"><?php echo __('save'); ?></button>
</div>
</form>
</div>
</div>
</div>
<!-- Edit Item Modal -->
<div class="modal fade" id="editItemModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<form method="POST">
<div class="modal-header">
<h5 class="modal-title"><?php echo __('edit_item'); ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<input type="hidden" name="action" value="edit_item">
<input type="hidden" name="id" id="edit_id">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label"><?php echo __('name_en'); ?> <span class="text-danger">*</span></label>
<input type="text" name="name_en" id="edit_name_en" class="form-control" required>
</div>
<div class="col-md-6">
<label class="form-label"><?php echo __('name_ar'); ?></label>
<input type="text" name="name_ar" id="edit_name_ar" class="form-control">
</div>
<div class="col-md-6">
<label class="form-label"><?php echo __('category'); ?> <span class="text-danger">*</span></label>
<select name="category_id" id="edit_category_id" class="form-select" required>
<option value=""><?php echo __('select_category'); ?></option>
<?php foreach ($categories as $cat): ?>
<option value="<?php echo $cat['id']; ?>"><?php echo htmlspecialchars($cat['name_en']); ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-6">
<label class="form-label"><?php echo __('sku'); ?></label>
<input type="text" name="sku" id="edit_sku" class="form-control">
</div>
<div class="col-md-4">
<label class="form-label"><?php echo __('unit'); ?></label>
<input type="text" name="unit" id="edit_unit" class="form-control">
</div>
<div class="col-md-4">
<label class="form-label"><?php echo __('min_level'); ?></label>
<input type="number" name="min_level" id="edit_min_level" class="form-control">
</div>
<div class="col-md-4">
<label class="form-label"><?php echo __('reorder_level'); ?></label>
<input type="number" name="reorder_level" id="edit_reorder_level" class="form-control">
</div>
<div class="col-12">
<label class="form-label"><?php echo __('description'); ?></label>
<textarea name="description" id="edit_description" class="form-control" rows="2"></textarea>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo __('cancel'); ?></button>
<button type="submit" class="btn btn-primary"><?php echo __('update'); ?></button>
</div>
</form>
</div>
</div>
</div>
<script>
function editItem(item) {
document.getElementById('edit_id').value = item.id;
document.getElementById('edit_name_en').value = item.name_en;
document.getElementById('edit_name_ar').value = item.name_ar;
document.getElementById('edit_category_id').value = item.category_id;
document.getElementById('edit_sku').value = item.sku || '';
document.getElementById('edit_unit').value = item.unit || 'piece';
document.getElementById('edit_min_level').value = item.min_level;
document.getElementById('edit_reorder_level').value = item.reorder_level;
document.getElementById('edit_description').value = item.description || '';
var myModal = new bootstrap.Modal(document.getElementById('editItemModal'));
myModal.show();
}
</script>

View File

@ -0,0 +1,111 @@
<?php
$report_type = $_GET['report'] ?? 'low_stock';
// Data Fetching based on report type
$data = [];
$columns = [];
if ($report_type === 'low_stock') {
$title = __('low_stock_report');
$columns = ['item_name', 'sku', 'min_level', 'current_stock', 'status'];
$data = $db->query("
SELECT i.name_en as item_name, i.sku, i.min_level,
COALESCE((SELECT SUM(quantity) FROM inventory_batches b WHERE b.item_id = i.id), 0) as current_stock
FROM inventory_items i
HAVING current_stock <= min_level
ORDER BY current_stock ASC
")->fetchAll(PDO::FETCH_ASSOC);
} elseif ($report_type === 'expiry') {
$title = __('expiry_report');
$columns = ['item_name', 'batch_number', 'expiry_date', 'quantity', 'days_remaining'];
$data = $db->query("
SELECT i.name_en as item_name, b.batch_number, b.expiry_date, b.quantity,
DATEDIFF(b.expiry_date, CURDATE()) as days_remaining
FROM inventory_batches b
JOIN inventory_items i ON b.item_id = i.id
WHERE b.quantity > 0 AND b.expiry_date IS NOT NULL
AND b.expiry_date <= DATE_ADD(CURDATE(), INTERVAL 90 DAY)
ORDER BY b.expiry_date ASC
")->fetchAll(PDO::FETCH_ASSOC);
} elseif ($report_type === 'valuation') {
$title = __('stock_valuation_report');
$columns = ['item_name', 'total_quantity', 'avg_cost', 'total_value'];
$data = $db->query("
SELECT i.name_en as item_name,
SUM(b.quantity) as total_quantity,
AVG(b.cost_price) as avg_cost,
SUM(b.quantity * b.cost_price) as total_value
FROM inventory_batches b
JOIN inventory_items i ON b.item_id = i.id
WHERE b.quantity > 0
GROUP BY i.id
ORDER BY total_value DESC
")->fetchAll(PDO::FETCH_ASSOC);
}
?>
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="mb-0 fw-bold text-dark"><?php echo __('inventory_reports'); ?></h2>
<div class="btn-group">
<a href="?report=low_stock" class="btn btn-outline-primary <?php echo $report_type === 'low_stock' ? 'active' : ''; ?>"><?php echo __('low_stock'); ?></a>
<a href="?report=expiry" class="btn btn-outline-primary <?php echo $report_type === 'expiry' ? 'active' : ''; ?>"><?php echo __('expiry_dates'); ?></a>
<a href="?report=valuation" class="btn btn-outline-primary <?php echo $report_type === 'valuation' ? 'active' : ''; ?>"><?php echo __('valuation'); ?></a>
</div>
</div>
<div class="card shadow-sm border-0">
<div class="card-header bg-white">
<h5 class="mb-0 fw-bold"><?php echo htmlspecialchars($title); ?></h5>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead class="table-light">
<tr>
<?php foreach ($columns as $col): ?>
<th><?php echo __(str_replace('_', ' ', $col)); ?></th>
<?php endforeach; ?>
</tr>
</thead>
<tbody>
<?php if (empty($data)): ?>
<tr>
<td colspan="<?php echo count($columns); ?>" class="text-center py-4 text-muted"><?php echo __('no_data_available'); ?></td>
</tr>
<?php else: ?>
<?php foreach ($data as $row): ?>
<tr>
<?php foreach ($columns as $col): ?>
<td>
<?php
if ($col === 'current_stock' || $col === 'total_quantity') {
echo number_format($row[$col]);
} elseif ($col === 'total_value' || $col === 'avg_cost') {
echo formatCurrency($row[$col]);
} elseif ($col === 'status') {
if ($row['current_stock'] == 0) echo '<span class="badge bg-danger">Out of Stock</span>';
else echo '<span class="badge bg-warning text-dark">Low Stock</span>';
} elseif ($col === 'days_remaining') {
$days = $row['days_remaining'];
if ($days < 0) echo '<span class="badge bg-danger">Expired</span>';
elseif ($days < 30) echo '<span class="badge bg-warning text-dark">' . $days . ' days</span>';
else echo '<span class="badge bg-info">' . $days . ' days</span>';
} else {
echo htmlspecialchars($row[$col]);
}
?>
</td>
<?php endforeach; ?>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
<div class="mt-3 text-end">
<button onclick="window.print()" class="btn btn-outline-secondary"><i class="bi bi-printer me-2"></i> <?php echo __('print_report'); ?></button>
</div>
</div>
</div>

View File

@ -0,0 +1,316 @@
<?php
// Handle Create Transaction
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['action']) && $_POST['action'] === 'add_transaction') {
$type = $_POST['type'] ?? 'in';
$item_id = $_POST['item_id'] ?? 0;
$quantity = (int)($_POST['quantity'] ?? 0);
$notes = $_POST['notes'] ?? '';
$reference_type = $_POST['reference_type'] ?? 'manual_adjustment';
$reference_id = 0; // Or pass from somewhere
if (!$item_id || $quantity <= 0) {
$_SESSION['flash_message'] = '<div class="alert alert-danger">' . __('fill_all_required_fields') . '</div>';
} else {
try {
$db->beginTransaction();
if ($type === 'in') {
// Create New Batch
$batch_number = $_POST['batch_number'] ?? date('YmdHis');
$expiry_date = !empty($_POST['expiry_date']) ? $_POST['expiry_date'] : null;
$cost_price = $_POST['cost_price'] ?? 0;
$supplier_id = !empty($_POST['supplier_id']) ? $_POST['supplier_id'] : null;
$stmt = $db->prepare("INSERT INTO inventory_batches (item_id, batch_number, expiry_date, quantity, cost_price, supplier_id, received_date) VALUES (?, ?, ?, ?, ?, ?, NOW())");
$stmt->execute([$item_id, $batch_number, $expiry_date, $quantity, $cost_price, $supplier_id]);
$batch_id = $db->lastInsertId();
// Create Transaction Record
$stmt = $db->prepare("INSERT INTO inventory_transactions (item_id, batch_id, transaction_type, quantity, reference_type, reference_id, user_id, notes) VALUES (?, ?, 'in', ?, ?, ?, ?, ?)");
$stmt->execute([$item_id, $batch_id, $quantity, $reference_type, $reference_id, $_SESSION['user_id'], $notes]);
} elseif ($type === 'out') {
// Deduct from Batch
$batch_id = $_POST['batch_id'] ?? 0;
// Check availability
$stmt = $db->prepare("SELECT quantity FROM inventory_batches WHERE id = ? FOR UPDATE");
$stmt->execute([$batch_id]);
$current_qty = $stmt->fetchColumn();
if ($current_qty < $quantity) {
throw new Exception(__('insufficient_stock_in_batch'));
}
// Update Batch
$stmt = $db->prepare("UPDATE inventory_batches SET quantity = quantity - ? WHERE id = ?");
$stmt->execute([$quantity, $batch_id]);
// Create Transaction Record
$stmt = $db->prepare("INSERT INTO inventory_transactions (item_id, batch_id, transaction_type, quantity, reference_type, reference_id, user_id, notes) VALUES (?, ?, 'out', ?, ?, ?, ?, ?)");
$stmt->execute([$item_id, $batch_id, $quantity, $reference_type, $reference_id, $_SESSION['user_id'], $notes]);
}
$db->commit();
$_SESSION['flash_message'] = '<div class="alert alert-success">' . __('transaction_recorded_successfully') . '</div>';
} catch (Exception $e) {
$db->rollBack();
$_SESSION['flash_message'] = '<div class="alert alert-danger">' . __('error_recording_transaction') . ': ' . $e->getMessage() . '</div>';
}
}
header("Location: inventory_transactions.php");
exit;
}
}
// Fetch Transactions
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$per_page = 20;
$offset = ($page - 1) * $per_page;
$stmt = $db->query("SELECT COUNT(*) FROM inventory_transactions");
$total_records = $stmt->fetchColumn();
$total_pages = ceil($total_records / $per_page);
$transactions = $db->query("
SELECT t.*, i.name_en as item_name, i.sku, b.batch_number, u.name as user_name
FROM inventory_transactions t
JOIN inventory_items i ON t.item_id = i.id
LEFT JOIN inventory_batches b ON t.batch_id = b.id
LEFT JOIN users u ON t.user_id = u.id
ORDER BY t.transaction_date DESC
LIMIT $per_page OFFSET $offset
")->fetchAll(PDO::FETCH_ASSOC);
// Fetch Items for Dropdown
$items = $db->query("SELECT id, name_en, sku FROM inventory_items WHERE is_active = 1 ORDER BY name_en ASC")->fetchAll(PDO::FETCH_ASSOC);
// Fetch Suppliers
$suppliers = $db->query("SELECT id, name_en FROM suppliers ORDER BY name_en ASC")->fetchAll(PDO::FETCH_ASSOC);
?>
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="mb-0 fw-bold text-dark"><?php echo __('inventory_transactions'); ?></h2>
<button type="button" class="btn btn-primary" onclick="openNewTransactionModal()">
<i class="bi bi-plus-lg me-1"></i> <?php echo __('new_transaction'); ?>
</button>
</div>
<div class="card shadow-sm border-0">
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead class="table-light">
<tr>
<th><?php echo __('date'); ?></th>
<th><?php echo __('type'); ?></th>
<th><?php echo __('item'); ?></th>
<th><?php echo __('batch'); ?></th>
<th><?php echo __('quantity'); ?></th>
<th><?php echo __('user'); ?></th>
<th><?php echo __('notes'); ?></th>
</tr>
</thead>
<tbody>
<?php if (empty($transactions)): ?>
<tr>
<td colspan="7" class="text-center py-4 text-muted"><?php echo __('no_transactions_found'); ?></td>
</tr>
<?php else: ?>
<?php foreach ($transactions as $t): ?>
<tr>
<td><?php echo date('Y-m-d H:i', strtotime($t['transaction_date'])); ?></td>
<td>
<?php if ($t['transaction_type'] === 'in'): ?>
<span class="badge bg-success"><i class="bi bi-arrow-down"></i> <?php echo __('in'); ?></span>
<?php elseif ($t['transaction_type'] === 'out'): ?>
<span class="badge bg-danger"><i class="bi bi-arrow-up"></i> <?php echo __('out'); ?></span>
<?php else: ?>
<span class="badge bg-warning text-dark"><?php echo __('adjustment'); ?></span>
<?php endif; ?>
</td>
<td>
<div class="fw-bold"><?php echo htmlspecialchars($t['item_name']); ?></div>
<small class="text-muted"><?php echo htmlspecialchars($t['sku']); ?></small>
</td>
<td><?php echo htmlspecialchars($t['batch_number'] ?? '-'); ?></td>
<td class="fw-bold"><?php echo $t['quantity']; ?></td>
<td><?php echo htmlspecialchars($t['user_name'] ?? 'System'); ?></td>
<td><?php echo htmlspecialchars($t['notes'] ?? ''); ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
<!-- Pagination -->
<?php if ($total_pages > 1): ?>
<nav class="mt-4">
<ul class="pagination justify-content-center">
<?php for ($i = 1; $i <= $total_pages; $i++): ?>
<li class="page-item <?php echo $i === $page ? 'active' : ''; ?>">
<a class="page-link" href="?page=<?php echo $i; ?>"><?php echo $i; ?></a>
</li>
<?php endfor; ?>
</ul>
</nav>
<?php endif; ?>
</div>
</div>
<!-- New Transaction Modal -->
<div class="modal fade" id="transactionModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<form method="POST">
<div class="modal-header">
<h5 class="modal-title"><?php echo __('new_transaction'); ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<input type="hidden" name="action" value="add_transaction">
<div class="mb-3">
<label class="form-label"><?php echo __('transaction_type'); ?></label>
<div class="btn-group w-100" role="group">
<input type="radio" class="btn-check" name="type" id="type_in" value="in" checked onchange="toggleType()">
<label class="btn btn-outline-success" for="type_in"><?php echo __('stock_in_purchase'); ?></label>
<input type="radio" class="btn-check" name="type" id="type_out" value="out" onchange="toggleType()">
<label class="btn btn-outline-danger" for="type_out"><?php echo __('stock_out_consumption'); ?></label>
</div>
</div>
<div class="mb-3">
<label class="form-label"><?php echo __('item'); ?> <span class="text-danger">*</span></label>
<select name="item_id" id="item_select" class="form-select" required onchange="fetchBatches()">
<option value=""><?php echo __('select_item'); ?></option>
<?php foreach ($items as $item): ?>
<option value="<?php echo $item['id']; ?>"><?php echo htmlspecialchars($item['name_en'] . ' (' . ($item['sku'] ?? '-') . ')'); ?></option>
<?php endforeach; ?>
</select>
</div>
<!-- Fields for IN -->
<div id="in_fields">
<div class="row g-3 mb-3">
<div class="col-md-6">
<label class="form-label"><?php echo __('batch_number'); ?></label>
<input type="text" name="batch_number" class="form-control" placeholder="Leave empty for auto-generated">
</div>
<div class="col-md-6">
<label class="form-label"><?php echo __('expiry_date'); ?></label>
<input type="date" name="expiry_date" class="form-control">
</div>
<div class="col-md-6">
<label class="form-label"><?php echo __('cost_price'); ?></label>
<input type="number" step="0.01" name="cost_price" class="form-control">
</div>
<div class="col-md-6">
<label class="form-label"><?php echo __('supplier'); ?></label>
<select name="supplier_id" class="form-select">
<option value=""><?php echo __('select_supplier'); ?></option>
<?php foreach ($suppliers as $sup): ?>
<option value="<?php echo $sup['id']; ?>"><?php echo htmlspecialchars($sup['name_en']); ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
</div>
<!-- Fields for OUT -->
<div id="out_fields" style="display: none;">
<div class="mb-3">
<label class="form-label"><?php echo __('select_batch_to_deduct_from'); ?> <span class="text-danger">*</span></label>
<select name="batch_id" id="batch_select" class="form-select">
<option value=""><?php echo __('select_item_first'); ?></option>
</select>
<div class="form-text text-muted" id="batch_info"></div>
</div>
</div>
<div class="mb-3">
<label class="form-label"><?php echo __('quantity'); ?> <span class="text-danger">*</span></label>
<input type="number" name="quantity" class="form-control" min="1" required>
</div>
<div class="mb-3">
<label class="form-label"><?php echo __('notes'); ?></label>
<textarea name="notes" class="form-control" rows="2"></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo __('cancel'); ?></button>
<button type="submit" class="btn btn-primary"><?php echo __('save_transaction'); ?></button>
</div>
</form>
</div>
</div>
</div>
<script>
function openNewTransactionModal() {
var myModal = new bootstrap.Modal(document.getElementById('transactionModal'));
myModal.show();
}
function toggleType() {
const isOut = document.getElementById('type_out').checked;
document.getElementById('in_fields').style.display = isOut ? 'none' : 'block';
document.getElementById('out_fields').style.display = isOut ? 'block' : 'none';
// Toggle required attribute for batch_select
document.getElementById('batch_select').required = isOut;
// Clear batch selection if switching
if (isOut) {
fetchBatches();
}
}
function fetchBatches() {
const itemId = document.getElementById('item_select').value;
const batchSelect = document.getElementById('batch_select');
const isOut = document.getElementById('type_out').checked;
if (!isOut || !itemId) return;
batchSelect.innerHTML = '<option value="">Loading...</option>';
fetch('api/inventory.php?action=get_batches&item_id=' + itemId)
.then(response => response.json())
.then(data => {
batchSelect.innerHTML = '<option value="">Select Batch</option>';
if (data.length === 0) {
batchSelect.innerHTML = '<option value="">No stock available</option>';
}
data.forEach(batch => {
const option = document.createElement('option');
option.value = batch.id;
option.text = `Batch: ${batch.batch_number} | Exp: ${batch.expiry_date || 'N/A'} | Qty: ${batch.quantity}`;
batchSelect.add(option);
});
})
.catch(err => {
console.error('Error fetching batches:', err);
batchSelect.innerHTML = '<option value="">Error loading batches</option>';
});
}
// Initial setup
document.addEventListener('DOMContentLoaded', function() {
// Initialize Select2 if available
if (typeof $().select2 === 'function') {
$('#item_select').select2({
dropdownParent: $('#transactionModal'),
theme: 'bootstrap-5'
});
$('#item_select').on('select2:select', function (e) {
fetchBatches();
});
}
});
</script>

256
includes/pages/roles.php Normal file
View File

@ -0,0 +1,256 @@
<?php
// Handle Actions
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['action']) && $_POST['action'] === 'update_permissions') {
try {
$role_id = $_POST['role_id'];
$perms = isset($_POST['permissions']) ? $_POST['permissions'] : [];
// Encode as JSON
$perms_json = json_encode($perms);
$stmt = $db->prepare("UPDATE roles SET permissions = ? WHERE id = ?");
$stmt->execute([$perms_json, $role_id]);
$_SESSION['flash_message'] = __('permissions_updated');
} catch (Exception $e) {
$_SESSION['flash_message'] = "Error: " . $e->getMessage();
}
header("Location: roles.php");
exit;
}
if (isset($_POST['action']) && $_POST['action'] === 'add_role') {
try {
$name = trim($_POST['name']);
$perms = isset($_POST['permissions']) ? $_POST['permissions'] : [];
if (empty($name)) {
throw new Exception("Role name is required");
}
// Generate slug
$slug = strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '-', $name)));
// Check if slug exists
$stmt = $db->prepare("SELECT COUNT(*) FROM roles WHERE slug = ?");
$stmt->execute([$slug]);
if ($stmt->fetchColumn() > 0) {
throw new Exception("Role with this name already exists");
}
// Encode permissions
$perms_json = json_encode($perms);
$stmt = $db->prepare("INSERT INTO roles (name, slug, permissions) VALUES (?, ?, ?)");
$stmt->execute([$name, $slug, $perms_json]);
$_SESSION['flash_message'] = "Role added successfully";
} catch (Exception $e) {
$_SESSION['flash_message'] = "Error: " . $e->getMessage();
}
header("Location: roles.php");
exit;
}
}
// Fetch Roles
$stmt = $db->query("SELECT * FROM roles ORDER BY name ASC");
$roles = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Define Available Permissions
$available_permissions = [
'dashboard',
'patients',
'visits',
'appointments',
'home_visits',
'queue',
'laboratory',
'xray',
'pharmacy',
'billing',
'insurance',
'doctors',
'reports',
'settings',
'users'
];
?>
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="fw-bold text-dark mb-0"><?php echo __('roles_permissions'); ?></h2>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addRoleModal">
<i class="bi bi-plus-lg"></i> <?php echo __('add_role'); ?>
</button>
</div>
<div class="card shadow-sm">
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead class="table-light">
<tr>
<th>ID</th>
<th><?php echo __('role'); ?></th>
<th><?php echo __('permissions'); ?></th>
<th><?php echo __('actions'); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($roles as $role): ?>
<tr>
<td><?php echo $role['id']; ?></td>
<td><span class="badge bg-primary fs-6"><?php echo htmlspecialchars($role['name']); ?></span></td>
<td>
<?php
$role_perms = json_decode($role['permissions'], true) ?? [];
if (in_array('*', $role_perms)) {
echo '<span class="badge bg-success">All Access</span>';
} else {
$count = count($role_perms);
echo $count > 0 ? $count . ' modules' : 'None';
}
?>
</td>
<td>
<?php if ($role['slug'] !== 'admin'): ?>
<button class="btn btn-sm btn-outline-primary" onclick='editPermissions(<?php echo json_encode($role); ?>)'>
<i class="bi bi-shield-lock"></i> <?php echo __('permissions'); ?>
</button>
<?php else: ?>
<span class="text-muted"><i class="bi bi-lock-fill"></i> Full Access</span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Add Role Modal -->
<div class="modal fade" id="addRoleModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<form method="POST" class="modal-content">
<input type="hidden" name="action" value="add_role">
<div class="modal-header">
<h5 class="modal-title"><?php echo __('add_role'); ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label for="roleName" class="form-label"><?php echo __('role_name'); ?></label>
<input type="text" class="form-control" id="roleName" name="name" required placeholder="e.g. Senior Nurse">
</div>
<h6 class="mt-4 mb-3"><?php echo __('permissions'); ?></h6>
<div class="row">
<div class="col-12 mb-3">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="selectAllAdd">
<label class="form-check-label fw-bold" for="selectAllAdd"><?php echo __('select_all'); ?></label>
</div>
<hr>
</div>
<?php foreach ($available_permissions as $perm): ?>
<div class="col-md-4 mb-2">
<div class="form-check">
<input class="form-check-input perm-check-add" type="checkbox" name="permissions[]" value="<?php echo $perm; ?>" id="add_perm_<?php echo $perm; ?>">
<label class="form-check-label" for="add_perm_<?php echo $perm; ?>">
<?php echo __('permission_' . $perm); ?>
</label>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo __('cancel'); ?></button>
<button type="submit" class="btn btn-primary"><?php echo __('save'); ?></button>
</div>
</form>
</div>
</div>
<!-- Edit Permissions Modal -->
<div class="modal fade" id="permissionsModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<form method="POST" class="modal-content">
<input type="hidden" name="action" value="update_permissions">
<input type="hidden" name="role_id" id="permRoleId">
<div class="modal-header">
<h5 class="modal-title"><?php echo __('edit_user'); ?>: <span id="permRoleName"></span></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-12 mb-3">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="selectAll">
<label class="form-check-label fw-bold" for="selectAll"><?php echo __('select_all'); ?></label>
</div>
<hr>
</div>
<?php foreach ($available_permissions as $perm): ?>
<div class="col-md-4 mb-2">
<div class="form-check">
<input class="form-check-input perm-check" type="checkbox" name="permissions[]" value="<?php echo $perm; ?>" id="perm_<?php echo $perm; ?>">
<label class="form-check-label" for="perm_<?php echo $perm; ?>">
<?php echo __('permission_' . $perm); ?>
</label>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo __('cancel'); ?></button>
<button type="submit" class="btn btn-primary"><?php echo __('save_permissions'); ?></button>
</div>
</form>
</div>
</div>
<script>
function editPermissions(role) {
document.getElementById('permRoleId').value = role.id;
document.getElementById('permRoleName').innerText = role.name;
// Reset all checkboxes
document.querySelectorAll('.perm-check').forEach(c => c.checked = false);
// Check active permissions
let perms = [];
try {
perms = JSON.parse(role.permissions);
} catch(e) {
perms = [];
}
if (perms && Array.isArray(perms)) {
perms.forEach(p => {
let checkbox = document.getElementById('perm_' + p);
if (checkbox) checkbox.checked = true;
});
} else if (perms === '*') {
// Handle wildcard if needed, though mostly admin specific
}
new bootstrap.Modal(document.getElementById('permissionsModal')).show();
}
document.getElementById('selectAll').addEventListener('change', function() {
let checked = this.checked;
document.querySelectorAll('.perm-check').forEach(c => c.checked = checked);
});
document.getElementById('selectAllAdd').addEventListener('change', function() {
let checked = this.checked;
document.querySelectorAll('.perm-check-add').forEach(c => c.checked = checked);
});
</script>

246
includes/pages/users.php Normal file
View File

@ -0,0 +1,246 @@
<?php
// Handle Actions
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['action'])) {
try {
if ($_POST['action'] === 'add_user') {
$name = $_POST['name'];
$email = $_POST['email'];
$password = password_hash($_POST['password'], PASSWORD_DEFAULT);
$role_id = $_POST['role_id'];
$active = isset($_POST['active']) ? 1 : 0;
$stmt = $db->prepare("INSERT INTO users (name, email, password, role_id, active) VALUES (?, ?, ?, ?, ?)");
$stmt->execute([$name, $email, $password, $role_id, $active]);
$_SESSION['flash_message'] = __('user_created');
} elseif ($_POST['action'] === 'edit_user') {
$id = $_POST['id'];
$name = $_POST['name'];
$email = $_POST['email'];
$role_id = $_POST['role_id'];
$active = isset($_POST['active']) ? 1 : 0;
$sql = "UPDATE users SET name = ?, email = ?, role_id = ?, active = ? WHERE id = ?";
$params = [$name, $email, $role_id, $active, $id];
if (!empty($_POST['password'])) {
$sql = "UPDATE users SET name = ?, email = ?, role_id = ?, active = ?, password = ? WHERE id = ?";
$params = [$name, $email, $role_id, $active, password_hash($_POST['password'], PASSWORD_DEFAULT), $id];
}
$stmt = $db->prepare($sql);
$stmt->execute($params);
$_SESSION['flash_message'] = __('user_updated');
} elseif ($_POST['action'] === 'delete_user') {
$id = $_POST['id'];
// Prevent deleting self
if ($id == $_SESSION['user_id']) {
throw new Exception("You cannot delete yourself.");
}
$stmt = $db->prepare("DELETE FROM users WHERE id = ?");
$stmt->execute([$id]);
$_SESSION['flash_message'] = __('user_deleted');
}
} catch (Exception $e) {
$_SESSION['flash_message'] = "Error: " . $e->getMessage();
}
header("Location: users.php");
exit;
}
}
// Fetch Users
$stmt = $db->query("SELECT u.*, r.name as role_name FROM users u JOIN roles r ON u.role_id = r.id ORDER BY u.id DESC");
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Fetch Roles
$stmt = $db->query("SELECT * FROM roles ORDER BY name ASC");
$roles = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="fw-bold text-dark mb-0"><?php echo __('users_management'); ?></h2>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addUserModal">
<i class="bi bi-plus-lg me-1"></i> <?php echo __('add_user'); ?>
</button>
</div>
<div class="card shadow-sm">
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead class="table-light">
<tr>
<th>ID</th>
<th><?php echo __('name'); ?></th>
<th><?php echo __('email'); ?></th>
<th><?php echo __('role'); ?></th>
<th><?php echo __('status'); ?></th>
<th><?php echo __('created_at'); ?></th>
<th><?php echo __('actions'); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($users as $user): ?>
<tr>
<td><?php echo $user['id']; ?></td>
<td>
<div class="d-flex align-items-center">
<img src="https://ui-avatars.com/api/?name=<?php echo urlencode($user['name']); ?>&background=random&color=fff&size=32" class="rounded-circle me-2" width="32" height="32">
<span class="fw-medium"><?php echo htmlspecialchars($user['name']); ?></span>
</div>
</td>
<td><?php echo htmlspecialchars($user['email']); ?></td>
<td><span class="badge bg-secondary"><?php echo htmlspecialchars($user['role_name']); ?></span></td>
<td>
<?php if ($user['active']): ?>
<span class="badge bg-success"><?php echo __('active'); ?></span>
<?php else: ?>
<span class="badge bg-danger"><?php echo __('inactive'); ?></span>
<?php endif; ?>
</td>
<td><?php echo date('Y-m-d', strtotime($user['created_at'])); ?></td>
<td>
<button class="btn btn-sm btn-outline-primary me-1" onclick="editUser(<?php echo htmlspecialchars(json_encode($user)); ?>)">
<i class="bi bi-pencil"></i>
</button>
<?php if ($user['id'] != $_SESSION['user_id']): ?>
<button class="btn btn-sm btn-outline-danger" onclick="deleteUser(<?php echo $user['id']; ?>)">
<i class="bi bi-trash"></i>
</button>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Add User Modal -->
<div class="modal fade" id="addUserModal" tabindex="-1">
<div class="modal-dialog">
<form method="POST" class="modal-content">
<input type="hidden" name="action" value="add_user">
<div class="modal-header">
<h5 class="modal-title"><?php echo __('add_user'); ?></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"><?php echo __('name'); ?></label>
<input type="text" name="name" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label"><?php echo __('email'); ?></label>
<input type="email" name="email" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label"><?php echo __('password'); ?></label>
<input type="password" name="password" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label"><?php echo __('role'); ?></label>
<select name="role_id" class="form-select" required>
<?php foreach ($roles as $role): ?>
<option value="<?php echo $role['id']; ?>"><?php echo htmlspecialchars($role['name']); ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="form-check">
<input type="checkbox" name="active" class="form-check-input" id="addActive" checked>
<label class="form-check-label" for="addActive"><?php echo __('active'); ?></label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo __('cancel'); ?></button>
<button type="submit" class="btn btn-primary"><?php echo __('save'); ?></button>
</div>
</form>
</div>
</div>
<!-- Edit User Modal -->
<div class="modal fade" id="editUserModal" tabindex="-1">
<div class="modal-dialog">
<form method="POST" class="modal-content">
<input type="hidden" name="action" value="edit_user">
<input type="hidden" name="id" id="editUserId">
<div class="modal-header">
<h5 class="modal-title"><?php echo __('edit_user'); ?></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"><?php echo __('name'); ?></label>
<input type="text" name="name" id="editUserName" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label"><?php echo __('email'); ?></label>
<input type="email" name="email" id="editUserEmail" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label"><?php echo __('password'); ?> <small class="text-muted">(Leave blank to keep current)</small></label>
<input type="password" name="password" class="form-control">
</div>
<div class="mb-3">
<label class="form-label"><?php echo __('role'); ?></label>
<select name="role_id" id="editUserRole" class="form-select" required>
<?php foreach ($roles as $role): ?>
<option value="<?php echo $role['id']; ?>"><?php echo htmlspecialchars($role['name']); ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="form-check">
<input type="checkbox" name="active" class="form-check-input" id="editUserActive">
<label class="form-check-label" for="editUserActive"><?php echo __('active'); ?></label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo __('cancel'); ?></button>
<button type="submit" class="btn btn-primary"><?php echo __('save'); ?></button>
</div>
</form>
</div>
</div>
<!-- Delete Confirmation Modal -->
<div class="modal fade" id="deleteUserModal" tabindex="-1">
<div class="modal-dialog">
<form method="POST" class="modal-content">
<input type="hidden" name="action" value="delete_user">
<input type="hidden" name="id" id="deleteUserId">
<div class="modal-header">
<h5 class="modal-title"><?php echo __('delete_user'); ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p><?php echo __('confirm_delete_user'); ?></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo __('cancel'); ?></button>
<button type="submit" class="btn btn-danger"><?php echo __('delete'); ?></button>
</div>
</form>
</div>
</div>
<script>
function editUser(user) {
document.getElementById('editUserId').value = user.id;
document.getElementById('editUserName').value = user.name;
document.getElementById('editUserEmail').value = user.email;
document.getElementById('editUserRole').value = user.role_id;
document.getElementById('editUserActive').checked = user.active == 1;
new bootstrap.Modal(document.getElementById('editUserModal')).show();
}
function deleteUser(id) {
document.getElementById('deleteUserId').value = id;
new bootstrap.Modal(document.getElementById('deleteUserModal')).show();
}
</script>

25
inventory_categories.php Normal file
View File

@ -0,0 +1,25 @@
<?php
$section = 'inventory_categories';
require_once __DIR__ . '/db/config.php';
require_once __DIR__ . '/helpers.php';
require_once __DIR__ . '/includes/auth.php';
check_auth();
$db = db();
$lang = $_SESSION['lang'];
require_once __DIR__ . '/includes/actions.php';
require_once __DIR__ . '/includes/common_data.php';
$is_ajax = isset($_GET['ajax_search']) || isset($_POST['ajax_search']);
if (!$is_ajax) {
require_once __DIR__ . '/includes/layout/header.php';
}
require_once __DIR__ . '/includes/pages/inventory_categories.php';
if (!$is_ajax) {
require_once __DIR__ . '/includes/layout/footer.php';
}

25
inventory_dashboard.php Normal file
View File

@ -0,0 +1,25 @@
<?php
$section = 'inventory_dashboard';
require_once __DIR__ . '/db/config.php';
require_once __DIR__ . '/helpers.php';
require_once __DIR__ . '/includes/auth.php';
check_auth();
$db = db();
$lang = $_SESSION['lang'];
require_once __DIR__ . '/includes/actions.php';
require_once __DIR__ . '/includes/common_data.php';
$is_ajax = isset($_GET['ajax_search']) || isset($_POST['ajax_search']);
if (!$is_ajax) {
require_once __DIR__ . '/includes/layout/header.php';
}
require_once __DIR__ . '/includes/pages/inventory_dashboard.php';
if (!$is_ajax) {
require_once __DIR__ . '/includes/layout/footer.php';
}

25
inventory_items.php Normal file
View File

@ -0,0 +1,25 @@
<?php
$section = 'inventory_items';
require_once __DIR__ . '/db/config.php';
require_once __DIR__ . '/helpers.php';
require_once __DIR__ . '/includes/auth.php';
check_auth();
$db = db();
$lang = $_SESSION['lang'];
require_once __DIR__ . '/includes/actions.php';
require_once __DIR__ . '/includes/common_data.php';
$is_ajax = isset($_GET['ajax_search']) || isset($_POST['ajax_search']);
if (!$is_ajax) {
require_once __DIR__ . '/includes/layout/header.php';
}
require_once __DIR__ . '/includes/pages/inventory_items.php';
if (!$is_ajax) {
require_once __DIR__ . '/includes/layout/footer.php';
}

25
inventory_reports.php Normal file
View File

@ -0,0 +1,25 @@
<?php
$section = 'inventory_reports';
require_once __DIR__ . '/db/config.php';
require_once __DIR__ . '/helpers.php';
require_once __DIR__ . '/includes/auth.php';
check_auth();
$db = db();
$lang = $_SESSION['lang'];
require_once __DIR__ . '/includes/actions.php';
require_once __DIR__ . '/includes/common_data.php';
$is_ajax = isset($_GET['ajax_search']) || isset($_POST['ajax_search']);
if (!$is_ajax) {
require_once __DIR__ . '/includes/layout/header.php';
}
require_once __DIR__ . '/includes/pages/inventory_reports.php';
if (!$is_ajax) {
require_once __DIR__ . '/includes/layout/footer.php';
}

View File

@ -0,0 +1,25 @@
<?php
$section = 'inventory_transactions';
require_once __DIR__ . '/db/config.php';
require_once __DIR__ . '/helpers.php';
require_once __DIR__ . '/includes/auth.php';
check_auth();
$db = db();
$lang = $_SESSION['lang'];
require_once __DIR__ . '/includes/actions.php';
require_once __DIR__ . '/includes/common_data.php';
$is_ajax = isset($_GET['ajax_search']) || isset($_POST['ajax_search']);
if (!$is_ajax) {
require_once __DIR__ . '/includes/layout/header.php';
}
require_once __DIR__ . '/includes/pages/inventory_transactions.php';
if (!$is_ajax) {
require_once __DIR__ . '/includes/layout/footer.php';
}

1198
lang.php

File diff suppressed because it is too large Load Diff

27
roles.php Normal file
View File

@ -0,0 +1,27 @@
<?php
$section = 'roles';
require_once __DIR__ . '/db/config.php';
require_once __DIR__ . '/helpers.php';
require_once __DIR__ . '/includes/auth.php';
// Check permissions
check_auth();
require_role('admin');
$db = db();
$lang = $_SESSION['lang'];
require_once __DIR__ . '/includes/actions.php';
require_once __DIR__ . '/includes/common_data.php';
$is_ajax = isset($_GET['ajax_search']) || isset($_POST['ajax_search']);
if (!$is_ajax) {
require_once __DIR__ . '/includes/layout/header.php';
}
require_once __DIR__ . '/includes/pages/roles.php';
if (!$is_ajax) {
require_once __DIR__ . '/includes/layout/footer.php';
}

27
users.php Normal file
View File

@ -0,0 +1,27 @@
<?php
$section = 'users';
require_once __DIR__ . '/db/config.php';
require_once __DIR__ . '/helpers.php';
require_once __DIR__ . '/includes/auth.php';
// Check permissions
check_auth();
require_role('admin');
$db = db();
$lang = $_SESSION['lang'];
require_once __DIR__ . '/includes/actions.php';
require_once __DIR__ . '/includes/common_data.php';
$is_ajax = isset($_GET['ajax_search']) || isset($_POST['ajax_search']);
if (!$is_ajax) {
require_once __DIR__ . '/includes/layout/header.php';
}
require_once __DIR__ . '/includes/pages/users.php';
if (!$is_ajax) {
require_once __DIR__ . '/includes/layout/footer.php';
}