Rework the demo into a faithful Mago4 look-and-feel and expand it with core ERP modules modelled on the real Mago4 database schema. UI (ispirata a Mago4): - Blue header with logo/search/operation date, desktop-style window tabs - White sidebar with coloured module icons (Anagrafiche, Vendite, Acquisti, Amministrazione, Logistica) - Card-based module landing pages with breadcrumb + tab strip - Document detail forms with left tabs, line grid and totals box Fatturazione (InvoiceMng / MA_SaleDoc): - Document types (Fattura Immediata, DDT, Nota di Credito, ProForma) - Lines with discount/IVA, automatic taxable/tax/total computation - Document states (draft -> printed -> issued / posted_to_inventory) Magazzino (Inventory / MA_InventoryEntries + MA_InventoryReasons): - Inventory movements with load/unload reasons (DebitCreditSign) - Posting a movement actually updates item balances - Causali and stock valuation pages Amministrazione / Scadenzario (AP_AR / MA_PyblsRcvbls): - Open items (receivables/payables) with due date, method, state - Settle action closes the item and recomputes the cash forecast Dashboard riprogettata (focus su scadenze e to-do): - Overdue alert banner, KPI for overdue payables/receivables - Upcoming deadlines table, prioritised "Cose da fare" action list - 30-day cash-flow forecast and customer credit-limit check Adds REST endpoints for invoices, movements, schedules and dashboard data. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
181 lines
10 KiB
HTML
181 lines
10 KiB
HTML
{% extends "base.html" %}
|
||
{% block title %}Dashboard - Mago4 Demo{% endblock %}
|
||
|
||
{% set status_badge = {'overdue':'badge-danger','due_soon':'badge-warning','open':'badge-info','paid':'badge-success'} %}
|
||
{% set status_label = {'overdue':'Scaduta','due_soon':'In scadenza','open':'Aperta','paid':'Saldata'} %}
|
||
|
||
{% block content %}
|
||
<div class="module-bar">
|
||
<div class="module-title">Cruscotto Aziendale</div>
|
||
<div class="breadcrumb"><a href="/">Mago4</a><span class="sep">»</span><span class="current">Dashboard</span></div>
|
||
</div>
|
||
|
||
<div class="content-pad">
|
||
<!-- Banner allerta scadenze -->
|
||
{% if stats.overdue_pay_count or stats.overdue_recv_count %}
|
||
<div class="alert alert-danger">
|
||
<i class="material-icons">notification_important</i>
|
||
<span>
|
||
Attenzione: hai
|
||
{% if stats.overdue_pay_count %}<b>{{ stats.overdue_pay_count }} pagamenti scaduti</b> (€ {{ "%.2f"|format(stats.overdue_pay_amount) }}){% endif %}
|
||
{% if stats.overdue_pay_count and stats.overdue_recv_count %} e {% endif %}
|
||
{% if stats.overdue_recv_count %}<b>{{ stats.overdue_recv_count }} incassi scaduti</b> (€ {{ "%.2f"|format(stats.overdue_recv_amount) }}){% endif %}.
|
||
<a href="/scadenzario" style="color:inherit;font-weight:700;text-decoration:underline;">Vai allo scadenzario »</a>
|
||
</span>
|
||
</div>
|
||
{% endif %}
|
||
|
||
<!-- KPI: focus scadenze -->
|
||
<div class="kpi-grid">
|
||
<div class="kpi-card" style="border-left-color: var(--c-red)">
|
||
<div class="kpi-title">Pagamenti Scaduti</div>
|
||
<div class="kpi-row">
|
||
<div class="kpi-icon"><i class="material-icons" style="color:var(--c-red)">payments</i></div>
|
||
<div><div class="kpi-value">€ {{ "{:,.0f}".format(stats.overdue_pay_amount) }}</div>
|
||
<div class="text-mute" style="font-size:11px;">{{ stats.overdue_pay_count }} partite</div></div>
|
||
</div>
|
||
</div>
|
||
<div class="kpi-card" style="border-left-color: var(--c-orange)">
|
||
<div class="kpi-title">Incassi Scaduti</div>
|
||
<div class="kpi-row">
|
||
<div class="kpi-icon"><i class="material-icons" style="color:var(--c-orange)">request_quote</i></div>
|
||
<div><div class="kpi-value">€ {{ "{:,.0f}".format(stats.overdue_recv_amount) }}</div>
|
||
<div class="text-mute" style="font-size:11px;">{{ stats.overdue_recv_count }} partite</div></div>
|
||
</div>
|
||
</div>
|
||
<div class="kpi-card" style="border-left-color: var(--c-blue)">
|
||
<div class="kpi-title">Ordini da Evadere</div>
|
||
<div class="kpi-row">
|
||
<div class="kpi-icon"><i class="material-icons" style="color:var(--c-blue)">local_shipping</i></div>
|
||
<div class="kpi-value">{{ stats.sales_to_fulfill }}</div>
|
||
</div>
|
||
</div>
|
||
<div class="kpi-card" style="border-left-color: var(--c-purple)">
|
||
<div class="kpi-title">Articoli da Ordinare</div>
|
||
<div class="kpi-row">
|
||
<div class="kpi-icon"><i class="material-icons" style="color:var(--c-purple)">production_quantity_limits</i></div>
|
||
<div class="kpi-value">{{ stats.low_stock_count }}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Colonna sinistra: scadenze | destra: cose da fare + cashflow -->
|
||
<div class="dash-grid-2">
|
||
<!-- Scadenze imminenti -->
|
||
<div class="panel">
|
||
<div class="panel-header">
|
||
<h3><i class="material-icons">event_note</i> Scadenze Imminenti (30 giorni)</h3>
|
||
<a href="/scadenzario" class="text-blue" style="font-size:12px;text-decoration:none;">Vedi tutto »</a>
|
||
</div>
|
||
<table class="data-table">
|
||
<thead><tr><th>Scadenza</th><th>Tipo</th><th>Soggetto</th><th class="text-right">Importo</th><th class="text-center">Stato</th></tr></thead>
|
||
<tbody>
|
||
{% for s in upcoming %}
|
||
{% set st = sched_status(s) %}
|
||
<tr class="row-link {% if st == 'overdue' %}low-stock{% endif %}" onclick="location.href='/scadenzario?type={{ s.type.value }}'">
|
||
<td class="text-bold">{{ s.due_date.strftime("%d/%m") }}</td>
|
||
<td>
|
||
{% if s.type == RECEIVABLE %}<span class="badge badge-load"><i class="material-icons">south_west</i> Inc.</span>
|
||
{% else %}<span class="badge badge-unload"><i class="material-icons">north_east</i> Pag.</span>{% endif %}
|
||
</td>
|
||
<td>{{ s.custsupp_name }}</td>
|
||
<td class="text-right text-bold">€ {{ "%.0f"|format(s.amount) }}</td>
|
||
<td class="text-center"><span class="badge {{ status_badge[st] }}">{{ status_label[st] }}</span></td>
|
||
</tr>
|
||
{% endfor %}
|
||
{% if not upcoming %}<tr><td colspan="5" class="text-center text-mute" style="padding:20px;">Nessuna scadenza nei prossimi 30 giorni</td></tr>{% endif %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div>
|
||
<!-- Cose da fare -->
|
||
<div class="panel">
|
||
<div class="panel-header"><h3><i class="material-icons">checklist</i> Cose da Fare</h3></div>
|
||
<div class="todo-list">
|
||
{% for t in todos %}
|
||
<div class="todo-item">
|
||
<div class="todo-icon c-{{ t.color }}"><i class="material-icons">{{ t.icon }}</i></div>
|
||
<div class="todo-body">
|
||
<div class="todo-text">{{ t.text }}</div>
|
||
{% if t.amount %}<div class="todo-amount">€ {{ "%.2f"|format(t.amount) }}</div>{% endif %}
|
||
</div>
|
||
<a href="{{ t.link }}" class="todo-action">{{ t.action }}</a>
|
||
</div>
|
||
{% endfor %}
|
||
{% if not todos %}
|
||
<div class="todo-empty"><i class="material-icons">check_circle</i>Tutto sotto controllo!<br>Nessuna attività urgente.</div>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Previsione di cassa -->
|
||
<div class="panel">
|
||
<div class="panel-header"><h3><i class="material-icons">account_balance_wallet</i> Previsione di Cassa (30 gg)</h3></div>
|
||
<div class="cashflow-box">
|
||
<div class="cashflow-row">
|
||
<div class="cf-label"><i class="material-icons text-success">south_west</i> Incassi previsti</div>
|
||
<div class="cf-value text-success">€ {{ "{:,.2f}".format(cashflow.inflow) }}</div>
|
||
</div>
|
||
<div class="cashflow-row">
|
||
<div class="cf-label"><i class="material-icons text-danger">north_east</i> Pagamenti previsti</div>
|
||
<div class="cf-value text-danger">− € {{ "{:,.2f}".format(cashflow.outflow) }}</div>
|
||
</div>
|
||
<div class="cashflow-row cf-net">
|
||
<div class="cf-label">Saldo previsto</div>
|
||
<div class="cf-value {% if cashflow.net >= 0 %}text-success{% else %}text-danger{% endif %}">€ {{ "{:,.2f}".format(cashflow.net) }}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Riga inferiore: fido superato + ultimi documenti -->
|
||
<div class="dash-grid-2">
|
||
<div class="panel">
|
||
<div class="panel-header"><h3><i class="material-icons">credit_card</i> Controllo Fido Clienti</h3></div>
|
||
<table class="data-table">
|
||
<thead><tr><th>Cliente</th><th class="text-right">Fido</th><th class="text-right">Esposizione</th><th class="text-center">Stato</th></tr></thead>
|
||
<tbody>
|
||
{% for c in credit_exceeded %}
|
||
<tr class="low-stock">
|
||
<td>{{ c.name }}</td>
|
||
<td class="text-right">€ {{ "%.0f"|format(c.credit_limit) }}</td>
|
||
<td class="text-right text-danger text-bold">€ {{ "%.0f"|format(c.balance) }}</td>
|
||
<td class="text-center"><span class="badge badge-danger"><i class="material-icons">warning</i> Superato</span></td>
|
||
</tr>
|
||
{% endfor %}
|
||
{% if not credit_exceeded %}<tr><td colspan="4" class="text-center text-mute" style="padding:20px;">Nessun cliente ha superato il fido</td></tr>{% endif %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="panel">
|
||
<div class="panel-header"><h3><i class="material-icons">description</i> Ultimi Documenti di Vendita</h3></div>
|
||
<table class="data-table">
|
||
<thead><tr><th>Data</th><th>Numero</th><th>Cliente</th><th class="text-right">Totale</th><th>Stato</th></tr></thead>
|
||
<tbody>
|
||
{% for i in last_invoices %}
|
||
<tr class="row-link" onclick="location.href='/invoices/{{ i.id }}'">
|
||
<td>{{ i.doc_date.strftime("%d/%m/%Y") }}</td>
|
||
<td class="text-bold mono">{{ i.doc_no }}</td>
|
||
<td>{{ i.customer_name }}</td>
|
||
<td class="text-right">€ {{ "%.2f"|format(i.total) }}</td>
|
||
<td><span class="badge status-{{ i.status.value }}">{{ doc_status_label(i.status) }}</span></td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- KPI riepilogo -->
|
||
<div class="kpi-grid" style="margin-top:16px;">
|
||
<div class="kpi-card"><div class="kpi-title">Fatturato Emesso</div><div class="kpi-value text-success">€ {{ "{:,.0f}".format(stats.invoiced_total) }}</div></div>
|
||
<div class="kpi-card" style="border-left-color: var(--c-teal)"><div class="kpi-title">Crediti Aperti</div><div class="kpi-value">€ {{ "{:,.0f}".format(stats.open_recv_amount) }}</div></div>
|
||
<div class="kpi-card" style="border-left-color: var(--c-orange)"><div class="kpi-title">Debiti Aperti</div><div class="kpi-value">€ {{ "{:,.0f}".format(stats.open_pay_amount) }}</div></div>
|
||
<div class="kpi-card" style="border-left-color: var(--c-purple)"><div class="kpi-title">Valore Magazzino</div><div class="kpi-value">€ {{ "{:,.0f}".format(stats.warehouse_value) }}</div></div>
|
||
</div>
|
||
</div>
|
||
{% endblock %}
|