Restyle UI to match Mago4 and add invoicing, warehouse, scadenzario
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>
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}{{ movement.doc_no }} - Mago4 Demo{% endblock %}
|
||||
{% block window_tabs %}
|
||||
<a href="/inventory-movements" class="window-tab"><i class="material-icons">swap_vert</i> Movimenti</a>
|
||||
<a href="/inventory-movements/{{ movement.id }}" class="window-tab active"><i class="material-icons">inventory</i> {{ movement.doc_no }}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="module-bar">
|
||||
<div class="module-title">Movimento di Magazzino — {{ movement.doc_no }}</div>
|
||||
<div class="breadcrumb"><a href="/">Mago4</a><span class="sep">»</span><a href="/magazzino">Logistica</a><span class="sep">»</span><a href="/inventory-movements">Movimenti</a><span class="sep">»</span><span class="current">{{ movement.doc_no }}</span></div>
|
||||
</div>
|
||||
|
||||
<div class="doc-toolbar">
|
||||
<button class="tb-btn" title="Precedente"><i class="material-icons">chevron_left</i></button>
|
||||
<button class="tb-btn" title="Successivo"><i class="material-icons">chevron_right</i></button>
|
||||
<div class="tb-sep"></div>
|
||||
<button class="tb-btn" title="Modifica"><i class="material-icons">edit</i></button>
|
||||
<button class="tb-btn" title="Salva"><i class="material-icons">save</i></button>
|
||||
<button class="tb-btn" title="Stampa"><i class="material-icons">print</i></button>
|
||||
<div class="tb-sep"></div>
|
||||
{% if not movement.posted %}
|
||||
<button class="btn btn-primary" style="margin-left:6px;" onclick="postMovement({{ movement.id }})"><i class="material-icons">check</i> Conferma e aggiorna giacenze</button>
|
||||
{% endif %}
|
||||
<a class="tb-btn" href="/inventory-movements" title="Chiudi" style="margin-left:auto;"><i class="material-icons">logout</i></a>
|
||||
</div>
|
||||
|
||||
<div style="background:#fff;border-bottom:1px solid var(--border);padding:14px 20px;">
|
||||
<div class="form-grid-2" style="margin-bottom:0;">
|
||||
<div>
|
||||
<div class="field-row"><label>Numero</label><div class="field-value text-bold">{{ movement.doc_no }}</div></div>
|
||||
<div class="field-row"><label>Data Documento</label><div class="field-value">{{ movement.doc_date.strftime("%d/%m/%Y") }}</div></div>
|
||||
<div class="field-row"><label>Data Registrazione</label><div class="field-value">{{ movement.posting_date.strftime("%d/%m/%Y") }}</div></div>
|
||||
<div class="field-row"><label>Deposito</label><div class="field-value">{{ movement.storage }}</div></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="field-row"><label>Causale</label><div class="field-value"><span class="mono">{{ movement.reason_code }}</span> — {{ movement.reason_description }}</div></div>
|
||||
<div class="field-row"><label>Segno</label><div class="field-value">
|
||||
{% if movement.sign.value == 'load' %}<span class="badge badge-load"><i class="material-icons">add</i> Carico (+)</span>
|
||||
{% else %}<span class="badge badge-unload"><i class="material-icons">remove</i> Scarico (−)</span>{% endif %}
|
||||
</div></div>
|
||||
<div class="field-row"><label>Cliente/Fornitore</label><div class="field-value">{{ movement.custsupp_name or '—' }}</div></div>
|
||||
<div class="field-row"><label>Stato</label><div class="field-value" id="statusField">
|
||||
{% if movement.posted %}<span class="badge badge-success"><i class="material-icons">check</i> Confermato</span>
|
||||
{% else %}<span class="badge badge-grey">Bozza</span>{% endif %}
|
||||
</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-pad">
|
||||
<div class="panel">
|
||||
<div class="panel-header"><h3><i class="material-icons">list</i> Righe Movimento</h3></div>
|
||||
<table class="data-table">
|
||||
<thead><tr><th>#</th><th>Articolo</th><th>Descrizione</th><th class="text-center">UM</th><th class="text-right">Q.tà</th><th class="text-right">Valore Unit.</th><th class="text-right">Importo</th><th>Lotto</th><th>Ubicazione</th></tr></thead>
|
||||
<tbody>
|
||||
{% for l in movement.lines %}
|
||||
<tr>
|
||||
<td>{{ l.line_no }}</td>
|
||||
<td class="mono text-bold">{{ l.item_code }}</td>
|
||||
<td>{{ l.description }}</td>
|
||||
<td class="text-center">{{ l.uom }}</td>
|
||||
<td class="text-right {% if movement.sign.value == 'load' %}text-success{% else %}text-danger{% endif %} text-bold">
|
||||
{{ '+' if movement.sign.value == 'load' else '−' }}{{ "%.2f"|format(l.quantity) }}
|
||||
</td>
|
||||
<td class="text-right">€ {{ "%.2f"|format(l.unit_value) }}</td>
|
||||
<td class="text-right text-bold">€ {{ "%.2f"|format(l.line_amount) }}</td>
|
||||
<td>{{ l.lot or '—' }}</td>
|
||||
<td>{{ l.location or '—' }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% if movement.notes %}
|
||||
<div class="panel">
|
||||
<div class="panel-header"><h3><i class="material-icons">notes</i> Note</h3></div>
|
||||
<div class="panel-body padded">{{ movement.notes }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="totals-box">
|
||||
<div class="t-item grand"><div class="t-label">VALORE TOTALE MOVIMENTO</div><div class="t-value">€ {{ "%.2f"|format(movement.total_amount) }}</div></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function postMovement(id) {
|
||||
if (!confirm('Confermare il movimento? Le giacenze degli articoli verranno aggiornate.')) return;
|
||||
fetch(`/inventory-movements/${id}/post`, { method: 'POST' })
|
||||
.then(r => r.json())
|
||||
.then(d => {
|
||||
showNotification('Movimento confermato — giacenze aggiornate');
|
||||
setTimeout(() => location.reload(), 800);
|
||||
})
|
||||
.catch(() => showNotification('Errore nella conferma', 'error'));
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user