fix financial issues
This commit is contained in:
@@ -61,8 +61,8 @@
|
||||
</div>
|
||||
<div class="col-12 col-lg-6">
|
||||
<div class="h-100 p-3 border rounded">
|
||||
<h3 class="h5">Expense Breakdown</h3>
|
||||
<canvas id="expenseChart" style="max-height:320px; width:100%;"></canvas>
|
||||
<h3 class="h5">Expenses out of Net Amount</h3>
|
||||
<canvas id="netExpenseChart" style="max-height:320px; width:100%;"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -77,10 +77,49 @@
|
||||
|
||||
<script>
|
||||
function fmt(n){ return '$' + Number(n||0).toFixed(2); }
|
||||
const initialSummaryData = {
|
||||
schoolYear: <?= json_encode((string)($schoolYear ?? '')) ?>,
|
||||
totalCharges: <?= json_encode((float)($totalCharges ?? 0)) ?>,
|
||||
totalEventFees: <?= json_encode((float)($totalEventFees ?? 0)) ?>,
|
||||
totalExtraCharges: <?= json_encode((float)($totalExtraCharges ?? 0)) ?>,
|
||||
totalDiscounts: <?= json_encode((float)($totalDiscounts ?? 0)) ?>,
|
||||
totalRefunds: <?= json_encode((float)($totalRefunds ?? 0)) ?>,
|
||||
totalExpenses: <?= json_encode((float)($totalExpenses ?? 0)) ?>,
|
||||
totalReimbursements: <?= json_encode((float)($totalReimbursements ?? 0)) ?>,
|
||||
donationToSchool: <?= json_encode((float)($donationToSchool ?? 0)) ?>,
|
||||
totalPaid: <?= json_encode((float)($totalPaid ?? 0)) ?>,
|
||||
amountCollected: <?= json_encode((float)($amountCollected ?? 0)) ?>,
|
||||
totalUnpaid: <?= json_encode((float)($totalUnpaid ?? 0)) ?>,
|
||||
netAmount: <?= json_encode((float)($netAmount ?? 0)) ?>
|
||||
};
|
||||
|
||||
function applySummaryData(d) {
|
||||
document.getElementById('summaryPeriod').textContent = 'Report for School Year: ' + (d.schoolYear || '');
|
||||
document.getElementById('sumCharges').textContent = fmt(d.totalCharges);
|
||||
if (document.getElementById('sumEventFees')) {
|
||||
document.getElementById('sumEventFees').textContent = fmt(d.totalEventFees || 0);
|
||||
}
|
||||
if (document.getElementById('sumExtraCharges')) {
|
||||
document.getElementById('sumExtraCharges').textContent = fmt(d.totalExtraCharges || 0);
|
||||
}
|
||||
document.getElementById('sumDiscounts').textContent = fmt(d.totalDiscounts);
|
||||
document.getElementById('sumRefunds').textContent = fmt(d.totalRefunds);
|
||||
document.getElementById('sumExpenses').textContent = fmt(d.totalExpenses);
|
||||
document.getElementById('sumReimb').textContent = fmt(d.totalReimbursements);
|
||||
if (document.getElementById('sumDonationToSchool')) {
|
||||
document.getElementById('sumDonationToSchool').textContent = fmt(d.donationToSchool);
|
||||
}
|
||||
document.getElementById('sumNet').textContent = fmt(d.netAmount);
|
||||
document.getElementById('sumCollected').textContent = fmt(d.amountCollected || d.totalPaid || 0);
|
||||
document.getElementById('sumUnpaid').textContent = fmt(d.totalUnpaid);
|
||||
}
|
||||
|
||||
// Auto-submit school year on change and hydrate via API
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const sel = document.querySelector('#summaryYearFilter select[name="school_year"]');
|
||||
if (sel) sel.addEventListener('change', function(){ loadSummary(); });
|
||||
applySummaryData(initialSummaryData);
|
||||
renderCharts(initialSummaryData);
|
||||
loadSummary();
|
||||
});
|
||||
|
||||
@@ -97,26 +136,7 @@ function loadSummary(){
|
||||
.then(d => {
|
||||
if (mySeq !== __sumSeq) return; // stale response
|
||||
if (!d || d.ok !== true) return;
|
||||
document.getElementById('summaryPeriod').textContent = 'Report for School Year: ' + (d.schoolYear||'');
|
||||
document.getElementById('sumCharges').textContent = fmt(d.totalCharges);
|
||||
if (document.getElementById('sumEventFees')) {
|
||||
document.getElementById('sumEventFees').textContent = fmt(d.totalEventFees || 0);
|
||||
}
|
||||
if (document.getElementById('sumExtraCharges')) {
|
||||
document.getElementById('sumExtraCharges').textContent = fmt(d.totalExtraCharges || 0);
|
||||
}
|
||||
document.getElementById('sumDiscounts').textContent = fmt(d.totalDiscounts);
|
||||
document.getElementById('sumRefunds').textContent = fmt(d.totalRefunds);
|
||||
document.getElementById('sumExpenses').textContent = fmt(d.totalExpenses);
|
||||
document.getElementById('sumReimb').textContent = fmt(d.totalReimbursements);
|
||||
if (document.getElementById('sumDonationToSchool')) {
|
||||
document.getElementById('sumDonationToSchool').textContent = fmt(d.donationToSchool);
|
||||
}
|
||||
document.getElementById('sumNet').textContent = fmt(d.netAmount);
|
||||
document.getElementById('sumCollected').textContent = fmt(d.amountCollected);
|
||||
document.getElementById('sumUnpaid').textContent = fmt(d.totalUnpaid);
|
||||
|
||||
// Refresh charts with new data
|
||||
applySummaryData(d);
|
||||
renderCharts(d);
|
||||
})
|
||||
.catch(()=>{});
|
||||
@@ -127,7 +147,7 @@ function renderCharts(d){
|
||||
// Destroy existing if present
|
||||
if (window._summaryChart) { window._summaryChart.destroy(); }
|
||||
if (window._collectedChart) { window._collectedChart.destroy(); }
|
||||
if (window._expenseChart) { window._expenseChart.destroy(); }
|
||||
if (window._netExpenseChart) { window._netExpenseChart.destroy(); }
|
||||
const summaryCtx = document.getElementById('summaryChart').getContext('2d');
|
||||
window._summaryChart = new Chart(summaryCtx, {
|
||||
type: 'bar',
|
||||
@@ -152,11 +172,44 @@ function renderCharts(d){
|
||||
options: { responsive:true, plugins:{ legend:{ position:'bottom' } } }
|
||||
});
|
||||
|
||||
const expenseCtx = document.getElementById('expenseChart').getContext('2d');
|
||||
window._expenseChart = new Chart(expenseCtx, {
|
||||
const netExpenseCtx = document.getElementById('netExpenseChart').getContext('2d');
|
||||
const netAmount = Number(d.netAmount || 0);
|
||||
const totalExpenses = Number(d.totalExpenses || 0);
|
||||
const expensePortion = Math.max(0, Math.min(totalExpenses, netAmount));
|
||||
const remainingNet = Math.max(0, netAmount - expensePortion);
|
||||
const expensePercent = netAmount > 0 ? ((totalExpenses / netAmount) * 100).toFixed(1) : '0.0';
|
||||
const remainingPercent = netAmount > 0 ? ((remainingNet / netAmount) * 100).toFixed(1) : '0.0';
|
||||
const netExpenseValues = [expensePortion, remainingNet];
|
||||
const netExpenseLabels = [
|
||||
'Expenses (' + expensePercent + '%)',
|
||||
'Remaining Net (' + remainingPercent + '%)'
|
||||
];
|
||||
window._netExpenseChart = new Chart(netExpenseCtx, {
|
||||
type: 'pie',
|
||||
data: { labels: ['Expenses','Reimbursements'], datasets: [{ data:[ d.totalExpenses||0, d.totalReimbursements||0 ], backgroundColor: ['#dc3545','#6f42c1']}]},
|
||||
options: { responsive:true }
|
||||
data: {
|
||||
labels: netExpenseLabels,
|
||||
datasets: [{
|
||||
data: netExpenseValues,
|
||||
backgroundColor: ['#20c997', '#dc3545'],
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: { position: 'bottom' },
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: function(context) {
|
||||
if (context.dataIndex === 0) {
|
||||
return 'Expenses: ' + fmt(totalExpenses) + ' (' + expensePercent + '% of net amount)';
|
||||
}
|
||||
return 'Remaining Net: ' + fmt(remainingNet) + ' (' + remainingPercent + '%)';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@@ -174,82 +227,4 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
// Bar chart summary
|
||||
const summaryCtx = document.getElementById('summaryChart').getContext('2d');
|
||||
window._summaryChart = new Chart(summaryCtx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: ['Charges', 'Event Fees', 'Paid', 'Unpaid', 'Discounts', 'Refunds', 'Expenses', 'Reimbursements', 'Net'],
|
||||
datasets: [{
|
||||
label: 'Amount (USD)',
|
||||
data: [
|
||||
<?= (float)$totalCharges ?>,
|
||||
<?= (float)($totalEventFees ?? 0) ?>,
|
||||
<?= (float)$totalPaid ?>,
|
||||
<?= (float)$totalUnpaid ?>,
|
||||
<?= (float)$totalDiscounts ?>,
|
||||
<?= (float)$totalRefunds ?>,
|
||||
<?= (float)$totalExpenses ?>,
|
||||
<?= (float)$totalReimbursements ?>,
|
||||
<?= (float)$netAmount ?>
|
||||
],
|
||||
backgroundColor: [
|
||||
'#007bff', '#6610f2', '#28a745', '#ffc107', '#17a2b8', '#ffc107', '#dc3545', '#6f42c1', '#20c997'
|
||||
]
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Collected vs Outstanding pie
|
||||
const collectedCtx = document.getElementById('collectedChart').getContext('2d');
|
||||
window._collectedChart = new Chart(collectedCtx, {
|
||||
type: 'pie',
|
||||
data: {
|
||||
labels: ['Amount Collected (Paid)', 'Amount Outstanding (Unpaid)'],
|
||||
datasets: [{
|
||||
data: [
|
||||
<?= (float)$amountCollected ?>,
|
||||
<?= (float)$totalUnpaid ?>
|
||||
],
|
||||
backgroundColor: ['#28a745', '#ffc107']
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
plugins: { legend: { position: 'bottom' } }
|
||||
}
|
||||
});
|
||||
|
||||
// Pie chart expenses
|
||||
const expenseCtx = document.getElementById('expenseChart').getContext('2d');
|
||||
window._expenseChart = new Chart(expenseCtx, {
|
||||
type: 'pie',
|
||||
data: {
|
||||
labels: ['Expenses', 'Reimbursements'],
|
||||
datasets: [{
|
||||
data: [
|
||||
<?= (float)$totalExpenses ?>,
|
||||
<?= (float)$totalReimbursements ?>
|
||||
],
|
||||
backgroundColor: ['#dc3545', '#6f42c1']
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
Reference in New Issue
Block a user