38960-vm/includes/pages/pharmacy_reports.php
2026-03-21 12:43:58 +00:00

349 lines
14 KiB
PHP

<?php
$section = 'pharmacy_reports';
?>
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="fw-bold text-dark mb-0">
<i class="bi bi-file-earmark-bar-graph me-2 text-primary"></i> <?php echo __('pharmacy_reports'); ?>
</h2>
</div>
<div class="card shadow-sm mb-4">
<div class="card-body">
<form id="reportForm" class="row g-3 align-items-end">
<div class="col-md-3">
<label for="reportType" class="form-label"><?php echo __('report_type'); ?></label>
<select class="form-select" id="reportType" name="type" required>
<option value="inventory_valuation"><?php echo __('inventory_valuation'); ?></option>
<option value="sales"><?php echo __('sales_report'); ?></option>
<option value="purchase_report"><?php echo __('purchase_report'); ?></option>
<option value="expiry"><?php echo __('expiry_report'); ?></option>
<option value="low_stock"><?php echo __('low_stock_report'); ?></option>
</select>
</div>
<div class="col-md-3 date-range-group" style="display: none;">
<label for="startDate" class="form-label"><?php echo __('start_date'); ?></label>
<input type="date" class="form-control" id="startDate" name="start_date" value="<?php echo date('Y-m-01'); ?>">
</div>
<div class="col-md-3 date-range-group" style="display: none;">
<label for="endDate" class="form-label"><?php echo __('end_date'); ?></label>
<input type="date" class="form-control" id="endDate" name="end_date" value="<?php echo date('Y-m-d'); ?>">
</div>
<div class="col-md-3">
<button type="button" class="btn btn-primary me-2" onclick="generateReport()">
<i class="bi bi-table"></i> <?php echo __('generate'); ?>
</button>
<button type="button" class="btn btn-secondary" onclick="printReport()">
<i class="bi bi-printer"></i> <?php echo __('print'); ?>
</button>
</div>
</form>
</div>
</div>
<div class="card shadow-sm" id="reportResultCard" style="display: none;">
<div class="card-header bg-white py-3">
<h5 class="card-title mb-0" id="reportTitle"></h5>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover table-bordered" id="reportTable">
<thead class="table-light">
<tr id="tableHeaders"></tr>
</thead>
<tbody id="tableBody"></tbody>
<tfoot id="tableFooter" class="table-light fw-bold"></tfoot>
</table>
</div>
<!-- Pagination Controls -->
<div id="paginationContainer" class="mt-3"></div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const reportType = document.getElementById('reportType');
const dateRangeGroups = document.querySelectorAll('.date-range-group');
function toggleDateInputs() {
const val = reportType.value;
if (val === 'sales' || val === 'expiry' || val === 'purchase_report') {
dateRangeGroups.forEach(el => el.style.display = 'block');
} else {
dateRangeGroups.forEach(el => el.style.display = 'none');
}
}
reportType.addEventListener('change', toggleDateInputs);
toggleDateInputs(); // Init
});
let currentPage = 1;
const limit = 20;
function generateReport(page = 1) {
currentPage = page;
const type = document.getElementById('reportType').value;
const startDate = document.getElementById('startDate').value;
const endDate = document.getElementById('endDate').value;
document.getElementById('reportResultCard').style.display = 'block';
document.getElementById('tableBody').innerHTML = '<tr><td colspan="10" class="text-center p-4"><div class="spinner-border text-primary" role="status"></div><p class="mt-2 mb-0"><?php echo __('loading'); ?>...</p></td></tr>';
const params = new URLSearchParams({
action: 'get_report',
type: type,
start_date: startDate,
end_date: endDate,
page: page,
limit: limit
});
fetch('api/pharmacy.php?' + params.toString())
.then(response => response.json())
.then(data => {
renderTable(type, data);
})
.catch(error => {
console.error('Error:', error);
document.getElementById('tableBody').innerHTML = `<tr><td colspan="10" class="text-center text-danger p-3">${error.message}</td></tr>`;
});
}
function renderTable(type, response) {
const headersRow = document.getElementById('tableHeaders');
const tbody = document.getElementById('tableBody');
const tfoot = document.getElementById('tableFooter');
headersRow.innerHTML = '';
tbody.innerHTML = '';
tfoot.innerHTML = '';
const data = response.data || [];
const total = response.total || 0;
if (data.length === 0) {
tbody.innerHTML = '<tr><td colspan="10" class="text-center text-muted py-4"><?php echo __('no_records_found'); ?></td></tr>';
document.getElementById('paginationContainer').innerHTML = '';
return;
}
if (type === 'inventory_valuation') {
headersRow.innerHTML = `
<th><?php echo __('drug_name'); ?></th>
<th><?php echo __('category'); ?></th>
<th><?php echo __('current_stock'); ?></th>
<th><?php echo __('avg_cost'); ?></th>
<th><?php echo __('selling_price'); ?></th>
<th><?php echo __('total_cost_value'); ?></th>
<th><?php echo __('total_sales_value'); ?></th>
`;
data.forEach(row => {
const costVal = parseFloat(row.total_cost_value || 0);
const salesVal = parseFloat(row.total_sales_value || 0);
tbody.innerHTML += `
<tr>
<td>${row.drug_name || ''} <small class="text-muted">(${row.drug_name_ar || ''})</small></td>
<td>${row.category_name || '-'}</td>
<td>${row.stock_quantity || 0}</td>
<td>${parseFloat(row.avg_cost || 0).toFixed(2)}</td>
<td>${parseFloat(row.selling_price || 0).toFixed(2)}</td>
<td>${costVal.toFixed(2)}</td>
<td>${salesVal.toFixed(2)}</td>
</tr>
`;
});
if (response.grand_total_cost) {
tfoot.innerHTML = `
<tr>
<td colspan="5" class="text-end"><?php echo __('grand_total'); ?>:</td>
<td>${parseFloat(response.grand_total_cost).toFixed(2)}</td>
<td>${parseFloat(response.grand_total_sales).toFixed(2)}</td>
</tr>
`;
}
} else if (type === 'sales') {
headersRow.innerHTML = `
<th><?php echo __('date'); ?></th>
<th><?php echo __('receipt_no'); ?></th>
<th><?php echo __('patient'); ?></th>
<th><?php echo __('items'); ?></th>
<th><?php echo __('total_amount'); ?></th>
<th><?php echo __('payment_method'); ?></th>
`;
data.forEach(row => {
tbody.innerHTML += `
<tr>
<td>${row.created_at}</td>
<td>#${row.id}</td>
<td>${row.patient_name || 'Guest'}</td>
<td>${row.item_count || 1}</td>
<td>${parseFloat(row.total_amount).toFixed(2)}</td>
<td>${row.payment_method || '-'}</td>
</tr>
`;
});
if (response.grand_total_sales) {
tfoot.innerHTML = `
<tr>
<td colspan="4" class="text-end"><?php echo __('grand_total'); ?>:</td>
<td colspan="2">${parseFloat(response.grand_total_sales).toFixed(2)}</td>
</tr>
`;
}
} else if (type === 'purchase_report') {
headersRow.innerHTML = `
<th><?php echo __('date'); ?></th>
<th><?php echo __('lpo'); ?> #</th>
<th><?php echo __('supplier'); ?></th>
<th><?php echo __('status'); ?></th>
<th><?php echo __('total_amount'); ?></th>
`;
data.forEach(row => {
let statusBadge = '';
switch(row.status) {
case 'Draft': statusBadge = '<span class="badge bg-secondary">Draft</span>'; break;
case 'Sent': statusBadge = '<span class="badge bg-primary">Sent</span>'; break;
case 'Received': statusBadge = '<span class="badge bg-success">Received</span>'; break;
case 'Cancelled': statusBadge = '<span class="badge bg-danger">Cancelled</span>'; break;
default: statusBadge = `<span class="badge bg-info">${row.status}</span>`;
}
tbody.innerHTML += `
<tr>
<td>${row.lpo_date}</td>
<td>#${row.id}</td>
<td>${row.supplier_name || '-'}</td>
<td>${statusBadge}</td>
<td>${parseFloat(row.total_amount).toFixed(2)}</td>
</tr>
`;
});
if (response.grand_total_purchases) {
tfoot.innerHTML = `
<tr>
<td colspan="4" class="text-end"><?php echo __('grand_total'); ?>:</td>
<td>${parseFloat(response.grand_total_purchases).toFixed(2)}</td>
</tr>
`;
}
} else if (type === 'expiry') {
headersRow.innerHTML = `
<th><?php echo __('drug_name'); ?></th>
<th><?php echo __('batch_number'); ?></th>
<th><?php echo __('expiry_date'); ?></th>
<th><?php echo __('quantity'); ?></th>
<th><?php echo __('supplier'); ?></th>
<th><?php echo __('days_remaining'); ?></th>
`;
data.forEach(row => {
const days = parseInt(row.days_remaining);
const statusClass = days < 0 ? 'text-danger fw-bold' : (days < 90 ? 'text-warning fw-bold' : '');
tbody.innerHTML += `
<tr>
<td>${row.drug_name}</td>
<td>${row.batch_number}</td>
<td>${row.expiry_date}</td>
<td>${row.quantity}</td>
<td>${row.supplier_name || '-'}</td>
<td class="${statusClass}">${days} <?php echo __('days'); ?></td>
</tr>
`;
});
} else if (type === 'low_stock') {
headersRow.innerHTML = `
<th><?php echo __('drug_name'); ?></th>
<th><?php echo __('current_stock'); ?></th>
<th><?php echo __('min_stock_level'); ?></th>
<th><?php echo __('reorder_level'); ?></th>
<th><?php echo __('unit'); ?></th>
<th><?php echo __('status'); ?></th>
`;
data.forEach(row => {
tbody.innerHTML += `
<tr>
<td>${row.name_en}</td>
<td>${row.total_stock}</td>
<td>${row.min_stock_level || 0}</td>
<td>${row.reorder_level || 0}</td>
<td>${row.unit || '-'}</td>
<td><span class="badge bg-danger"><?php echo __('low_stock'); ?></span></td>
</tr>
`;
});
}
renderPagination(total, limit, currentPage);
}
function renderPagination(totalItems, itemsPerPage, currentPage) {
const totalPages = Math.ceil(totalItems / itemsPerPage);
const paginationContainer = document.getElementById('paginationContainer');
paginationContainer.innerHTML = '';
if (totalPages <= 1) return;
let paginationHTML = '<nav aria-label="Page navigation"><ul class="pagination justify-content-center">';
// Previous Button
paginationHTML += `
<li class="page-item ${currentPage === 1 ? 'disabled' : ''}">
<a class="page-link" href="#" onclick="generateReport(${currentPage - 1}); return false;" aria-label="Previous">
<span aria-hidden="true">&laquo;</span>
</a>
</li>
`;
// Page Numbers
for (let i = 1; i <= totalPages; i++) {
if (i === 1 || i === totalPages || (i >= currentPage - 2 && i <= currentPage + 2)) {
paginationHTML += `
<li class="page-item ${i === currentPage ? 'active' : ''}">
<a class="page-link" href="#" onclick="generateReport(${i}); return false;">${i}</a>
</li>
`;
} else if (i === currentPage - 3 || i === currentPage + 3) {
paginationHTML += '<li class="page-item disabled"><span class="page-link">...</span></li>';
}
}
// Next Button
paginationHTML += `
<li class="page-item ${currentPage === totalPages ? 'disabled' : ''}">
<a class="page-link" href="#" onclick="generateReport(${currentPage + 1}); return false;" aria-label="Next">
<span aria-hidden="true">&raquo;</span>
</a>
</li>
`;
paginationHTML += '</ul></nav>';
paginationContainer.innerHTML = paginationHTML;
}
function printReport() {
const type = document.getElementById('reportType').value;
const startDate = document.getElementById('startDate').value;
const endDate = document.getElementById('endDate').value;
const url = `print_pharmacy_report.php?type=${type}&start_date=${startDate}&end_date=${endDate}`;
// Open in new window/tab
window.open(url, '_blank', 'width=1000,height=800');
}
</script>