dashboart stats: as of date
This commit is contained in:
@@ -3,24 +3,28 @@
|
||||
require '../../../assets/utils/db_auth.php';
|
||||
require '../../../assets/utils/classes/ReportManager.php';
|
||||
|
||||
$month = $data['month'] ?? date('Y-m');
|
||||
$month = date('Y-m');
|
||||
$report = new ReportManager($pdo2, $company_id);
|
||||
|
||||
$stats = $report->getDashboardStats($month);
|
||||
// All-time stock totals
|
||||
$sth = $pdo2->prepare(
|
||||
"SELECT
|
||||
ROUND(COALESCE(SUM(total_in), 0), 2) AS total_in,
|
||||
ROUND(COALESCE(SUM(total_out), 0), 2) AS total_out
|
||||
FROM warehouse_balance
|
||||
WHERE company_id = :company_id"
|
||||
);
|
||||
$sth->execute([':company_id' => $company_id]);
|
||||
$stock_stats = $sth->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
// Sales stats — query td_order and td_invoice directly
|
||||
$month_start = $month . '-01';
|
||||
$month_end = date('Y-m-t', strtotime($month_start));
|
||||
|
||||
// Total orders this month (excluding cancelled)
|
||||
// All-time orders (excluding cancelled)
|
||||
$sth = $pdo2->prepare(
|
||||
"SELECT COUNT(*), COALESCE(SUM(grand_total), 0)
|
||||
FROM td_order
|
||||
WHERE company_id = :company_id
|
||||
AND status != -1
|
||||
AND order_date BETWEEN :start AND :end"
|
||||
WHERE company_id = :company_id
|
||||
AND status != -1"
|
||||
);
|
||||
$sth->execute([':company_id' => $company_id, ':start' => $month_start, ':end' => $month_end]);
|
||||
$sth->execute([':company_id' => $company_id]);
|
||||
[$total_orders, $total_revenue] = $sth->fetch(PDO::FETCH_NUM);
|
||||
|
||||
// Unpaid invoices (status=0 draft + status=1 issued + status=3 overdue)
|
||||
@@ -50,9 +54,8 @@
|
||||
$healthy_count = max(0, $total_in_stock - $critical_count - $warning_count);
|
||||
|
||||
$answer['output'] = [
|
||||
'total_in' => $stats['total_in'],
|
||||
'total_out' => $stats['total_out'],
|
||||
'active_products' => $stats['active_products'],
|
||||
'total_in' => $stock_stats['total_in'],
|
||||
'total_out' => $stock_stats['total_out'],
|
||||
'low_stock' => count($low_stock_items),
|
||||
'total_orders' => (int)$total_orders,
|
||||
'total_revenue' => (float)$total_revenue,
|
||||
@@ -62,7 +65,6 @@
|
||||
'most_moved' => $report->getMostMovedProducts($month),
|
||||
'low_stock_items' => $low_stock_items,
|
||||
'recent_activity' => $report->getRecentActivity(10),
|
||||
'months' => $report->getAvailableMonths(),
|
||||
'stock_health' => [
|
||||
'healthy' => $healthy_count,
|
||||
'warning' => $warning_count,
|
||||
|
||||
+10
-47
@@ -20,13 +20,6 @@
|
||||
<h1 class="fs-3 mb-1">Dashboard</h1>
|
||||
<p class="mb-0">Inventory overview across all warehouses</p>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<label class="mb-0 text-nowrap fw-semibold">Month</label>
|
||||
<div class="input-group" style="min-width:160px;">
|
||||
<span class="input-group-text"><i class="ti ti-calendar"></i></span>
|
||||
<input type="text" id="month_filter" class="form-control" readonly placeholder="Select month" style="cursor:pointer;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -42,7 +35,7 @@
|
||||
<div>
|
||||
<h2 class="mb-3 fs-6">Total Stock In</h2>
|
||||
<h3 class="fw-bold mb-0" id="stat_total_in">—</h3>
|
||||
<p class="text-warning mb-0 small">Units received this month</p>
|
||||
<p class="text-warning mb-0 small">Total units received</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-loader-overlay" id="overlay_in">
|
||||
@@ -59,7 +52,7 @@
|
||||
<div>
|
||||
<h2 class="mb-3 fs-6">Total Stock Out</h2>
|
||||
<h3 class="fw-bold mb-0" id="stat_total_out">—</h3>
|
||||
<p class="text-danger mb-0 small">Units dispatched this month</p>
|
||||
<p class="text-danger mb-0 small">Total units dispatched</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-loader-overlay" id="overlay_out">
|
||||
@@ -76,7 +69,7 @@
|
||||
<div>
|
||||
<h2 class="mb-3 fs-6">Total Orders</h2>
|
||||
<h3 class="fw-bold mb-0" id="stat_total_orders">—</h3>
|
||||
<p class="text-success mb-0 small">Orders this month</p>
|
||||
<p class="text-success mb-0 small">All orders to date</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-loader-overlay" id="overlay_orders">
|
||||
@@ -93,7 +86,7 @@
|
||||
<div>
|
||||
<h2 class="mb-3 fs-6">Total Revenue</h2>
|
||||
<h3 class="fw-bold mb-0" id="stat_total_revenue">—</h3>
|
||||
<p class="text-info mb-0 small">Grand total this month</p>
|
||||
<p class="text-info mb-0 small">Grand total to date</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-loader-overlay" id="overlay_revenue">
|
||||
@@ -233,7 +226,7 @@
|
||||
<div class="card h-100" style="position:relative;">
|
||||
<div class="card-header bg-white d-flex justify-content-between align-items-center px-4 py-3">
|
||||
<h4 class="mb-0 h5">Most Moved Products</h4>
|
||||
<span class="small text-muted" id="most_moved_month"></span>
|
||||
<span class="small text-muted">This Month</span>
|
||||
</div>
|
||||
<ul class="list-group list-group-flush" id="list_most_moved">
|
||||
<li class="list-group-item text-center text-muted py-5">Loading...</li>
|
||||
@@ -295,7 +288,7 @@
|
||||
|
||||
|
||||
// ── Render all sections ───────────────────────────────────────────────
|
||||
async function render(d, month) {
|
||||
async function render(d) {
|
||||
|
||||
// Stats — top row
|
||||
$('#stat_total_in').text(format_number(d.total_in, 2));
|
||||
@@ -305,7 +298,6 @@
|
||||
$('#overlay_in, #overlay_out, #overlay_orders, #overlay_revenue').hide();
|
||||
|
||||
// Stats — secondary row
|
||||
$('#stat_active_products').text(format_number(d.active_products));
|
||||
$('#stat_low_stock_count').text(format_number(d.low_stock));
|
||||
$('#stat_unpaid_invoices').text(format_number(d.unpaid_invoices));
|
||||
$('#stat_pending_returns').text(format_number(d.pending_returns));
|
||||
@@ -355,7 +347,7 @@
|
||||
$('#stat_total_contacts').text(format_number(d.total_contacts || 0));
|
||||
$('#stat_total_wh').text(format_number(d.total_warehouses || 0));
|
||||
|
||||
var sh_series = [healthy_pct, critical_pct];
|
||||
var sh_series = [healthy_pct, warning_pct + critical_pct];
|
||||
if (overallChart) {
|
||||
await overallChart.updateSeries(sh_series);
|
||||
} else {
|
||||
@@ -402,14 +394,13 @@
|
||||
}
|
||||
},
|
||||
stroke: { lineCap: 'round' },
|
||||
labels: ['Healthy', 'Critical']
|
||||
labels: ['Healthy', 'Warning']
|
||||
});
|
||||
await overallChart.render();
|
||||
}
|
||||
$('#overlay_overall').hide();
|
||||
|
||||
// Most Moved Products
|
||||
$('#most_moved_month').text(format_month(month));
|
||||
var moved_html = '';
|
||||
if (!d.most_moved || d.most_moved.length === 0) {
|
||||
moved_html = '<li class="list-group-item text-center text-muted py-4">No data for this month.</li>';
|
||||
@@ -490,11 +481,6 @@
|
||||
|
||||
// ── Fetch + render ────────────────────────────────────────────────────
|
||||
function retrieve_dashboard() {
|
||||
|
||||
var fpDate = monthPicker.selectedDates[0];
|
||||
var month = fpDate
|
||||
? fpDate.getFullYear() + '-' + String(fpDate.getMonth() + 1).padStart(2, '0')
|
||||
: '<?php echo date('Y-m'); ?>';
|
||||
show_overlays();
|
||||
|
||||
return ajax_request({
|
||||
@@ -502,22 +488,15 @@
|
||||
autoPrepare: true,
|
||||
checkRequired: 0,
|
||||
action: 'read',
|
||||
data: { "month": month },
|
||||
data: {},
|
||||
onSuccess: async function(res) {
|
||||
await render(res.output, month);
|
||||
await render(res.output);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// ── Helpers ───────────────────────────────────────────────────────────
|
||||
function format_month(ym) {
|
||||
if (!ym) return '';
|
||||
var parts = ym.split('-');
|
||||
var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
|
||||
return months[parseInt(parts[1]) - 1] + ' ' + parts[0];
|
||||
}
|
||||
|
||||
function time_ago(dateStr) {
|
||||
if (!dateStr) return '';
|
||||
var diff = Math.floor((new Date() - new Date(dateStr.replace(/-/g,'/'))) / 1000);
|
||||
@@ -530,22 +509,6 @@
|
||||
|
||||
|
||||
// ── Boot ─────────────────────────────────────────────────────────────
|
||||
var monthPicker = flatpickr('#month_filter', {
|
||||
plugins: [
|
||||
new monthSelectPlugin({
|
||||
shorthand: true,
|
||||
dateFormat: 'M Y',
|
||||
altFormat: 'M Y',
|
||||
theme: 'light'
|
||||
})
|
||||
],
|
||||
disableMobile: true,
|
||||
onChange: function() {
|
||||
retrieve_dashboard();
|
||||
}
|
||||
});
|
||||
monthPicker.setDate('<?php echo date('M Y'); ?>', false); // false = don't trigger onChange
|
||||
|
||||
$(async function() {
|
||||
try {
|
||||
show_overlays();
|
||||
|
||||
Reference in New Issue
Block a user