Mango.Nop.Plugins/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Components/_FruitBankDashboard.cshtml

429 lines
20 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@* FruitBank operational dashboard — loaded via AJAX, never blocks page render *@
<div id="fb-dashboard-loading" class="text-center py-3">
<i class="fas fa-spinner fa-spin fa-lg text-muted"></i>
<span class="text-muted ml-2">Operatív adatok betöltése...</span>
</div>
<div id="fb-dashboard-content" style="display:none;">
<div class="row" id="fb-pipeline-stats">
<div class="col-6 col-md col-sm-4">
<div class="info-box mb-3">
<span class="info-box-icon bg-info elevation-1"><i class="fas fa-shopping-basket"></i></span>
<div class="info-box-content">
<span class="info-box-text">Mai rendelés</span>
<span class="info-box-number" id="fb-stat-total"></span>
</div>
</div>
</div>
<div class="col-6 col-md col-sm-4">
<div class="info-box mb-3">
<span class="info-box-icon bg-warning elevation-1"><i class="fas fa-weight-hanging"></i></span>
<div class="info-box-content">
<span class="info-box-text">Mérés alatt</span>
<span class="info-box-number" id="fb-stat-measuring"></span>
</div>
</div>
</div>
<div class="col-6 col-md col-sm-4">
<div class="info-box mb-3">
<span class="info-box-icon bg-success elevation-1"><i class="fas fa-check-circle"></i></span>
<div class="info-box-content">
<span class="info-box-text">Auditálva</span>
<span class="info-box-number" id="fb-stat-audited"></span>
</div>
</div>
</div>
<div class="col-6 col-md col-sm-4">
<div class="info-box mb-3">
<span class="info-box-icon bg-danger elevation-1"><i class="fas fa-file-invoice-dollar"></i></span>
<div class="info-box-content">
<span class="info-box-text">InnVoice hiányzik</span>
<span class="info-box-number" id="fb-stat-innvoice"></span>
</div>
</div>
</div>
<div class="col-6 col-md col-sm-4">
<div class="info-box mb-3">
<span class="info-box-icon bg-secondary elevation-1"><i class="fas fa-flag-checkered"></i></span>
<div class="info-box-content">
<span class="info-box-text">Befejezve</span>
<span class="info-box-number" id="fb-stat-completed"></span>
</div>
</div>
</div>
</div>
<div class="card card-primary" id="fb-orders-card">
<div class="card-header">
<h3 class="card-title">
<i class="fas fa-list mr-1"></i>
Mai rendelések
</h3>
<div class="card-tools">
<button type="button" class="btn btn-tool" data-card-widget="collapse">
<i class="fas fa-minus"></i>
</button>
</div>
</div>
<div class="card-body p-0">
<table class="table table-sm table-striped table-hover mb-0" id="fb-orders-table">
<thead class="thead-light">
<tr>
<th>Rendelés</th>
<th>Partner</th>
<th class="text-right">Összeg</th>
<th class="text-center">Mérés</th>
<th class="text-center">InnVoice</th>
<th class="text-center">Státusz</th>
<th>Átvétel</th>
</tr>
</thead>
<tbody id="fb-orders-body">
<tr><td colspan="7" class="text-center text-muted py-3">Betöltés...</td></tr>
</tbody>
</table>
</div>
<div class="card-footer text-muted small" id="fb-orders-footer" style="display:none;">
<a href="/Admin/CustomOrder/List">Összes rendelés &rarr;</a>
</div>
</div>
<div class="card" id="fb-alerts-card" style="display:none;">
<div class="card-header bg-danger">
<h3 class="card-title text-white">
<i class="fas fa-exclamation-triangle mr-1"></i>
Figyelmet igénylő tételek
<span class="badge badge-light ml-2" id="fb-alerts-count">0</span>
</h3>
<div class="card-tools">
<button type="button" class="btn btn-tool text-white" data-card-widget="collapse">
<i class="fas fa-minus"></i>
</button>
</div>
</div>
<div class="card-body p-0">
<table class="table table-sm table-striped mb-0">
<thead class="thead-light">
<tr>
<th>Típus</th>
<th>Partner</th>
<th>Részlet</th>
<th>Link</th>
</tr>
</thead>
<tbody id="fb-alerts-body"></tbody>
</table>
</div>
</div>
<div class="card card-warning collapsed-card" id="fb-credits-card" style="display:none;">
<div class="card-header">
<h3 class="card-title">
<i class="fas fa-credit-card mr-1"></i>
Hitelkeret státusz
<span class="badge badge-secondary ml-2" id="fb-credits-count">0</span>
</h3>
<div class="card-tools">
<button type="button" class="btn btn-tool" data-card-widget="collapse">
<i class="fas fa-plus"></i>
</button>
</div>
</div>
<div class="card-body p-0">
<table class="table table-sm table-striped mb-0">
<thead class="thead-light">
<tr>
<th>Partner</th>
<th class="text-right">Hitelkeret</th>
<th class="text-right">Kint lévő</th>
<th class="text-right">Szabad</th>
<th class="text-center">Státusz</th>
</tr>
</thead>
<tbody id="fb-credits-body"></tbody>
</table>
</div>
</div>
<div class="card card-info collapsed-card" id="fb-preorders-card" style="display:none;">
<div class="card-header">
<h3 class="card-title">
<i class="fas fa-clock mr-1"></i>
Nyitott előrendelések
<span class="badge badge-secondary ml-2" id="fb-preorders-count">0</span>
</h3>
<div class="card-tools">
<button type="button" class="btn btn-tool" data-card-widget="collapse">
<i class="fas fa-plus"></i>
</button>
</div>
</div>
<div class="card-body p-0">
<table class="table table-sm table-striped mb-0">
<thead class="thead-light">
<tr>
<th>Partner</th>
<th>Létrehozva</th>
<th class="text-center">Tételek</th>
<th class="text-center">Teljesített</th>
<th class="text-center">Státusz</th>
<th></th>
</tr>
</thead>
<tbody id="fb-preorders-body"></tbody>
</table>
</div>
<div class="card-footer text-muted small">
<a href="/Admin/Preorders">Összes előrendelés &rarr;</a>
</div>
</div>
<div class="card card-secondary collapsed-card" id="fb-docs-card" style="display:none;">
<div class="card-header">
<h3 class="card-title">
<i class="fas fa-truck-loading mr-1"></i>
Feldolgozatlan szállítmányok
<span class="badge badge-secondary ml-2" id="fb-docs-count">0</span>
</h3>
<div class="card-tools">
<button type="button" class="btn btn-tool" data-card-widget="collapse">
<i class="fas fa-plus"></i>
</button>
</div>
</div>
<div class="card-body p-0">
<table class="table table-sm table-striped mb-0">
<thead class="thead-light">
<tr>
<th>Partner</th>
<th>Szállítás dátuma</th>
<th class="text-center">Tételek</th>
<th class="text-center">Feldolgozva</th>
<th></th>
</tr>
</thead>
<tbody id="fb-docs-body"></tbody>
</table>
</div>
<div class="card-footer text-muted small">
<a href="/Admin/Shipping">Összes szállítmány &rarr;</a>
</div>
</div>
</div>
<script>
(function () {
// ── Helpers ──────────────────────────────────────────────────────────────
function fmt(num) {
return new Intl.NumberFormat('hu-HU', { style: 'currency', currency: 'HUF', maximumFractionDigits: 0 }).format(num);
}
function measuringBadge(status) {
var map = {
'NotStarted': '<span class="badge badge-secondary">Nem kezdett</span>',
'Started': '<span class="badge badge-warning">Mérés alatt</span>',
'Audited': '<span class="badge badge-success">Auditálva</span>'
};
return map[status] || '<span class="badge badge-light">' + status + '</span>';
}
function orderStatusBadge(status) {
var map = {
'Pending': '<span class="badge badge-secondary">Függőben</span>',
'Processing': '<span class="badge badge-info">Folyamatban</span>',
'Complete': '<span class="badge badge-success">Befejezve</span>',
'Cancelled': '<span class="badge badge-danger">Törölve</span>'
};
return map[status] || '<span class="badge badge-light">' + status + '</span>';
}
function creditBadge(status) {
var map = {
'ok': '<span class="badge badge-success">OK</span>',
'warning': '<span class="badge badge-warning">Közel a limithez</span>',
'exceeded': '<span class="badge badge-danger">Túllépve</span>'
};
return map[status] || status;
}
function preorderStatusBadge(status) {
var map = {
'Pending': '<span class="badge badge-warning">Várakozik</span>',
'PartiallyFulfilled': '<span class="badge badge-info">Részben teljesítve</span>',
'Confirmed': '<span class="badge badge-success">Megerősítve</span>',
'Cancelled': '<span class="badge badge-secondary">Törölve</span>'
};
return map[status] || status;
}
function alertTypeBadge(type) {
var map = {
'missing_innvoice': '<span class="badge badge-danger">InnVoice</span>',
'stale_measuring': '<span class="badge badge-warning">Régi mérés</span>',
'credit_exceeded': '<span class="badge badge-danger">Hitelkeret</span>',
'old_preorder': '<span class="badge badge-warning">Előrendelés</span>'
};
return map[type] || '<span class="badge badge-secondary">' + type + '</span>';
}
function alertLink(alert) {
if (alert.type === 'missing_innvoice' || alert.type === 'stale_measuring')
return '<a href="/Admin/Order/Edit/' + alert.orderId + '" class="btn btn-xs btn-outline-primary">Rendelés</a>';
if (alert.type === 'credit_exceeded')
return '<a href="/Admin/CustomerCredit/Details/' + alert.customerId + '" class="btn btn-xs btn-outline-warning">Hitelkeret</a>';
if (alert.type === 'old_preorder')
return '<a href="/Admin/Preorders" class="btn btn-xs btn-outline-info">Előrendelések</a>';
return '';
}
function alertDetail(alert) {
if (alert.type === 'missing_innvoice' || alert.type === 'stale_measuring')
return '#' + (alert.orderNumber || alert.orderId) + (alert.dateOfReceipt ? ' &nbsp;<small class="text-muted">' + alert.dateOfReceipt + '</small>' : '');
if (alert.type === 'credit_exceeded')
return fmt(alert.outstanding) + ' / ' + fmt(alert.creditLimit);
if (alert.type === 'old_preorder')
return alert.createdAt;
return alert.message || '';
}
// ── Main load ────────────────────────────────────────────────────────────
$.ajax({
url: '/Admin/CustomDashboard/GetDashboardData',
type: 'GET',
timeout: 60000,
success: function (data) {
// ── Pipeline stat boxes ──────────────────────────────────────────
var p = data.pipeline;
$('#fb-stat-total').text(p.total);
$('#fb-stat-measuring').text(p.measuring);
$('#fb-stat-audited').text(p.audited);
$('#fb-stat-innvoice').text(p.missingInnVoice);
$('#fb-stat-completed').text(p.completed);
// Highlight the InnVoice box red if there are missing syncs
if (p.missingInnVoice > 0)
$('#fb-stat-innvoice').closest('.info-box').addClass('bg-danger text-white').find('.info-box-text').addClass('text-white');
// ── Today's order rows ───────────────────────────────────────────
var $ob = $('#fb-orders-body').empty();
if (p.rows && p.rows.length > 0) {
p.rows.forEach(function (o) {
var innVoiceIcon = o.hasInnVoice
? '<i class="fas fa-check text-success"></i>'
: '<i class="fas fa-times text-danger"></i>';
$ob.append(
'<tr>' +
'<td><a href="/Admin/Order/Edit/' + o.id + '">#' + (o.orderNumber || o.id) + '</a></td>' +
'<td>' + (o.company || '') + '</td>' +
'<td class="text-right text-nowrap">' + fmt(o.total) + '</td>' +
'<td class="text-center">' + measuringBadge(o.measuringStatus) + '</td>' +
'<td class="text-center">' + innVoiceIcon + '</td>' +
'<td class="text-center">' + orderStatusBadge(o.orderStatus) + '</td>' +
'<td class="text-nowrap small text-muted">' + (o.dateOfReceipt || '') + '</td>' +
'</tr>'
);
});
if (p.total > 20) {
$('#fb-orders-footer').show();
}
} else {
$ob.append('<tr><td colspan="7" class="text-center text-muted py-3">Nincs mai rendelés</td></tr>');
}
// ── Alerts ───────────────────────────────────────────────────────
if (data.alerts && data.alerts.length > 0) {
$('#fb-alerts-count').text(data.alerts.length);
var $ab = $('#fb-alerts-body').empty();
data.alerts.forEach(function (a) {
$ab.append(
'<tr>' +
'<td>' + alertTypeBadge(a.type) + '</td>' +
'<td>' + (a.company || '') + '</td>' +
'<td class="small">' + alertDetail(a) + '</td>' +
'<td>' + alertLink(a) + '</td>' +
'</tr>'
);
});
$('#fb-alerts-card').show();
}
// ── Credit status ────────────────────────────────────────────────
if (data.creditStatus && data.creditStatus.length > 0) {
$('#fb-credits-count').text(data.creditStatus.length);
var $cb = $('#fb-credits-body').empty();
data.creditStatus.forEach(function (c) {
var rowClass = c.status === 'exceeded' ? 'table-danger' : c.status === 'warning' ? 'table-warning' : '';
$cb.append(
'<tr class="' + rowClass + '">' +
'<td><a href="/Admin/CustomerCredit/Details/' + c.customerId + '">' + c.company + '</a></td>' +
'<td class="text-right text-nowrap">' + fmt(c.creditLimit) + '</td>' +
'<td class="text-right text-nowrap">' + fmt(c.outstanding) + '</td>' +
'<td class="text-right text-nowrap">' + fmt(c.remaining) + '</td>' +
'<td class="text-center">' + creditBadge(c.status) + '</td>' +
'</tr>'
);
});
$('#fb-credits-card').show();
}
// ── Pending preorders ────────────────────────────────────────────
if (data.pendingPreorders && data.pendingPreorders.length > 0) {
$('#fb-preorders-count').text(data.pendingPreorders.length);
var $pb = $('#fb-preorders-body').empty();
data.pendingPreorders.forEach(function (p) {
$pb.append(
'<tr>' +
'<td>' + p.company + '</td>' +
'<td class="small text-muted">' + p.createdAt + '</td>' +
'<td class="text-center">' + p.itemCount + '</td>' +
'<td class="text-center">' + p.fulfilledCount + ' / ' + p.itemCount + '</td>' +
'<td class="text-center">' + preorderStatusBadge(p.status) + '</td>' +
'<td><a href="/Admin/Preorders/Details/' + p.id + '" class="btn btn-xs btn-outline-secondary">Részletek</a></td>' +
'</tr>'
);
});
$('#fb-preorders-card').show();
}
// ── Unprocessed shipping docs ────────────────────────────────────
if (data.unprocessedDocs && data.unprocessedDocs.length > 0) {
$('#fb-docs-count').text(data.unprocessedDocs.length);
var $db = $('#fb-docs-body').empty();
data.unprocessedDocs.forEach(function (d) {
var progress = d.totalItems > 0
? d.measuredItems + ' / ' + d.totalItems
: '';
$db.append(
'<tr>' +
'<td>' + (d.partnerName || '') + '</td>' +
'<td class="small text-muted">' + (d.shippingDate || '') + '</td>' +
'<td class="text-center">' + d.totalItems + '</td>' +
'<td class="text-center">' + progress + '</td>' +
'<td><a href="/Admin/Shipping/ShippingDocument/' + d.id + '" class="btn btn-xs btn-outline-secondary">Megnyitás</a></td>' +
'</tr>'
);
});
$('#fb-docs-card').show();
}
// ── Show everything, hide spinner ────────────────────────────────
$('#fb-dashboard-loading').hide();
$('#fb-dashboard-content').show();
},
error: function (xhr, status, error) {
$('#fb-dashboard-loading').html(
'<p class="text-muted"><i class="fas fa-exclamation-circle mr-1"></i>Nem sikerült betölteni az operatív adatokat. (' + (xhr.status || status) + ')</p>'
);
}
});
}());
</script>