added prefernce business overview

This commit is contained in:
2026-10-22 13:48:48 +02:00
parent 33c81e2ad1
commit c4a3e48dd2
12 changed files with 3777 additions and 206 deletions
+64 -53
View File
@@ -6,6 +6,7 @@ error_reporting(E_ALL);
include('include/headscript.php');
require_once __DIR__ . '/class/MagoSync.php';
require_once __DIR__ . '/class/MagoSalesStats.php';
require_once __DIR__ . '/class/UiPrefs.php';
$db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection();
@@ -1072,17 +1073,49 @@ if ($action === 'order') {
<div class="warn-strip mb-3" id="missingAmounts" style="display:none;"></div>
<!-- BARRA: metrica dei grafici + personalizza -->
<div class="d-flex justify-content-between align-items-center mb-2 flex-wrap gap-2">
<div class="chart-title" style="font-size:1.05rem;">Analisi</div>
<div class="metric-switch" id="metricSwitch">
<button type="button" data-metric="count" class="active"># N° ordini</button>
<button type="button" data-metric="value">€ Valore</button>
<div class="d-flex align-items-center gap-2 flex-wrap">
<span class="chart-title mb-0" style="font-size:1rem;">Grafici in</span>
<div class="metric-switch" id="metricSwitch">
<button type="button" data-metric="count" class="active"># N° ordini</button>
<button type="button" data-metric="value">€ Valore</button>
</div>
</div>
<button type="button" data-layout-btn="sales_orders_stats"></button>
</div>
<!-- GRAFICI -->
<div class="row g-3 mb-3">
<div class="col-xl-8">
<!-- RIQUADRI (ordine personalizzabile per utente: ui_layout.js) -->
<div class="row g-3 mb-4" <?= UiPrefs::attr($pdo, $iduserlogin ?? 0, 'sales_orders_stats') ?>>
<!-- ELENCO ORDINI -->
<div class="col-12" data-widget="orders" data-title="Elenco ordini">
<div class="chart-card">
<div class="d-flex justify-content-between align-items-center mb-2">
<div class="chart-title" data-help="st.list">Elenco ordini <span class="text-muted fw-normal" id="rowsInfo"></span></div>
<div class="chart-hint">Clicca una riga per il dettaglio</div>
</div>
<div class="table-responsive">
<table id="ordersTable" class="table table-striped align-middle w-100">
<thead>
<tr>
<th>N° ordine</th>
<th>Data</th>
<th>Cliente</th>
<th>Rif. cliente</th>
<th>Consegna <span class="small fw-normal">(ZIBO / cliente)</span></th>
<th class="text-end">Imponibile</th>
<th>Stato</th>
<th>Fatt.</th>
<th>Agente</th>
<th>Area</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
</div>
<div class="col-xl-8" data-widget="monthly" data-title="Andamento mensile">
<div class="chart-card">
<div class="d-flex justify-content-between align-items-start">
<div>
@@ -1093,83 +1126,47 @@ if ($action === 'order') {
<div id="chMonthly" style="min-height:320px;"></div>
</div>
</div>
<div class="col-xl-4">
<div class="col-xl-4" data-widget="status" data-title="Ripartizione per stato">
<div class="chart-card">
<div class="chart-title" data-help="st.status">Ripartizione per stato</div>
<div class="chart-hint">Clicca una fetta per filtrare</div>
<div id="chStatus" style="min-height:320px;"></div>
</div>
</div>
</div>
<div class="row g-3 mb-3">
<div class="col-xl-7">
<div class="col-xl-7" data-widget="customers" data-title="Top clienti">
<div class="chart-card">
<div class="chart-title" id="ttlCustomers" data-help="st.topcust">Top 10 clienti per numero ordini</div>
<div class="chart-hint">Clicca un cliente per vedere solo i suoi ordini</div>
<div id="chCustomers" style="min-height:360px;"></div>
</div>
</div>
<div class="col-xl-5">
<div class="col-xl-5" data-widget="due" data-title="Scadenze ordini aperti">
<div class="chart-card">
<div class="chart-title" id="ttlDue" data-help="st.due">Scadenze ordini aperti</div>
<div class="chart-hint">In base alla data di consegna prevista</div>
<div id="chDue" style="min-height:360px;"></div>
</div>
</div>
</div>
<div class="row g-3 mb-3">
<div class="col-12">
<div class="col-12" data-widget="items" data-title="Top articoli">
<div class="chart-card">
<div class="chart-title" id="ttlItems" data-help="st.items">Top 10 articoli per numero ordini</div>
<div class="chart-hint">Dalle righe ordine · passa sopra una barra per quantità e valore</div>
<div id="chItems" style="min-height:380px;"></div>
</div>
</div>
</div>
<div class="row g-3 mb-4">
<div class="col-lg-6">
<div class="col-lg-6" data-widget="area" data-title="Ordini per area">
<div class="chart-card">
<div class="chart-title" id="ttlArea" data-help="st.area">Ordini per area</div>
<div id="chArea" style="min-height:260px;"></div>
</div>
</div>
<div class="col-lg-6">
<div class="col-lg-6" data-widget="agent" data-title="Ordini per agente">
<div class="chart-card">
<div class="chart-title" id="ttlSalesperson" data-help="st.agent">Ordini per agente</div>
<div id="chSalesperson" style="min-height:260px;"></div>
</div>
</div>
</div>
<!-- TABELLA -->
<div class="chart-card">
<div class="d-flex justify-content-between align-items-center mb-2">
<div class="chart-title" data-help="st.list">Elenco ordini <span class="text-muted fw-normal" id="rowsInfo"></span></div>
<div class="chart-hint">Clicca una riga per il dettaglio</div>
</div>
<div class="table-responsive">
<table id="ordersTable" class="table table-striped align-middle w-100">
<thead>
<tr>
<th>N° ordine</th>
<th>Data</th>
<th>Cliente</th>
<th>Rif. cliente</th>
<th>Consegna <span class="small fw-normal">(ZIBO / cliente)</span></th>
<th class="text-end">Imponibile</th>
<th>Stato</th>
<th>Fatt.</th>
<th>Agente</th>
<th>Area</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
</div>
</div>
@@ -1382,10 +1379,18 @@ if ($action === 'order') {
}
// aperta da link (?q=numero ordine): non sovrascrivo i filtri salvati dell'utente
const URL_Q = new URLSearchParams(location.search).get('q');
const URL_P = new URLSearchParams(location.search);
const URL_Q = URL_P.get('q');
// aperta dal Sommario (?from=&to=&st=): periodo e stati del box cliccato, senza toccare i filtri salvati
const URL_RANGE = /^\d{4}-\d{2}-\d{2}$/.test(URL_P.get('from') || '') ? {
from: URL_P.get('from'),
to: /^\d{4}-\d{2}-\d{2}$/.test(URL_P.get('to') || '') ? URL_P.get('to') : URL_P.get('from'),
st: (URL_P.get('st') || '').split(',').filter(Boolean)
} : null;
const URL_LINK = !!(URL_Q || URL_RANGE);
function saveFilters(f) {
if (URL_Q) return;
if (URL_LINK) return;
try {
localStorage.setItem(STORE_KEY, JSON.stringify(Object.assign({}, f, {
metric: metric
@@ -2328,7 +2333,7 @@ if ($action === 'order') {
loadFilterOptions(false).then(d => {
window.__totalOrders = d && d.sync ? d.sync.total_orders : 0;
const saved = URL_Q ? null : restoreFilters();
const saved = URL_LINK ? null : restoreFilters();
if (saved && saved.metric === 'value') metric = 'value';
if (URL_Q) {
// tutto lo storico, solo l'ordine cercato; se è uno solo apro il dettaglio
@@ -2337,6 +2342,11 @@ if ($action === 'order') {
$('#periodChips .chip').removeClass('active');
$('#fSearch').val(URL_Q);
window.__autoOpen = URL_Q;
} else if (URL_RANGE) {
$('#fFrom').val(URL_RANGE.from);
$('#fTo').val(URL_RANGE.to);
$('#periodChips .chip').removeClass('active');
URL_RANGE.st.forEach(st => $(`#statusChips .chip[data-status="${st}"]`).addClass('active'));
}
if (saved && saved.from) {
$('#fFrom').val(saved.from);
@@ -2346,7 +2356,7 @@ if ($action === 'order') {
$('#fAreas').val(saved.areas || []).trigger('change.select2');
(saved.statuses || []).forEach(s => $(`#statusChips .chip[data-status="${s}"]`).addClass('active'));
$('#fSearch').val(saved.q || '');
} else if (!URL_Q) {
} else if (!URL_LINK) {
setPeriod('y' + new Date().getFullYear(), true);
}
loadData();
@@ -2355,6 +2365,7 @@ if ($action === 'order') {
})();
</script>
<script src="sales_help.js?v=3"></script>
<script src="ui_layout.js?v=1"></script>
</body>
</html>