38960-vm/includes/pages/inventory_reports.php
2026-03-21 18:03:25 +00:00

207 lines
9.4 KiB
PHP

<?php
$report_type = $_GET['report'] ?? 'low_stock';
// Data Fetching based on report type
$data = [];
$columns = [];
$departments = $db->query("SELECT id, name_en FROM departments ORDER BY name_en ASC")->fetchAll(PDO::FETCH_ASSOC);
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);
} elseif ($report_type === 'consumption') {
$title = __('consumption_report');
$columns = ['department', 'item_name', 'total_quantity', 'total_cost'];
// Filters
$filter_department = $_GET['department_id'] ?? '';
$filter_start = $_GET['start_date'] ?? '';
$filter_end = $_GET['end_date'] ?? '';
$where = "WHERE t.transaction_type = 'out'";
$params = [];
if ($filter_department) {
$where .= " AND t.department_id = ?";
$params[] = $filter_department;
}
if ($filter_start) {
$where .= " AND DATE(t.transaction_date) >= ?";
$params[] = $filter_start;
}
if ($filter_end) {
$where .= " AND DATE(t.transaction_date) <= ?";
$params[] = $filter_end;
}
$sql = "
SELECT d.name_en as department,
i.name_en as item_name,
SUM(t.quantity) as total_quantity,
SUM(t.quantity * COALESCE(b.cost_price, 0)) as total_cost
FROM inventory_transactions t
JOIN departments d ON t.department_id = d.id
JOIN inventory_items i ON t.item_id = i.id
LEFT JOIN inventory_batches b ON t.batch_id = b.id
$where
GROUP BY d.id, i.id
ORDER BY d.name_en ASC, total_cost DESC
";
$stmt = $db->prepare($sql);
$stmt->execute($params);
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Calculate totals
$grand_total_qty = 0;
$grand_total_cost = 0;
foreach ($data as $row) {
$grand_total_qty += $row['total_quantity'];
$grand_total_cost += $row['total_cost'];
}
}
?>
<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>
<a href="?report=consumption" class="btn btn-outline-primary <?php echo $report_type === 'consumption' ? 'active' : ''; ?>"><?php echo __('department_consumption'); ?></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">
<?php if ($report_type === 'consumption'): ?>
<form method="GET" class="row g-3 mb-4 border-bottom pb-4">
<input type="hidden" name="report" value="consumption">
<div class="col-md-3">
<label class="form-label"><?php echo __('department'); ?></label>
<select name="department_id" class="form-select">
<option value=""><?php echo __('all_departments'); ?></option>
<?php foreach ($departments as $dept): ?>
<option value="<?php echo $dept['id']; ?>" <?php echo (isset($filter_department) && $filter_department == $dept['id']) ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($dept['name_en']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-3">
<label class="form-label"><?php echo __('start_date'); ?></label>
<input type="date" name="start_date" class="form-control" value="<?php echo htmlspecialchars($filter_start ?? ''); ?>">
</div>
<div class="col-md-3">
<label class="form-label"><?php echo __('end_date'); ?></label>
<input type="date" name="end_date" class="form-control" value="<?php echo htmlspecialchars($filter_end ?? ''); ?>">
</div>
<div class="col-md-3 d-flex align-items-end">
<button type="submit" class="btn btn-primary w-100">
<i class="bi bi-filter"></i> <?php echo __('filter'); ?>
</button>
</div>
</form>
<?php endif; ?>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead class="table-light">
<tr>
<?php foreach ($columns as $col): ?>
<th><?php echo __($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' || $col === 'total_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>
<?php if ($report_type === 'consumption' && !empty($data)): ?>
<tfoot class="table-light fw-bold">
<tr>
<td colspan="2" class="text-end"><?php echo __('total'); ?>:</td>
<td><?php echo number_format($grand_total_qty); ?></td>
<td><?php echo formatCurrency($grand_total_cost); ?></td>
</tr>
</tfoot>
<?php endif; ?>
</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>