38960-vm/includes/pages/pharmacy_inventory.php
2026-03-21 09:33:13 +00:00

352 lines
16 KiB
PHP

<?php
$page = $_GET['page'] ?? 1;
$search = $_GET['search'] ?? '';
// Fetch drugs with stock info
// The API 'get_stock' returns all, but for pagination we might want to do it in PHP or adjust API.
// For now, let's use the API approach via JS or just fetch in PHP.
// Since we are in PHP page, fetching directly is better for SEO/Speed than pure AJAX sometimes, but standard here seems mixed.
// I'll fetch via PHP for initial render.
$limit = 10;
$offset = ($page - 1) * $limit;
$where = "WHERE 1=1";
$params = [];
if ($search) {
$where .= " AND (d.name_en LIKE ? OR d.name_ar LIKE ?)";
$params[] = "%$search%";
$params[] = "%$search%";
}
// Count
$count_stmt = $db->prepare("SELECT COUNT(*) FROM drugs d $where");
$count_stmt->execute($params);
$total_rows = $count_stmt->fetchColumn();
$total_pages = ceil($total_rows / $limit);
// Fetch
$sql = "SELECT d.id, d.name_en, d.name_ar, d.min_stock_level, d.reorder_level, d.unit,
COALESCE(SUM(b.quantity), 0) as total_stock
FROM drugs d
LEFT JOIN pharmacy_batches b ON d.id = b.drug_id AND b.quantity > 0 AND b.expiry_date >= CURDATE()
$where
GROUP BY d.id
ORDER BY d.name_en ASC
LIMIT $limit OFFSET $offset";
$stmt = $db->prepare($sql);
$stmt->execute($params);
$drugs = $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-primary"><i class="bi bi-boxes me-2"></i> <?php echo __('inventory'); ?></h2>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addStockModal">
<i class="bi bi-plus-lg me-1"></i> <?php echo __('add_stock'); ?>
</button>
</div>
<div class="card shadow-sm">
<div class="card-body">
<form method="GET" class="row g-3 mb-4">
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text bg-light border-end-0"><i class="bi bi-search text-muted"></i></span>
<input type="text" name="search" class="form-control border-start-0 ps-0" placeholder="<?php echo __('search'); ?>..." value="<?php echo htmlspecialchars($search); ?>">
</div>
</div>
<div class="col-md-2">
<button type="submit" class="btn btn-primary w-100"><?php echo __('search'); ?></button>
</div>
</form>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th><?php echo __('drug_name'); ?></th>
<th><?php echo __('stock'); ?></th>
<th><?php echo __('unit'); ?></th>
<th><?php echo __('status'); ?></th>
<th><?php echo __('actions'); ?></th>
</tr>
</thead>
<tbody>
<?php if (empty($drugs)): ?>
<tr>
<td colspan="5" class="text-center py-4 text-muted">
<i class="bi bi-inbox fs-1 d-block mb-2"></i>
<?php echo __('no_data_found'); ?>
</td>
</tr>
<?php else: ?>
<?php foreach ($drugs as $drug): ?>
<?php
$status_class = 'bg-success';
$status_text = __('in_stock');
if ($drug['total_stock'] <= 0) {
$status_class = 'bg-danger';
$status_text = __('out_of_stock');
} elseif ($drug['total_stock'] <= $drug['min_stock_level']) {
$status_class = 'bg-warning text-dark';
$status_text = __('low_stock');
}
?>
<tr>
<td>
<div class="fw-bold"><?php echo htmlspecialchars($drug['name_en']); ?></div>
<small class="text-muted"><?php echo htmlspecialchars($drug['name_ar']); ?></small>
</td>
<td>
<span class="fs-5 fw-bold"><?php echo $drug['total_stock']; ?></span>
</td>
<td><?php echo htmlspecialchars($drug['unit'] ?? '-'); ?></td>
<td>
<span class="badge <?php echo $status_class; ?> rounded-pill">
<?php echo $status_text; ?>
</span>
</td>
<td>
<button class="btn btn-sm btn-outline-info" onclick="viewBatches(<?php echo $drug['id']; ?>, '<?php echo addslashes($drug['name_en']); ?>')">
<i class="bi bi-eye"></i> <?php echo __('view_batches'); ?>
</button>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
<!-- Pagination -->
<?php if ($total_pages > 1): ?>
<nav aria-label="Page navigation" class="mt-4">
<ul class="pagination justify-content-center">
<li class="page-item <?php echo $page <= 1 ? 'disabled' : ''; ?>">
<a class="page-link" href="?page=<?php echo max(1, $page - 1); ?>&search=<?php echo urlencode($search); ?>"><?php echo __('previous'); ?></a>
</li>
<?php
$range = 2;
// First page
if ($page == 1) {
echo '<li class="page-item active"><span class="page-link">1</span></li>';
} else {
echo '<li class="page-item"><a class="page-link" href="?page=1&search='.urlencode($search).'">1</a></li>';
}
// Start of range
$start = max(2, $page - $range);
// End of range
$end = min($total_pages - 1, $page + $range);
// Dots before range
if ($start > 2) {
echo '<li class="page-item disabled"><span class="page-link">...</span></li>';
}
// Range loop
for ($i = $start; $i <= $end; $i++) {
if ($i == $page) {
echo '<li class="page-item active"><span class="page-link">'.$i.'</span></li>';
} else {
echo '<li class="page-item"><a class="page-link" href="?page='.$i.'&search='.urlencode($search).'">'.$i.'</a></li>';
}
}
// Dots after range
if ($end < $total_pages - 1) {
echo '<li class="page-item disabled"><span class="page-link">...</span></li>';
}
// Last page (if total > 1)
if ($total_pages > 1) {
if ($page == $total_pages) {
echo '<li class="page-item active"><span class="page-link">'.$total_pages.'</span></li>';
} else {
echo '<li class="page-item"><a class="page-link" href="?page='.$total_pages.'&search='.urlencode($search).'">'.$total_pages.'</a></li>';
}
}
?>
<li class="page-item <?php echo $page >= $total_pages ? 'disabled' : ''; ?>">
<a class="page-link" href="?page=<?php echo min($total_pages, $page + 1); ?>&search=<?php echo urlencode($search); ?>"><?php echo __('next'); ?></a>
</li>
</ul>
</nav>
<?php endif; ?>
</div>
</div>
</div>
<!-- Add Stock Modal -->
<div class="modal fade" id="addStockModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><?php echo __('add_stock'); ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="addStockForm">
<div class="mb-3">
<label class="form-label"><?php echo __('select_drug'); ?></label>
<select class="form-select select2" name="drug_id" required style="width: 100%;">
<option value=""><?php echo __('select_drug'); ?></option>
<?php
$all_drugs = $db->query("SELECT id, name_en FROM drugs ORDER BY name_en ASC")->fetchAll(PDO::FETCH_ASSOC);
foreach ($all_drugs as $d) {
echo "<option value='{$d['id']}'>" . htmlspecialchars($d['name_en']) . "</option>";
}
?>
</select>
</div>
<div class="mb-3">
<label class="form-label"><?php echo __('batch_number'); ?></label>
<input type="text" class="form-control" name="batch_number" required>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label"><?php echo __('expiry_date'); ?></label>
<input type="date" class="form-control" name="expiry_date" required>
</div>
<div class="col-md-6 mb-3">
<label class="form-label"><?php echo __('quantity'); ?></label>
<input type="number" class="form-control" name="quantity" min="1" required>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label"><?php echo __('cost_price'); ?></label>
<input type="number" class="form-control" name="cost_price" step="0.01" value="0">
</div>
<div class="col-md-6 mb-3">
<label class="form-label"><?php echo __('sale_price'); ?></label>
<input type="number" class="form-control" name="sale_price" step="0.01" value="0">
</div>
</div>
<div class="mb-3">
<label class="form-label"><?php echo __('supplier'); ?></label>
<select class="form-select" name="supplier_id">
<option value=""><?php echo __('select_supplier'); ?></option>
<?php
$suppliers = $db->query("SELECT id, name_en FROM suppliers ORDER BY name_en ASC")->fetchAll(PDO::FETCH_ASSOC);
foreach ($suppliers as $s) {
echo "<option value='{$s['id']}'>" . htmlspecialchars($s['name_en']) . "</option>";
}
?>
</select>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo __('cancel'); ?></button>
<button type="button" class="btn btn-primary" onclick="submitStock()"><?php echo __('save'); ?></button>
</div>
</div>
</div>
</div>
<!-- View Batches Modal -->
<div class="modal fade" id="viewBatchesModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="batchesModalTitle"><?php echo __('view_batches'); ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="table-responsive">
<table class="table table-sm table-striped">
<thead>
<tr>
<th><?php echo __('batch_number'); ?></th>
<th><?php echo __('expiry_date'); ?></th>
<th><?php echo __('quantity'); ?></th>
<th><?php echo __('cost_price'); ?></th>
<th><?php echo __('supplier'); ?></th>
</tr>
</thead>
<tbody id="batchesTableBody">
<!-- Populated via JS -->
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<script>
function submitStock() {
const form = document.getElementById('addStockForm');
if (!form.checkValidity()) {
form.reportValidity();
return;
}
const formData = new FormData(form);
fetch('api/pharmacy.php?action=add_stock', {
method: 'POST',
body: formData
})
.then(r => r.json())
.then(data => {
if (data.success) {
location.reload();
} else {
alert(data.error || 'Error adding stock');
}
})
.catch(e => {
console.error(e);
alert('Network error');
});
}
function viewBatches(drugId, drugName) {
document.getElementById('batchesModalTitle').textContent = drugName + ' - Batches';
const tbody = document.getElementById('batchesTableBody');
tbody.innerHTML = '<tr><td colspan="5" class="text-center">Loading...</td></tr>';
const modal = new bootstrap.Modal(document.getElementById('viewBatchesModal'));
modal.show();
fetch('api/pharmacy.php?action=get_batches&drug_id=' + drugId)
.then(r => r.json())
.then(data => {
tbody.innerHTML = '';
if (data.length === 0) {
tbody.innerHTML = '<tr><td colspan="5" class="text-center">No active batches found</td></tr>';
return;
}
data.forEach(batch => {
tbody.innerHTML += `
<tr>
<td>${batch.batch_number}</td>
<td>${batch.expiry_date}</td>
<td>${batch.quantity}</td>
<td>${batch.cost_price}</td>
<td>${batch.supplier_name || '-'}</td>
</tr>
`;
});
})
.catch(e => {
tbody.innerHTML = '<tr><td colspan="5" class="text-center text-danger">Error loading data</td></tr>';
});
}
$(document).ready(function() {
$('.select2').select2({
theme: 'bootstrap-5',
dropdownParent: $('#addStockModal')
});
});
</script>