diff --git a/db/migrations/20261024115505_add_sales_matrici_permission.php b/db/migrations/20261024115505_add_sales_matrici_permission.php
new file mode 100644
index 00000000..489d35fd
--- /dev/null
+++ b/db/migrations/20261024115505_add_sales_matrici_permission.php
@@ -0,0 +1,35 @@
+fetchRow("SELECT id FROM auth_permissions WHERE name = 'sales.matrici.view'");
+ if ($exists) return;
+
+ $this->table('auth_permissions')->insert([
+ 'name' => 'sales.matrici.view',
+ 'display_name' => 'Statistiche matrici',
+ 'description' => 'Vedere prezzi di vendita, clienti e mescole per matrice',
+ 'removable' => 1,
+ 'created_at' => date('Y-m-d H:i:s'),
+ 'updated_at' => date('Y-m-d H:i:s'),
+ ])->saveData();
+ }
+
+ public function down(): void
+ {
+ $this->execute("DELETE pr FROM auth_permission_role pr
+ JOIN auth_permissions p ON p.id = pr.permission_id
+ WHERE p.name = 'sales.matrici.view'");
+ $this->execute("DELETE FROM auth_permissions WHERE name = 'sales.matrici.view'");
+ }
+}
diff --git a/public/userarea/sales_customer.php b/public/userarea/sales_customer.php
index e863cfc8..96de2037 100644
--- a/public/userarea/sales_customer.php
+++ b/public/userarea/sales_customer.php
@@ -22,6 +22,7 @@ if (!userCan('sales.stats.view')) {
exit;
}
$canDeliveries = userCan('sales.deliveries.view');
+$canMatrici = userCan('sales.matrici.view');
/* ============================================================
* AJAX
@@ -1203,6 +1204,9 @@ if ($action === 'data') {
Andamento ordini
Confronto anni
Scheda cliente
+
+ Matrici
+
Consegne
@@ -1252,6 +1256,9 @@ if ($action === 'data') {
+
+
+
@@ -1271,6 +1278,14 @@ if ($action === 'data') {
@@ -1309,6 +1324,7 @@ if ($action === 'data') {
const STORE_KEY = 'zibo_sales_customer_v1';
const CUR_Y = new Date().getFullYear();
const ZIBO_WEEK = = MagoSalesStats::ZIBO_IS_WEEK ? 'true' : 'false' ?>;
+ const CAN_MATRICI = = $canMatrici ? 'true' : 'false' ?>;
const ZIBO_END_DAYS = = (int)MagoSalesStats::ZIBO_WEEK_END_DAYS ?>;
const ST_LABEL = {
aperto: 'Aperto',
@@ -1538,6 +1554,7 @@ if ($action === 'data') {
`);
}
@@ -1876,9 +1893,74 @@ if ($action === 'data') {
buttons: xls(`Fatture - ${name}`)
});
+ if (CAN_MATRICI) loadMatrici(d.info.code, name);
showTab(tab);
}
+ function loadMatrici(code, name) {
+ const ul = {
+ m: 'm',
+ kg: 'kg',
+ pz: 'pz'
+ };
+ const fp = v => v === null || v === undefined ? '—' : fmtEur(v, Math.abs(v) >= 10 ? 2 : 3);
+ $('#nMatrici').text('…');
+ fetch('sales_matrici.php?action=list&from=2020-01-01&c=' + encodeURIComponent(code)).then(r => r.json()).then(m => {
+ if (code !== current) return;
+ const rows = (m && m.success) ? m.rows : [];
+ $('#nMatrici').text(fmtNum(rows.length));
+ makeTable('matrici', '#tMatrici', {
+ data: rows,
+ columns: [{
+ title: 'Matrice',
+ data: 'name',
+ render: (v, t, r) => t === 'display' ? `
${esc(v)}${esc((m.types || {})[r.type] || r.type)}
` : v
+ }, {
+ title: 'UM',
+ data: 'uom'
+ }, {
+ title: 'Ordini',
+ data: 'orders',
+ className: 'text-end'
+ }, {
+ title: 'Quantità',
+ data: 'qty',
+ className: 'text-end text-nowrap',
+ render: (v, t, r) => t === 'display' ? fmtNum(+v, +v % 1 ? 2 : 0) + (+r.open_qty ? `
+${fmtNum(+r.open_qty)} da cons.
` : '') : +v
+ }, {
+ title: 'Valore',
+ data: 'value',
+ className: 'text-end amount',
+ render: (v, t) => t === 'display' ? fmtEur(+v) : +v
+ }, {
+ title: 'Prezzo medio',
+ data: 'price',
+ className: 'text-end amount',
+ render: (v, t, r) => t === 'display' ? `${fp(v)}
/${ul[r.kind] || esc(r.uom)}` : (v === null ? '' : +v)
+ }, {
+ title: 'Ultimo prezzo',
+ data: 'last_price',
+ className: 'text-end text-nowrap',
+ render: (v, t, r) => t === 'display' ? `${fp(v)}
${fmtDate(r.last_date)}
` : (v === null ? '' : +v)
+ }, {
+ title: 'Var. 12 mesi',
+ data: 'var',
+ className: 'text-end',
+ render: (v, t) => t === 'display' ? (v === null ? '
—' : deltaSpan(v, '')) : (v === null ? '' : +v)
+ }, {
+ title: 'Mescola stimata',
+ data: 'kg',
+ className: 'text-end',
+ render: (v, t, r) => t === 'display' ? (r.kind === 'pz' ? '
a pezzi: in attesa' : (+v ? fmtNum(+v) + ' kg' : '
—')) : +v
+ }],
+ order: [
+ [4, 'desc']
+ ],
+ buttons: xls(`Matrici - ${name}`)
+ });
+ }).catch(() => $('#nMatrici').text('—'));
+ }
+
function showTab(t) {
tab = t;
$('#scTabs button').removeClass('active');
@@ -1917,7 +1999,7 @@ if ($action === 'data') {
});
const st = store();
- if (['open', 'orders', 'items', 'docs'].includes(st.tab)) tab = st.tab;
+ if (['open', 'orders', 'items', 'docs'].concat(CAN_MATRICI ? ['matrici'] : []).includes(st.tab)) tab = st.tab;
loadFilters().then(() => {
renderRecent();
diff --git a/public/userarea/sales_matrici.php b/public/userarea/sales_matrici.php
index fb726013..fde1b0f5 100644
--- a/public/userarea/sales_matrici.php
+++ b/public/userarea/sales_matrici.php
@@ -12,7 +12,8 @@ $db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection();
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
-if (!userCan('sales.stats.view')) {
+// Permesso specifico: prezzi di vendita per matrice e cliente (dati riservati)
+if (!userCan('sales.matrici.view')) {
if (isset($_GET['action'])) {
MagoSalesStats::jsonOut(['success' => false, 'message' => 'Non hai i permessi per questa pagina']);
}
diff --git a/public/userarea/sales_orders_deliveries.php b/public/userarea/sales_orders_deliveries.php
index 0e85951b..e777ba85 100644
--- a/public/userarea/sales_orders_deliveries.php
+++ b/public/userarea/sales_orders_deliveries.php
@@ -635,6 +635,9 @@ if ($action === 'data') {
Andamento ordini
Confronto anni
Scheda cliente
+
+
Matrici
+
Consegne
diff --git a/public/userarea/sales_orders_stats.php b/public/userarea/sales_orders_stats.php
index a5e0648a..8d9027d5 100644
--- a/public/userarea/sales_orders_stats.php
+++ b/public/userarea/sales_orders_stats.php
@@ -1282,6 +1282,9 @@ if ($action === 'order') {
Andamento ordini
Confronto anni
Scheda cliente
+
+
Matrici
+
Consegne
diff --git a/public/userarea/sales_orders_years.php b/public/userarea/sales_orders_years.php
index b46cb25d..963252df 100644
--- a/public/userarea/sales_orders_years.php
+++ b/public/userarea/sales_orders_years.php
@@ -979,6 +979,9 @@ if ($action === 'data') {
Andamento ordini
Confronto anni
Scheda cliente
+
+
Matrici
+
Consegne
diff --git a/public/userarea/sales_summary.php b/public/userarea/sales_summary.php
index ab0b3dfc..e95d45df 100644
--- a/public/userarea/sales_summary.php
+++ b/public/userarea/sales_summary.php
@@ -1812,6 +1812,9 @@ if ($action === 'data') {
Andamento ordini
Confronto anni
Scheda cliente
+
+
Matrici
+
Consegne