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:
2026-06-17 11:47:32 +02:00
co-authored by Claude Sonnet 4.6
parent 8a9fb5085a
commit b6b6759b9a
26 changed files with 2900 additions and 2125 deletions
+42
View File
@@ -0,0 +1,42 @@
{% extends "base.html" %}
{% block title %}Acquisti - Mago4 Demo{% endblock %}
{% block window_tabs %}<a href="/acquisti" class="window-tab active"><i class="material-icons">shopping_cart</i> Acquisti</a>{% endblock %}
{% block content %}
<div class="module-bar">
<div class="module-title">Acquisti</div>
<div class="breadcrumb"><a href="/">Mago4</a><span class="sep">»</span><span class="current">Acquisti</span></div>
</div>
<div class="tab-strip">
<a href="/purchase-orders">Ordini Fornitore</a>
<a href="/acquisti" class="active">Documenti Acquisto</a>
<a href="#">Politiche Acquisto</a>
</div>
<div class="cards-grid">
<div class="menu-card">
<div class="menu-card-header"><h3>Ordini Fornitore</h3><span class="collapse-dot">○—</span></div>
<div class="menu-card-body">
<a href="/purchase-orders" class="menu-link"><i class="material-icons ml-icon mtype-form">shopping_cart</i><span class="ml-text">Ordini Fornitore</span><i class="material-icons ml-star">star_border</i></a>
<a href="/purchase-orders" class="menu-link"><i class="material-icons ml-icon mtype-list">list_alt</i><span class="ml-text">Lista Ordini Fornitore</span><i class="material-icons ml-star">star_border</i></a>
<a href="/purchase-orders" class="menu-link"><i class="material-icons ml-icon mtype-print">print</i><span class="ml-text">Portafoglio Fornitori</span><i class="material-icons ml-star">star_border</i></a>
</div>
</div>
<div class="menu-card">
<div class="menu-card-header"><h3>Documenti di Acquisto</h3><span class="collapse-dot">○—</span></div>
<div class="menu-card-body">
<a href="#" class="menu-link"><i class="material-icons ml-icon mtype-form">receipt_long</i><span class="ml-text">Fatture di Acquisto</span><i class="material-icons ml-star">star_border</i></a>
<a href="#" class="menu-link"><i class="material-icons ml-icon mtype-form">inventory</i><span class="ml-text">Documenti di Carico</span><i class="material-icons ml-star">star_border</i></a>
</div>
</div>
<div class="menu-card">
<div class="menu-card-header"><h3>Procedure</h3><span class="collapse-dot">○—</span></div>
<div class="menu-card-body">
<a href="/magazzino" class="menu-link"><i class="material-icons ml-icon mtype-proc">bolt</i><span class="ml-text">Generazione Ordini da Sottoscorta</span><i class="material-icons ml-star">star_border</i></a>
<a href="#" class="menu-link"><i class="material-icons ml-icon mtype-print">bar_chart</i><span class="ml-text">Statistiche Acquisti</span><i class="material-icons ml-star">star_border</i></a>
</div>
</div>
</div>
{% endblock %}
+52
View File
@@ -0,0 +1,52 @@
{% extends "base.html" %}
{% block title %}Amministrazione - Mago4 Demo{% endblock %}
{% block window_tabs %}<a href="/amministrazione" class="window-tab active"><i class="material-icons">account_balance</i> Amministrazione</a>{% endblock %}
{% block content %}
<div class="module-bar">
<div class="module-title">Amministrazione</div>
<div class="breadcrumb"><a href="/">Mago4</a><span class="sep">»</span><span class="current">Amministrazione</span></div>
</div>
<div class="tab-strip">
<a href="/amministrazione" class="active">Amministrazione</a>
<a href="/scadenzario">Scadenzario</a>
</div>
<div class="cards-grid">
<div class="menu-card">
<div class="menu-card-header"><h3>Pagamenti / Incassi</h3><span class="collapse-dot">○—</span></div>
<div class="menu-card-body">
<a href="/scadenzario" class="menu-link"><i class="material-icons ml-icon mtype-form">event_note</i><span class="ml-text">Scadenzario</span><i class="material-icons ml-star">star_border</i></a>
<a href="/scadenzario?type=receivable" class="menu-link"><i class="material-icons ml-icon mtype-list">request_quote</i><span class="ml-text">Partite a Credito (Incassi)</span><i class="material-icons ml-star">star_border</i></a>
<a href="/scadenzario?type=payable" class="menu-link"><i class="material-icons ml-icon mtype-list">payments</i><span class="ml-text">Partite a Debito (Pagamenti)</span><i class="material-icons ml-star">star_border</i></a>
<a href="/scadenzario" class="menu-link"><i class="material-icons ml-icon mtype-print">print</i><span class="ml-text">Stampa Scadenzario</span><i class="material-icons ml-star">star_border</i></a>
</div>
</div>
<div class="menu-card">
<div class="menu-card-header"><h3>Contabilità</h3><span class="collapse-dot">○—</span></div>
<div class="menu-card-body">
<a href="#" class="menu-link"><i class="material-icons ml-icon mtype-form">menu_book</i><span class="ml-text">Prima Nota</span><i class="material-icons ml-star">star_border</i></a>
<a href="#" class="menu-link"><i class="material-icons ml-icon mtype-list">account_tree</i><span class="ml-text">Piano dei Conti</span><i class="material-icons ml-star">star_border</i></a>
<a href="#" class="menu-link"><i class="material-icons ml-icon mtype-print">summarize</i><span class="ml-text">Bilancio</span><i class="material-icons ml-star">star_border</i></a>
</div>
</div>
<div class="menu-card">
<div class="menu-card-header"><h3>IVA</h3><span class="collapse-dot">○—</span></div>
<div class="menu-card-body">
<a href="#" class="menu-link"><i class="material-icons ml-icon mtype-print">receipt_long</i><span class="ml-text">Registri IVA</span><i class="material-icons ml-star">star_border</i></a>
<a href="#" class="menu-link"><i class="material-icons ml-icon mtype-proc">calculate</i><span class="ml-text">Liquidazione IVA</span><i class="material-icons ml-star">star_border</i></a>
</div>
</div>
<div class="menu-card">
<div class="menu-card-header"><h3>Banche</h3><span class="collapse-dot">○—</span></div>
<div class="menu-card-body">
<a href="#" class="menu-link"><i class="material-icons ml-icon mtype-list">account_balance</i><span class="ml-text">Banche Aziendali</span><i class="material-icons ml-star">star_border</i></a>
<a href="#" class="menu-link"><i class="material-icons ml-icon mtype-proc">sync_alt</i><span class="ml-text">Riconciliazione Bancaria</span><i class="material-icons ml-star">star_border</i></a>
<a href="#" class="menu-link"><i class="material-icons ml-icon mtype-proc">request_page</i><span class="ml-text">Presentazione Effetti (RiBa)</span><i class="material-icons ml-star">star_border</i></a>
</div>
</div>
</div>
{% endblock %}
+53
View File
@@ -0,0 +1,53 @@
{% extends "base.html" %}
{% block title %}Anagrafiche - Mago4 Demo{% endblock %}
{% block window_tabs %}<a href="/anagrafiche" class="window-tab active"><i class="material-icons">contacts</i> Anagrafiche</a>{% endblock %}
{% block content %}
<div class="module-bar">
<div class="module-title">Anagrafiche</div>
<div class="breadcrumb"><a href="/">Mago4</a><span class="sep">»</span><span class="current">Anagrafiche</span></div>
</div>
<div class="tab-strip">
<a href="/anagrafiche" class="active">Anagrafiche</a>
<a href="/customers">Clienti</a>
<a href="/suppliers">Fornitori</a>
<a href="/products">Articoli</a>
</div>
<div class="cards-grid">
<div class="menu-card">
<div class="menu-card-header"><h3>Clienti</h3><span class="collapse-dot">○—</span></div>
<div class="menu-card-body">
<a href="/customers" class="menu-link"><i class="material-icons ml-icon mtype-form">people</i><span class="ml-text">Clienti</span><i class="material-icons ml-star">star_border</i></a>
<a href="/customers" class="menu-link"><i class="material-icons ml-icon mtype-print">badge</i><span class="ml-text">Schede Cliente</span><i class="material-icons ml-star">star_border</i></a>
<a href="/customers" class="menu-link"><i class="material-icons ml-icon mtype-list">account_balance_wallet</i><span class="ml-text">Fido Cliente</span><i class="material-icons ml-star">star_border</i></a>
</div>
</div>
<div class="menu-card">
<div class="menu-card-header"><h3>Fornitori</h3><span class="collapse-dot">○—</span></div>
<div class="menu-card-body">
<a href="/suppliers" class="menu-link"><i class="material-icons ml-icon mtype-form">local_shipping</i><span class="ml-text">Fornitori</span><i class="material-icons ml-star">star_border</i></a>
<a href="/suppliers" class="menu-link"><i class="material-icons ml-icon mtype-print">badge</i><span class="ml-text">Schede Fornitore</span><i class="material-icons ml-star">star_border</i></a>
</div>
</div>
<div class="menu-card">
<div class="menu-card-header"><h3>Articoli</h3><span class="collapse-dot">○—</span></div>
<div class="menu-card-body">
<a href="/products" class="menu-link"><i class="material-icons ml-icon mtype-form">inventory_2</i><span class="ml-text">Articoli</span><i class="material-icons ml-star">star_border</i></a>
<a href="/warehouse" class="menu-link"><i class="material-icons ml-icon mtype-list">inventory</i><span class="ml-text">Giacenze Articoli</span><i class="material-icons ml-star">star_border</i></a>
<a href="/products" class="menu-link"><i class="material-icons ml-icon mtype-print">sell</i><span class="ml-text">Listini</span><i class="material-icons ml-star">star_border</i></a>
</div>
</div>
<div class="menu-card">
<div class="menu-card-header"><h3>Tabelle</h3><span class="collapse-dot">○—</span></div>
<div class="menu-card-body">
<a href="#" class="menu-link"><i class="material-icons ml-icon mtype-list">category</i><span class="ml-text">Categorie Clienti</span><i class="material-icons ml-star">star_border</i></a>
<a href="#" class="menu-link"><i class="material-icons ml-icon mtype-list">payments</i><span class="ml-text">Condizioni di Pagamento</span><i class="material-icons ml-star">star_border</i></a>
<a href="#" class="menu-link"><i class="material-icons ml-icon mtype-list">public</i><span class="ml-text">Paesi ISO</span><i class="material-icons ml-star">star_border</i></a>
</div>
</div>
</div>
{% endblock %}
+80 -63
View File
@@ -3,81 +3,98 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Mago4 Demo - ERP{% endblock %}</title>
<title>{% block title %}Mago4 Demo{% endblock %}</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap">
<link rel="stylesheet" href="{{ url_for('static', path='/css/style.css') }}">
{% block extra_css %}{% endblock %}
</head>
<body>
<div class="app-container">
<!-- Sidebar Navigation -->
<!-- Window tabs (stile desktop Mago4) -->
<div class="window-tabs">
<a href="/" class="window-tab {% if active_module == 'dashboard' %}active{% endif %}">
<i class="material-icons">home</i> Home
</a>
{% block window_tabs %}{% endblock %}
</div>
<!-- Header -->
<header class="app-header">
<button class="header-burger"><i class="material-icons">menu</i></button>
<a href="/" class="logo">
<span class="logo-mark">
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M2 20 L8 4 L12 14 L16 4 L22 20 L18 20 L15 11 L12 18 L9 11 L6 20 Z" fill="#1577be"/>
<path d="M16 14 L20 14 L20 9 L22 9 L22 20 L18 20 Z" fill="#5aa632"/>
</svg>
</span>
<span class="logo-text">MAGO</span>
</a>
<div class="header-search">
<i class="material-icons">search</i>
<input type="text" placeholder="Cerca..." onkeydown="if(event.key==='Enter')globalSearch(this.value)">
</div>
<div class="header-right">
<button class="header-icon-btn" title="Lingua"><i class="material-icons">language</i></button>
<div class="header-date">
<span class="label">Data delle operazioni</span>
<span class="value">{{ operation_date }}</span>
</div>
<button class="header-icon-btn" title="Calendario"><i class="material-icons">event</i></button>
<button class="header-icon-btn" title="Profilo"><i class="material-icons">account_circle</i></button>
<button class="header-icon-btn" title="Aggiorna" onclick="location.reload()"><i class="material-icons">refresh</i></button>
</div>
</header>
<div class="app-body">
<!-- Sidebar -->
<aside class="sidebar">
<div class="sidebar-header">
<div class="logo">
<span class="logo-text">Mago4</span>
<span class="logo-version">Demo</span>
</div>
<div class="sidebar-group-title">
<span class="gt-left">
<span class="gt-mark"><i class="material-icons">apps</i></span>
<span class="gt-text">Mago4</span>
</span>
<i class="material-icons chev">expand_less</i>
</div>
<nav class="sidebar-nav">
<a href="/" class="nav-item {% if request.url.path == '/' %}active{% endif %}">
<i class="material-icons">dashboard</i>
<span>Dashboard</span>
</a>
<a href="/customers" class="nav-item {% if 'customers' in request.url.path %}active{% endif %}">
<i class="material-icons">people</i>
<span>Clienti</span>
</a>
<a href="/suppliers" class="nav-item {% if 'suppliers' in request.url.path %}active{% endif %}">
<i class="material-icons">local_shipping</i>
<span>Fornitori</span>
</a>
<a href="/products" class="nav-item {% if 'products' in request.url.path %}active{% endif %}">
<i class="material-icons">inventory_2</i>
<span>Articoli</span>
</a>
<a href="/sales-orders" class="nav-item {% if 'sales' in request.url.path %}active{% endif %}">
<i class="material-icons">receipt</i>
<span>Ordini Vendita</span>
</a>
<a href="/purchase-orders" class="nav-item {% if 'purchase' in request.url.path %}active{% endif %}">
<i class="material-icons">shopping_cart</i>
<span>Ordini Acquisto</span>
</a>
<a href="/warehouse" class="nav-item {% if 'warehouse' in request.url.path %}active{% endif %}">
<i class="material-icons">warehouse</i>
<span>Magazzino</span>
</a>
</nav>
<a href="/" class="nav-item {% if active_module == 'dashboard' %}active{% endif %}">
<i class="material-icons ic-anagrafiche">dashboard</i> Dashboard
</a>
<a href="/anagrafiche" class="nav-item {% if active_module == 'anagrafiche' %}active{% endif %}">
<i class="material-icons ic-anagrafiche">contacts</i> Anagrafiche
</a>
<a href="/amministrazione" class="nav-item {% if active_module == 'amministrazione' %}active{% endif %}">
<i class="material-icons ic-amministrazione">account_balance</i> Amministrazione
</a>
<a href="/vendite" class="nav-item {% if active_module == 'vendite' %}active{% endif %}">
<i class="material-icons ic-vendite">point_of_sale</i> Vendite
</a>
<a href="/acquisti" class="nav-item {% if active_module == 'acquisti' %}active{% endif %}">
<i class="material-icons ic-acquisti">shopping_cart</i> Acquisti
</a>
<a href="/magazzino" class="nav-item {% if active_module == 'magazzino' %}active{% endif %}">
<i class="material-icons ic-logistica">warehouse</i> Logistica
</a>
<a href="#" class="nav-item disabled">
<i class="material-icons ic-produzione">precision_manufacturing</i> Produzione
</a>
<a href="#" class="nav-item disabled">
<i class="material-icons ic-servizi">build</i> Servizi
</a>
<a href="#" class="nav-item disabled">
<i class="material-icons ic-preferenze">settings</i> Preferenze
</a>
<div class="sidebar-footer">
<div class="version-info">
<span>v1.0.0</span>
<span>In-Memory DB</span>
</div>
<div class="sidebar-sub-group">
<span>TaskBuilder Studio</span>
<i class="material-icons chev" style="font-size:16px;">expand_more</i>
</div>
</aside>
<!-- Main Content -->
<main class="main-content">
<header class="top-bar">
<div class="top-bar-content">
<h1 class="page-title">{% block page_title %}{% endblock %}</h1>
<div class="top-bar-actions">
<button class="btn-icon" title="Notifiche">
<i class="material-icons">notifications</i>
</button>
<button class="btn-icon" title="Profilo">
<i class="material-icons">account_circle</i>
</button>
</div>
</div>
</header>
<section class="content-area">
{% block content %}{% endblock %}
</section>
<!-- Main content -->
<main class="main">
{% block content %}{% endblock %}
</main>
</div>
+60 -111
View File
@@ -1,53 +1,46 @@
{% extends "base.html" %}
{% block title %}Clienti - Mago4 Demo{% endblock %}
{% block page_title %}Clienti{% endblock %}
{% block window_tabs %}<a href="/customers" class="window-tab active"><i class="material-icons">people</i> Clienti</a>{% endblock %}
{% block content %}
<div class="page-header">
<button class="btn btn-primary" onclick="openCreateCustomerModal()">
<i class="material-icons">add</i> Nuovo Cliente
</button>
<div class="module-bar">
<div class="module-title">Clienti</div>
<div class="breadcrumb"><a href="/">Mago4</a><span class="sep">»</span><a href="/anagrafiche">Anagrafiche</a><span class="sep">»</span><span class="current">Clienti</span></div>
</div>
<div class="tab-strip">
<a href="/anagrafiche">Anagrafiche</a>
<a href="/customers" class="active">Clienti</a>
<a href="/suppliers">Fornitori</a>
<a href="/products">Articoli</a>
</div>
<div class="widget-card">
<div class="widget-header">
<h3 class="widget-title">Elenco Clienti</h3>
</div>
<div class="widget-body">
<div class="doc-toolbar">
<button class="tb-btn" title="Nuovo" onclick="alert('Nuovo cliente (demo)')"><i class="material-icons">add_box</i></button>
<button class="tb-btn" title="Cerca"><i class="material-icons">search</i></button>
<div class="tb-sep"></div>
<button class="tb-btn" title="Stampa"><i class="material-icons">print</i></button>
<button class="tb-btn" title="Esporta"><i class="material-icons">file_download</i></button>
</div>
<div class="content-pad">
<div class="panel">
<div class="panel-header"><h3><i class="material-icons">people</i> Elenco Clienti</h3></div>
<table class="data-table">
<thead>
<tr>
<th>Codice</th>
<th>Ragione Sociale</th>
<th>Città</th>
<th>Paese</th>
<th>Telefono</th>
<th>Limite Credito</th>
<th>Saldo</th>
<th>Azioni</th>
</tr>
<tr><th>Codice</th><th>Ragione Sociale</th><th>Partita IVA</th><th>Città</th><th>Paese</th><th>Pagamento</th><th class="text-right">Fido</th><th class="text-right">Saldo</th><th></th></tr>
</thead>
<tbody>
{% for customer in customers %}
{% for c in customers %}
<tr>
<td><strong>{{ customer.code }}</strong></td>
<td>{{ customer.name }}</td>
<td>{{ customer.city }}</td>
<td>{{ customer.country }}</td>
<td>{{ customer.phone }}</td>
<td class="text-right">{{ "%.2f"|format(customer.credit_limit) }}</td>
<td class="text-right {% if customer.balance > 0 %}text-danger{% endif %}">
€ {{ "%.2f"|format(customer.balance) }}
</td>
<td>
<button class="btn-small btn-info" onclick="viewCustomer({{ customer.id }})">
<i class="material-icons">visibility</i>
</button>
<button class="btn-small btn-warning" onclick="editCustomer({{ customer.id }})">
<i class="material-icons">edit</i>
</button>
</td>
<td class="text-bold mono">{{ c.code }}</td>
<td>{{ c.name }}</td>
<td class="mono">{{ c.vat_number or '—' }}</td>
<td>{{ c.city }}</td>
<td>{{ c.country }}</td>
<td>{{ c.payment_terms }}</td>
<td class="text-right">€ {{ "%.0f"|format(c.credit_limit) }}</td>
<td class="text-right {% if c.balance > 0 %}text-danger{% endif %}">€ {{ "%.2f"|format(c.balance) }}</td>
<td class="text-center"><button class="btn-icon-sm act-view" onclick="viewCustomer({{ c.id }})"><i class="material-icons">visibility</i></button></td>
</tr>
{% endfor %}
</tbody>
@@ -55,82 +48,38 @@
</div>
</div>
<!-- Modal Detail -->
<div id="customerModal" class="modal" onclick="closeModal(event)">
<div class="modal-content" onclick="event.stopPropagation()">
<div class="modal-header">
<h2 id="modalTitle">Dettagli Cliente</h2>
<button class="btn-close" onclick="closeModal()">
<i class="material-icons">close</i>
</button>
</div>
<div class="modal-body" id="modalBody">
<!-- Content loaded via JS -->
</div>
<div id="genericModal" class="modal" onclick="if(event.target.id==='genericModal')closeGenericModal()">
<div class="modal-content">
<div class="modal-header"><h2 id="gmTitle">Dettagli</h2><button class="modal-close" onclick="closeGenericModal()"><i class="material-icons">close</i></button></div>
<div class="modal-body" id="gmBody"></div>
</div>
</div>
<script>
function viewCustomer(customerId) {
fetch(`/api/customers/${customerId}`)
.then(r => r.json())
.then(data => {
document.getElementById('modalTitle').textContent = `Cliente: ${data.name}`;
document.getElementById('modalBody').innerHTML = `
<div class="detail-grid">
<div class="detail-item">
<label>Codice</label>
<span>${data.code}</span>
</div>
<div class="detail-item">
<label>Ragione Sociale</label>
<span>${data.name}</span>
</div>
<div class="detail-item">
<label>Email</label>
<span>${data.email}</span>
</div>
<div class="detail-item">
<label>Telefono</label>
<span>${data.phone}</span>
</div>
<div class="detail-item">
<label>Indirizzo</label>
<span>${data.address}</span>
</div>
<div class="detail-item">
<label>Città</label>
<span>${data.city}</span>
</div>
<div class="detail-item">
<label>Paese</label>
<span>${data.country}</span>
</div>
<div class="detail-item">
<label>Limite Credito</label>
<span>€ ${data.credit_limit.toFixed(2)}</span>
</div>
<div class="detail-item">
<label>Saldo</label>
<span class="${data.balance > 0 ? 'text-danger' : ''}">${data.balance > 0 ? '€ ' : ''}${Math.abs(data.balance).toFixed(2)}</span>
</div>
</div>
`;
document.getElementById('customerModal').classList.add('show');
});
}
function editCustomer(customerId) {
alert('Modifica cliente: ' + customerId + ' (da implementare)');
}
function openCreateCustomerModal() {
alert('Creazione nuovo cliente (da implementare)');
}
function closeModal(event) {
if (event && event.target.id !== 'customerModal') return;
document.getElementById('customerModal').classList.remove('show');
function viewCustomer(id) {
fetch(`/api/customers/${id}`).then(r=>r.json()).then(d=>{
document.getElementById('gmTitle').textContent = 'Cliente: ' + d.name;
document.getElementById('gmBody').innerHTML = `
<div style="padding:16px">
<div class="form-section-title">Dati Principali</div>
<div class="form-grid-2">
${field('Codice', d.code)}${field('Ragione Sociale', d.name)}
${field('Partita IVA', d.vat_number || '—')}${field('Codice Fiscale', d.fiscal_code || '—')}
${field('Email', d.email)}${field('Telefono', d.phone)}
</div>
<div class="form-section-title">Indirizzo</div>
<div class="form-grid-2">
${field('Indirizzo', d.address)}${field('Città', d.city)}
${field('Paese', d.country)}${field('Pagamento', d.payment_terms)}
</div>
<div class="form-section-title">Dati Commerciali</div>
<div class="form-grid-2">
${field('Limite Credito', '€ ' + d.credit_limit.toFixed(2))}
${field('Saldo', '€ ' + d.balance.toFixed(2))}
</div>
</div>`;
document.getElementById('genericModal').classList.add('show');
});
}
</script>
{% endblock %}
+173 -99
View File
@@ -1,106 +1,180 @@
{% extends "base.html" %}
{% block title %}Dashboard - Mago4 Demo{% endblock %}
{% block page_title %}Dashboard{% 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="dashboard-container">
<!-- First Row - KPI Cards -->
<div class="widget-row">
{% for widget in widgets[0] %}
<div class="widget-card stat-card" style="border-left-color: var(--color-{{ widget.color }})">
<div class="widget-header">
<h3 class="widget-title">{{ widget.title }}</h3>
</div>
<div class="widget-body stat-body">
<div class="stat-icon" style="color: var(--color-{{ widget.color }})">
<i class="material-icons">{{ widget.icon }}</i>
</div>
<div class="stat-value">{{ widget.value }}</div>
</div>
</div>
{% endfor %}
</div>
<!-- Second Row - Data Tables -->
<div class="widget-row">
{% for widget in widgets[1] %}
<div class="widget-card">
<div class="widget-header">
<h3 class="widget-title">{{ widget.title }}</h3>
{% if widget.subtitle %}<p class="widget-subtitle">{{ widget.subtitle }}</p>{% endif %}
</div>
<div class="widget-body grid-body">
<table class="data-table">
<thead>
<tr>
{% if "Vendita" in widget.title %}
<th>Data</th>
<th>Numero Ordine</th>
<th>Cliente</th>
<th>Importo</th>
<th>Stato</th>
{% else %}
<th>Data</th>
<th>Numero Ordine</th>
<th>Fornitore</th>
<th>Importo</th>
<th>Stato</th>
{% endif %}
</tr>
</thead>
<tbody>
{% if "Vendita" in widget.title %}
{% for order in widget.data.orders %}
<tr>
<td>{{ order.order_date }}</td>
<td><strong>{{ order.order_number }}</strong></td>
<td>{{ order.customer_name }}</td>
<td class="text-right">{{ order.total_amount }}</td>
<td>
<span class="badge status-{{ order.status }}">{{ order.status }}</span>
</td>
</tr>
{% endfor %}
{% else %}
{% for order in widget.data.orders %}
<tr>
<td>{{ order.order_date }}</td>
<td><strong>{{ order.order_number }}</strong></td>
<td>{{ order.supplier_name }}</td>
<td class="text-right">{{ order.total_amount }}</td>
<td>
<span class="badge status-{{ order.status }}">{{ order.status }}</span>
</td>
</tr>
{% endfor %}
{% endif %}
</tbody>
</table>
</div>
</div>
{% endfor %}
</div>
<!-- Summary Stats -->
<div class="summary-stats">
<div class="stat-summary">
<div class="stat-label">Totale Clienti</div>
<div class="stat-number">{{ stats.total_customers }}</div>
</div>
<div class="stat-summary">
<div class="stat-label">Totale Fornitori</div>
<div class="stat-number">{{ stats.total_suppliers }}</div>
</div>
<div class="stat-summary">
<div class="stat-label">Articoli in Catalogo</div>
<div class="stat-number">{{ stats.total_products }}</div>
</div>
<div class="stat-summary">
<div class="stat-label">Debiti Fornitori</div>
<div class="stat-number text-orange">€ {{ "%.2f"|format(stats.total_payable) }}</div>
</div>
</div>
<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 %}
+55
View File
@@ -0,0 +1,55 @@
{% extends "base.html" %}
{% block title %}Movimenti di Magazzino - Mago4 Demo{% endblock %}
{% block window_tabs %}<a href="/inventory-movements" class="window-tab active"><i class="material-icons">swap_vert</i> Movimenti</a>{% endblock %}
{% block content %}
<div class="module-bar">
<div class="module-title">Movimenti di Magazzino</div>
<div class="breadcrumb"><a href="/">Mago4</a><span class="sep">»</span><a href="/magazzino">Logistica</a><span class="sep">»</span><span class="current">Movimenti</span></div>
</div>
<div class="tab-strip">
<a href="/magazzino">Magazzino</a>
<a href="/inventory-movements" class="active">Movimenti</a>
<a href="/warehouse">Giacenze</a>
<a href="/inventory-reasons">Causali</a>
</div>
<div class="doc-toolbar">
<button class="tb-btn" title="Nuovo movimento" onclick="alert('Nuovo movimento (demo)')"><i class="material-icons">add_box</i></button>
<button class="tb-btn" title="Cerca"><i class="material-icons">search</i></button>
<div class="tb-sep"></div>
<button class="tb-btn" title="Stampa giornale"><i class="material-icons">print</i></button>
</div>
<div class="content-pad">
<div class="alert alert-info"><i class="material-icons">info</i> I movimenti <b>confermati</b> aggiornano le giacenze secondo il segno della causale (carico +, scarico ).</div>
<div class="panel">
<div class="panel-header"><h3><i class="material-icons">swap_vert</i> Elenco Movimenti</h3></div>
<table class="data-table">
<thead><tr><th>Data Reg.</th><th>Numero</th><th>Causale</th><th class="text-center">Segno</th><th>Cliente/Fornitore</th><th class="text-center">Deposito</th><th class="text-right">Valore</th><th class="text-center">Stato</th><th></th></tr></thead>
<tbody>
{% for m in movements %}
<tr class="row-link" onclick="location.href='/inventory-movements/{{ m.id }}'">
<td>{{ m.posting_date.strftime("%d/%m/%Y") }}</td>
<td class="text-bold mono">{{ m.doc_no }}</td>
<td><span class="mono">{{ m.reason_code }}</span> — {{ m.reason_description }}</td>
<td class="text-center">
{% if m.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 %}
</td>
<td>{{ m.custsupp_name or '—' }}</td>
<td class="text-center">{{ m.storage }}</td>
<td class="text-right">€ {{ "%.2f"|format(m.total_amount) }}</td>
<td class="text-center">
{% if m.posted %}<span class="badge badge-success"><i class="material-icons">check</i> Confermato</span>
{% else %}<span class="badge badge-grey">Bozza</span>{% endif %}
</td>
<td class="text-center"><i class="material-icons text-blue" style="font-size:17px;">chevron_right</i></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
+46
View File
@@ -0,0 +1,46 @@
{% extends "base.html" %}
{% block title %}Causali di Magazzino - Mago4 Demo{% endblock %}
{% block window_tabs %}<a href="/inventory-reasons" class="window-tab active"><i class="material-icons">rule</i> Causali</a>{% endblock %}
{% block content %}
<div class="module-bar">
<div class="module-title">Causali di Magazzino</div>
<div class="breadcrumb"><a href="/">Mago4</a><span class="sep">»</span><a href="/magazzino">Logistica</a><span class="sep">»</span><span class="current">Causali</span></div>
</div>
<div class="tab-strip">
<a href="/magazzino">Magazzino</a>
<a href="/inventory-movements">Movimenti</a>
<a href="/warehouse">Giacenze</a>
<a href="/inventory-reasons" class="active">Causali</a>
</div>
<div class="doc-toolbar">
<button class="tb-btn" title="Nuova causale" onclick="alert('Nuova causale (demo)')"><i class="material-icons">add_box</i></button>
<button class="tb-btn" title="Stampa"><i class="material-icons">print</i></button>
</div>
<div class="content-pad">
<div class="alert alert-info"><i class="material-icons">info</i> Le causali determinano se un movimento <b>carica</b> o <b>scarica</b> la giacenza (campo <span class="mono">DebitCreditSign</span> in Mago4).</div>
<div class="panel">
<div class="panel-header"><h3><i class="material-icons">rule</i> Elenco Causali</h3></div>
<table class="data-table">
<thead><tr><th>Codice</th><th>Descrizione</th><th class="text-center">Segno</th><th class="text-center">Numerazione Fiscale</th><th class="text-center">Aggiorna Giacenze</th></tr></thead>
<tbody>
{% for r in reasons %}
<tr>
<td class="text-bold mono">{{ r.code }}</td>
<td>{{ r.description }}</td>
<td class="text-center">
{% if r.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 %}
</td>
<td class="text-center">{% if r.fiscal %}<i class="material-icons text-success">check_circle</i>{% else %}<i class="material-icons text-mute">remove</i>{% endif %}</td>
<td class="text-center">{% if r.updates_balance %}<i class="material-icons text-success">check_circle</i>{% else %}<i class="material-icons text-mute">remove</i>{% endif %}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
+141
View File
@@ -0,0 +1,141 @@
{% extends "base.html" %}
{% block title %}{{ invoice.doc_no }} - Mago4 Demo{% endblock %}
{% block window_tabs %}
<a href="/invoices" class="window-tab"><i class="material-icons">description</i> Documenti Vendita</a>
<a href="/invoices/{{ invoice.id }}" class="window-tab active"><i class="material-icons">request_quote</i> {{ invoice.doc_no }}</a>
{% endblock %}
{% block content %}
<div class="module-bar">
<div class="module-title">{{ doc_type_label(invoice.doc_type) }} — {{ invoice.doc_no }}</div>
<div class="breadcrumb"><a href="/">Mago4</a><span class="sep">»</span><a href="/vendite">Vendite</a><span class="sep">»</span><a href="/invoices">Documenti Vendita</a><span class="sep">»</span><span class="current">{{ invoice.doc_no }}</span></div>
</div>
<!-- Toolbar documento -->
<div class="doc-toolbar">
<button class="tb-btn" title="Primo"><i class="material-icons">first_page</i></button>
<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>
<button class="tb-btn" title="Ultimo"><i class="material-icons">last_page</i></button>
<div class="tb-sep"></div>
<button class="tb-btn" title="Nuovo"><i class="material-icons">note_add</i></button>
<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="Elimina"><i class="material-icons">delete</i></button>
<div class="tb-sep"></div>
<button class="tb-btn" title="Stampa"><i class="material-icons">print</i></button>
<button class="tb-btn" title="Invia email"><i class="material-icons">email</i></button>
<button class="tb-btn" title="Esporta XML (FatturaPA)"><i class="material-icons">file_download</i></button>
<div class="tb-sep"></div>
<a class="tb-btn" href="/invoices" title="Chiudi"><i class="material-icons">logout</i></a>
</div>
<!-- Intestazione documento -->
<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">{{ invoice.doc_no }}</div></div>
<div class="field-row"><label>Del</label><div class="field-value">{{ invoice.doc_date.strftime("%d/%m/%Y") }}</div></div>
<div class="field-row"><label>Registrato il</label><div class="field-value">{{ invoice.posting_date.strftime("%d/%m/%Y") }}</div></div>
</div>
<div>
<div class="field-row"><label>Cliente</label><div class="field-value">{{ invoice.customer_name }}</div></div>
<div class="field-row"><label>Partita IVA</label><div class="field-value mono">{{ invoice.customer_vat or '—' }}</div></div>
<div class="field-row"><label>Stato</label><div class="field-value"><span class="badge status-{{ invoice.status.value }}">{{ doc_status_label(invoice.status) }}</span></div></div>
</div>
</div>
</div>
<!-- Form con tab laterali -->
<div class="doc-form">
<div class="doc-form-tabs">
<div class="doc-form-tab active" onclick="showTab(this,'tab-main')"><i class="material-icons">article</i> Dati Principali</div>
<div class="doc-form-tab" onclick="showTab(this,'tab-lines')"><i class="material-icons">list</i> Righe Documento</div>
<div class="doc-form-tab" onclick="showTab(this,'tab-pay')"><i class="material-icons">payments</i> Dati Pagamento</div>
<div class="doc-form-tab" onclick="showTab(this,'tab-notes')"><i class="material-icons">notes</i> Note</div>
</div>
<div class="doc-form-content">
<!-- TAB: Dati principali -->
<div id="tab-main">
<div class="form-section-title">Dati Principali</div>
<div class="form-grid-2">
<div class="field-row"><label>Tipo Documento</label><div class="field-value">{{ doc_type_label(invoice.doc_type) }}</div></div>
<div class="field-row"><label>Valuta</label><div class="field-value">{{ invoice.currency }}</div></div>
<div class="field-row"><label>Listino</label><div class="field-value">{{ invoice.price_list }}</div></div>
<div class="field-row"><label>Agente</label><div class="field-value">{{ invoice.salesperson or '—' }}</div></div>
<div class="field-row"><label>Nostro Rif.</label><div class="field-value">{{ invoice.our_reference or '—' }}</div></div>
<div class="field-row"><label>Vostro Rif.</label><div class="field-value">{{ invoice.your_reference or '—' }}</div></div>
</div>
<div class="form-section-title">Stato Elaborazione</div>
<div class="form-grid-2">
<div class="field-row"><label>Stampato</label><div class="field-value">{{ 'Sì' if invoice.printed else 'No' }}</div></div>
<div class="field-row"><label>Emesso</label><div class="field-value">{{ 'Sì' if invoice.issued else 'No' }}</div></div>
<div class="field-row"><label>Scaricato a Magazzino</label><div class="field-value">{{ 'Sì' if invoice.posted_to_inventory else 'No' }}</div></div>
</div>
</div>
<!-- TAB: Righe -->
<div id="tab-lines" style="display:none;">
<div class="form-section-title">Righe Documento</div>
<table class="data-table-nested">
<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">Val. Unit.</th><th class="text-right">Sconto</th><th class="text-right">Prezzo Netto</th><th class="text-center">IVA</th><th class="text-right">Imponibile</th></tr></thead>
<tbody>
{% for l in invoice.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">{{ "%.2f"|format(l.quantity) }}</td>
<td class="text-right">€ {{ "%.2f"|format(l.unit_value) }}</td>
<td class="text-right">{{ "%.0f"|format(l.discount_pct) }}%</td>
<td class="text-right">€ {{ "%.2f"|format(l.net_price) }}</td>
<td class="text-center">{{ "%.0f"|format(l.tax_rate) }}%</td>
<td class="text-right text-bold">€ {{ "%.2f"|format(l.taxable_amount) }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- TAB: Pagamento -->
<div id="tab-pay" style="display:none;">
<div class="form-section-title">Dati di Pagamento</div>
<div class="form-grid-2">
<div class="field-row"><label>Condizione</label><div class="field-value">{{ invoice.payment_terms }}</div></div>
<div class="field-row"><label>Totale Documento</label><div class="field-value text-bold">€ {{ "%.2f"|format(invoice.total) }}</div></div>
</div>
<div class="form-section-title">Riepilogo IVA</div>
<table class="data-table-nested">
<thead><tr><th>Aliquota</th><th class="text-right">Imponibile</th><th class="text-right">Imposta</th></tr></thead>
<tbody>
<tr><td>22%</td><td class="text-right">€ {{ "%.2f"|format(invoice.taxable_total) }}</td><td class="text-right">€ {{ "%.2f"|format(invoice.tax_total) }}</td></tr>
</tbody>
</table>
</div>
<!-- TAB: Note -->
<div id="tab-notes" style="display:none;">
<div class="form-section-title">Note</div>
<div class="field-value" style="min-height:80px;align-items:flex-start;">{{ invoice.notes or 'Nessuna nota.' }}</div>
</div>
</div>
</div>
<!-- Totali -->
<div class="totals-box">
<div class="t-item"><div class="t-label">Totale Imponibile</div><div class="t-value">€ {{ "%.2f"|format(invoice.taxable_total) }}</div></div>
<div class="t-item"><div class="t-label">Totale IVA</div><div class="t-value">€ {{ "%.2f"|format(invoice.tax_total) }}</div></div>
<div class="t-item grand"><div class="t-label">TOTALE DOCUMENTO</div><div class="t-value">€ {{ "%.2f"|format(invoice.total) }}</div></div>
</div>
<script>
function showTab(el, id) {
document.querySelectorAll('.doc-form-tab').forEach(t => t.classList.remove('active'));
el.classList.add('active');
['tab-main','tab-lines','tab-pay','tab-notes'].forEach(t =>
document.getElementById(t).style.display = (t === id ? 'block' : 'none'));
}
</script>
{% endblock %}
+55
View File
@@ -0,0 +1,55 @@
{% extends "base.html" %}
{% block title %}Documenti Vendita - Mago4 Demo{% endblock %}
{% block window_tabs %}<a href="/invoices" class="window-tab active"><i class="material-icons">description</i> Documenti Vendita</a>{% endblock %}
{% block content %}
<div class="module-bar">
<div class="module-title">Documenti di Vendita</div>
<div class="breadcrumb"><a href="/">Mago4</a><span class="sep">»</span><a href="/vendite">Vendite</a><span class="sep">»</span><span class="current">Documenti Vendita</span></div>
</div>
<div class="tab-strip">
<a href="/invoices" class="{% if selected_type == 'all' %}active{% endif %}">Tutti</a>
<a href="/invoices?type=immediate_invoice" class="{% if selected_type == 'immediate_invoice' %}active{% endif %}">Fatture Immediate</a>
<a href="/invoices?type=delivery_note" class="{% if selected_type == 'delivery_note' %}active{% endif %}">DDT</a>
<a href="/invoices?type=credit_note" class="{% if selected_type == 'credit_note' %}active{% endif %}">Note di Credito</a>
<a href="/invoices?type=proforma_invoice" class="{% if selected_type == 'proforma_invoice' %}active{% endif %}">ProForma</a>
</div>
<div class="doc-toolbar">
<button class="tb-btn" title="Nuovo documento" onclick="alert('Nuovo documento (demo)')"><i class="material-icons">add_box</i></button>
<button class="tb-btn" title="Cerca"><i class="material-icons">search</i></button>
<div class="tb-sep"></div>
<button class="tb-btn" title="Stampa"><i class="material-icons">print</i></button>
<button class="tb-btn" title="Invia email"><i class="material-icons">email</i></button>
<button class="tb-btn" title="Esporta XML"><i class="material-icons">file_download</i></button>
</div>
<div class="content-pad">
<div class="panel">
<div class="panel-header"><h3><i class="material-icons">description</i> Elenco Documenti ({{ invoices|length }})</h3></div>
<table class="data-table">
<thead><tr><th>Tipo</th><th>Numero</th><th>Data</th><th>Cliente</th><th class="text-right">Imponibile</th><th class="text-right">IVA</th><th class="text-right">Totale</th><th>Stato</th><th class="text-center">Fatt.</th><th></th></tr></thead>
<tbody>
{% for i in invoices %}
<tr class="row-link" onclick="location.href='/invoices/{{ i.id }}'">
<td>{{ doc_type_label(i.doc_type) }}</td>
<td class="text-bold mono">{{ i.doc_no }}</td>
<td>{{ i.doc_date.strftime("%d/%m/%Y") }}</td>
<td>{{ i.customer_name }}</td>
<td class="text-right">€ {{ "%.2f"|format(i.taxable_total) }}</td>
<td class="text-right text-mute">€ {{ "%.2f"|format(i.tax_total) }}</td>
<td class="text-right text-bold">€ {{ "%.2f"|format(i.total) }}</td>
<td><span class="badge status-{{ i.status.value }}">{{ doc_status_label(i.status) }}</span></td>
<td class="text-center">
{% if i.issued %}<i class="material-icons text-success" title="Emesso" style="font-size:17px;">check_circle</i>
{% elif i.printed %}<i class="material-icons text-warning" title="Stampato" style="font-size:17px;">print</i>
{% else %}<i class="material-icons text-mute" title="Bozza" style="font-size:17px;">edit</i>{% endif %}
</td>
<td class="text-center"><i class="material-icons text-blue" style="font-size:17px;">chevron_right</i></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
+53
View File
@@ -0,0 +1,53 @@
{% extends "base.html" %}
{% block title %}Logistica - Mago4 Demo{% endblock %}
{% block window_tabs %}<a href="/magazzino" class="window-tab active"><i class="material-icons">warehouse</i> Logistica</a>{% endblock %}
{% block content %}
<div class="module-bar">
<div class="module-title">Logistica &amp; Magazzino</div>
<div class="breadcrumb"><a href="/">Mago4</a><span class="sep">»</span><span class="current">Logistica</span></div>
</div>
<div class="tab-strip">
<a href="/magazzino" class="active">Magazzino</a>
<a href="/inventory-movements">Movimenti</a>
<a href="/warehouse">Giacenze</a>
<a href="/inventory-reasons">Tabelle</a>
</div>
<div class="cards-grid">
<div class="menu-card">
<div class="menu-card-header"><h3>Movimenti di Magazzino</h3><span class="collapse-dot">○—</span></div>
<div class="menu-card-body">
<a href="/inventory-movements" class="menu-link"><i class="material-icons ml-icon mtype-form">swap_vert</i><span class="ml-text">Movimenti di Magazzino</span><i class="material-icons ml-star">star_border</i></a>
<a href="/inventory-movements" class="menu-link"><i class="material-icons ml-icon mtype-list">list_alt</i><span class="ml-text">Lista Movimenti</span><i class="material-icons ml-star">star_border</i></a>
<a href="/inventory-movements" class="menu-link"><i class="material-icons ml-icon mtype-print">print</i><span class="ml-text">Giornale di Magazzino</span><i class="material-icons ml-star">star_border</i></a>
</div>
</div>
<div class="menu-card">
<div class="menu-card-header"><h3>Giacenze</h3><span class="collapse-dot">○—</span></div>
<div class="menu-card-body">
<a href="/warehouse" class="menu-link"><i class="material-icons ml-icon mtype-list">inventory</i><span class="ml-text">Giacenze Articoli</span><i class="material-icons ml-star">star_border</i></a>
<a href="/warehouse" class="menu-link"><i class="material-icons ml-icon mtype-print">warning</i><span class="ml-text">Articoli Sotto Scorta</span><i class="material-icons ml-star">star_border</i></a>
<a href="/warehouse" class="menu-link"><i class="material-icons ml-icon mtype-list">euro</i><span class="ml-text">Valorizzazione Magazzino</span><i class="material-icons ml-star">star_border</i></a>
</div>
</div>
<div class="menu-card">
<div class="menu-card-header"><h3>Tabelle</h3><span class="collapse-dot">○—</span></div>
<div class="menu-card-body">
<a href="/inventory-reasons" class="menu-link"><i class="material-icons ml-icon mtype-list">rule</i><span class="ml-text">Causali di Magazzino</span><i class="material-icons ml-star">star_border</i></a>
<a href="#" class="menu-link"><i class="material-icons ml-icon mtype-list">warehouse</i><span class="ml-text">Depositi</span><i class="material-icons ml-star">star_border</i></a>
<a href="#" class="menu-link"><i class="material-icons ml-icon mtype-list">place</i><span class="ml-text">Ubicazioni</span><i class="material-icons ml-star">star_border</i></a>
</div>
</div>
<div class="menu-card">
<div class="menu-card-header"><h3>Procedure</h3><span class="collapse-dot">○—</span></div>
<div class="menu-card-body">
<a href="#" class="menu-link"><i class="material-icons ml-icon mtype-proc">bolt</i><span class="ml-text">Inventario Fisico</span><i class="material-icons ml-star">star_border</i></a>
<a href="#" class="menu-link"><i class="material-icons ml-icon mtype-proc">bolt</i><span class="ml-text">Ricalcolo Giacenze</span><i class="material-icons ml-star">star_border</i></a>
</div>
</div>
</div>
{% endblock %}
+100
View File
@@ -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 %}
+67 -121
View File
@@ -1,68 +1,50 @@
{% extends "base.html" %}
{% block title %}Articoli - Mago4 Demo{% endblock %}
{% block page_title %}Articoli{% endblock %}
{% block window_tabs %}<a href="/products" class="window-tab active"><i class="material-icons">inventory_2</i> Articoli</a>{% endblock %}
{% block content %}
<div class="page-header">
<button class="btn btn-primary" onclick="openCreateProductModal()">
<i class="material-icons">add</i> Nuovo Articolo
</button>
{% if low_stock %}
<div class="alert alert-warning">
<i class="material-icons">warning</i>
{{ low_stock|length }} articolo/i sotto la soglia di riordino
</div>
{% endif %}
<div class="module-bar">
<div class="module-title">Articoli</div>
<div class="breadcrumb"><a href="/">Mago4</a><span class="sep">»</span><a href="/anagrafiche">Anagrafiche</a><span class="sep">»</span><span class="current">Articoli</span></div>
</div>
<div class="tab-strip">
<a href="/anagrafiche">Anagrafiche</a>
<a href="/customers">Clienti</a>
<a href="/suppliers">Fornitori</a>
<a href="/products" class="active">Articoli</a>
</div>
<div class="widget-card">
<div class="widget-header">
<h3 class="widget-title">Catalogo Articoli</h3>
</div>
<div class="widget-body">
<div class="doc-toolbar">
<button class="tb-btn" title="Nuovo" onclick="alert('Nuovo articolo (demo)')"><i class="material-icons">add_box</i></button>
<button class="tb-btn" title="Cerca"><i class="material-icons">search</i></button>
<div class="tb-sep"></div>
<button class="tb-btn" title="Stampa"><i class="material-icons">print</i></button>
</div>
<div class="content-pad">
{% if low_stock %}
<div class="alert alert-warning"><i class="material-icons">warning</i> {{ low_stock|length }} articolo/i sotto la scorta minima</div>
{% endif %}
<div class="panel">
<div class="panel-header"><h3><i class="material-icons">inventory_2</i> Catalogo Articoli</h3></div>
<table class="data-table">
<thead>
<tr>
<th>Codice</th>
<th>Descrizione</th>
<th>Categoria</th>
<th>Prezzo Unitario</th>
<th>Giacenza</th>
<th>Soglia Riordino</th>
<th>Fornitore</th>
<th>Azioni</th>
</tr>
</thead>
<thead><tr><th>Codice</th><th>Descrizione</th><th>Categoria</th><th class="text-center">UM</th><th class="text-right">Prezzo Vend.</th><th class="text-right">Costo</th><th class="text-center">IVA</th><th class="text-right">Giacenza</th><th></th></tr></thead>
<tbody>
{% for product in products %}
<tr class="{% if product.quantity_in_stock <= product.reorder_level %}low-stock{% endif %}">
<td><strong>{{ product.code }}</strong></td>
<td>{{ product.description }}</td>
<td>{{ product.category }}</td>
<td class="text-right">{{ "%.2f"|format(product.unit_price) }}</td>
<td class="text-right {% if product.quantity_in_stock <= product.reorder_level %}text-danger{% endif %}">
{{ product.quantity_in_stock }}
{% if product.quantity_in_stock <= product.reorder_level %}
<i class="material-icons small-icon">warning</i>
{% endif %}
</td>
<td class="text-right">{{ product.reorder_level }}</td>
<td>
{% if product.supplier_id %}
Fornitore #{{ product.supplier_id }}
{% else %}
{% endif %}
</td>
<td>
<button class="btn-small btn-info" onclick="viewProduct({{ product.id }})">
<i class="material-icons">visibility</i>
</button>
<button class="btn-small btn-warning" onclick="editProduct({{ product.id }})">
<i class="material-icons">edit</i>
</button>
{% for p in products %}
<tr class="{% if p.quantity_in_stock <= p.reorder_level %}low-stock{% endif %}">
<td class="text-bold mono">{{ p.code }}</td>
<td>{{ p.description }}</td>
<td>{{ p.category }}</td>
<td class="text-center">{{ p.uom }}</td>
<td class="text-right">€ {{ "%.2f"|format(p.unit_price) }}</td>
<td class="text-right text-mute">€ {{ "%.2f"|format(p.purchase_price) }}</td>
<td class="text-center">{{ "%.0f"|format(p.tax_rate) }}%</td>
<td class="text-right {% if p.quantity_in_stock <= p.reorder_level %}text-danger text-bold{% endif %}">
{{ p.quantity_in_stock }} {{ p.uom }}
{% if p.quantity_in_stock <= p.reorder_level %}<i class="material-icons" style="font-size:14px;vertical-align:middle;">warning</i>{% endif %}
</td>
<td class="text-center"><button class="btn-icon-sm act-view" onclick="viewProduct({{ p.id }})"><i class="material-icons">visibility</i></button></td>
</tr>
{% endfor %}
</tbody>
@@ -70,75 +52,39 @@
</div>
</div>
<div id="productModal" class="modal" onclick="closeModal(event)">
<div class="modal-content" onclick="event.stopPropagation()">
<div class="modal-header">
<h2 id="modalTitle">Dettagli Articolo</h2>
<button class="btn-close" onclick="closeModal()">
<i class="material-icons">close</i>
</button>
</div>
<div class="modal-body" id="modalBody">
</div>
<div id="genericModal" class="modal" onclick="if(event.target.id==='genericModal')closeGenericModal()">
<div class="modal-content">
<div class="modal-header"><h2 id="gmTitle">Dettagli</h2><button class="modal-close" onclick="closeGenericModal()"><i class="material-icons">close</i></button></div>
<div class="modal-body" id="gmBody"></div>
</div>
</div>
<script>
function viewProduct(productId) {
fetch(`/api/products/${productId}`)
.then(r => r.json())
.then(data => {
const isLowStock = data.quantity_in_stock <= data.reorder_level;
document.getElementById('modalTitle').textContent = `Articolo: ${data.code}`;
document.getElementById('modalBody').innerHTML = `
<div class="detail-grid">
<div class="detail-item">
<label>Codice</label>
<span>${data.code}</span>
</div>
<div class="detail-item">
<label>Descrizione</label>
<span>${data.description}</span>
</div>
<div class="detail-item">
<label>Categoria</label>
<span>${data.category}</span>
</div>
<div class="detail-item">
<label>Prezzo Unitario</label>
<span>€ ${data.unit_price.toFixed(2)}</span>
</div>
<div class="detail-item">
<label>Giacenza Attuale</label>
<span class="${isLowStock ? 'text-danger' : ''}">
${data.quantity_in_stock} ${isLowStock ? '⚠️ SOTTOSORTA' : ''}
</span>
</div>
<div class="detail-item">
<label>Soglia Riordino</label>
<span>${data.reorder_level}</span>
</div>
<div class="detail-item">
<label>Fornitore</label>
<span>${data.supplier_id ? 'Fornitore #' + data.supplier_id : '—'}</span>
</div>
</div>
`;
document.getElementById('productModal').classList.add('show');
});
}
function editProduct(productId) {
alert('Modifica articolo: ' + productId + ' (da implementare)');
}
function openCreateProductModal() {
alert('Creazione nuovo articolo (da implementare)');
}
function closeModal(event) {
if (event && event.target.id !== 'productModal') return;
document.getElementById('productModal').classList.remove('show');
function viewProduct(id) {
fetch(`/api/products/${id}`).then(r=>r.json()).then(d=>{
const low = d.quantity_in_stock <= d.reorder_level;
openGenericModal('Articolo: ' + d.code, `
<div style="padding:16px">
<div class="form-section-title">Dati Principali</div>
<div class="form-grid-2">
${field('Codice', d.code)}${field('Descrizione', d.description)}
${field('Categoria', d.category)}${field('Unità di Misura', d.uom)}
</div>
<div class="form-section-title">Dati Commerciali</div>
<div class="form-grid-2">
${field('Prezzo di Vendita', '€ ' + d.unit_price.toFixed(2))}
${field('Costo di Acquisto', '€ ' + d.purchase_price.toFixed(2))}
${field('Aliquota IVA', d.tax_rate.toFixed(0) + '%')}
</div>
<div class="form-section-title">Dati Magazzino</div>
<div class="form-grid-2">
${field('Giacenza', '<span class="' + (low?'text-danger text-bold':'') + '">' + d.quantity_in_stock + ' ' + d.uom + (low?' ⚠ sottoscorta':'') + '</span>')}
${field('Scorta Minima', d.reorder_level + ' ' + d.uom)}
${field('Scorta Massima', d.max_stock + ' ' + d.uom)}
${field('Valore Giacenza', '€ ' + (d.quantity_in_stock * d.purchase_price).toFixed(2))}
</div>
</div>`);
});
}
</script>
{% endblock %}
+49 -123
View File
@@ -1,60 +1,40 @@
{% extends "base.html" %}
{% block title %}Ordini Acquisto - Mago4 Demo{% endblock %}
{% block page_title %}Ordini Acquisto{% endblock %}
{% block title %}Ordini Fornitore - Mago4 Demo{% endblock %}
{% block window_tabs %}<a href="/purchase-orders" class="window-tab active"><i class="material-icons">shopping_cart</i> Ordini Fornitore</a>{% endblock %}
{% block content %}
<div class="page-header">
<button class="btn btn-primary" onclick="openCreateOrderModal()">
<i class="material-icons">add</i> Nuovo Ordine
</button>
{% if pending %}
<div class="alert alert-info">
<i class="material-icons">info</i>
{{ pending|length }} ordine/i in sospeso
</div>
{% endif %}
<div class="module-bar">
<div class="module-title">Ordini Fornitore</div>
<div class="breadcrumb"><a href="/">Mago4</a><span class="sep">»</span><a href="/acquisti">Acquisti</a><span class="sep">»</span><span class="current">Ordini Fornitore</span></div>
</div>
<div class="tab-strip">
<a href="/purchase-orders" class="active">Ordini Fornitore</a>
<a href="/acquisti">Documenti Acquisto</a>
</div>
<div class="widget-card">
<div class="widget-header">
<h3 class="widget-title">Elenco Ordini Acquisto</h3>
</div>
<div class="widget-body">
<div class="doc-toolbar">
<button class="tb-btn" title="Nuovo" onclick="alert('Nuovo ordine (demo)')"><i class="material-icons">add_box</i></button>
<button class="tb-btn" title="Cerca"><i class="material-icons">search</i></button>
<div class="tb-sep"></div>
<button class="tb-btn" title="Stampa"><i class="material-icons">print</i></button>
</div>
<div class="content-pad">
{% if pending %}<div class="alert alert-info"><i class="material-icons">info</i> {{ pending|length }} ordine/i in sospeso</div>{% endif %}
<div class="panel">
<div class="panel-header"><h3><i class="material-icons">shopping_cart</i> Elenco Ordini Fornitore</h3></div>
<table class="data-table">
<thead>
<tr>
<th>Data</th>
<th>Numero Ordine</th>
<th>Fornitore</th>
<th>Importo Totale</th>
<th>Data Consegna Prevista</th>
<th>Stato</th>
<th>Azioni</th>
</tr>
</thead>
<thead><tr><th>Data</th><th>Numero</th><th>Fornitore</th><th class="text-right">Importo</th><th>Consegna Prevista</th><th>Stato</th><th></th></tr></thead>
<tbody>
{% for order in orders %}
{% for o in orders %}
<tr>
<td>{{ order.order_date.strftime("%d/%m/%Y") }}</td>
<td><strong>{{ order.order_number }}</strong></td>
<td>{{ order.supplier_name }}</td>
<td class="text-right">€ {{ "%.2f"|format(order.total_amount) }}</td>
<td>
{% if order.expected_delivery_date %}
{{ order.expected_delivery_date.strftime("%d/%m/%Y") }}
{% else %}
{% endif %}
</td>
<td>
<span class="badge status-{{ order.status.value }}">{{ order.status.value }}</span>
</td>
<td>
<button class="btn-small btn-info" onclick="viewOrder({{ order.id }})">
<i class="material-icons">visibility</i>
</button>
</td>
<td>{{ o.order_date.strftime("%d/%m/%Y") }}</td>
<td class="text-bold mono">{{ o.order_number }}</td>
<td>{{ o.supplier_name }}</td>
<td class="text-right">€ {{ "%.2f"|format(o.total_amount) }}</td>
<td>{{ o.expected_delivery_date.strftime("%d/%m/%Y") if o.expected_delivery_date else '—' }}</td>
<td><span class="badge status-{{ o.status.value }}">{{ o.status.value }}</span></td>
<td class="text-center"><button class="btn-icon-sm act-view" onclick="viewOrder({{ o.id }})"><i class="material-icons">visibility</i></button></td>
</tr>
{% endfor %}
</tbody>
@@ -62,84 +42,30 @@
</div>
</div>
<div id="orderModal" class="modal" onclick="closeModal(event)">
<div class="modal-content" onclick="event.stopPropagation()">
<div class="modal-header">
<h2 id="modalTitle">Dettagli Ordine Acquisto</h2>
<button class="btn-close" onclick="closeModal()">
<i class="material-icons">close</i>
</button>
</div>
<div class="modal-body" id="modalBody">
</div>
<div id="genericModal" class="modal" onclick="if(event.target.id==='genericModal')closeGenericModal()">
<div class="modal-content">
<div class="modal-header"><h2 id="gmTitle">Ordine</h2><button class="modal-close" onclick="closeGenericModal()"><i class="material-icons">close</i></button></div>
<div class="modal-body" id="gmBody"></div>
</div>
</div>
<script>
function viewOrder(orderId) {
fetch(`/api/purchase-orders/${orderId}`)
.then(r => r.json())
.then(data => {
const deliveryDate = data.expected_delivery_date ? new Date(data.expected_delivery_date).toLocaleDateString('it-IT') : '—';
const orderDate = new Date(data.order_date).toLocaleDateString('it-IT');
let linesHtml = '<table class="data-table-nested"><thead><tr><th>Articolo</th><th>Quantità</th><th>Prezzo Unit.</th><th>Totale</th></tr></thead><tbody>';
data.lines.forEach(line => {
linesHtml += `<tr>
<td>${line.product_description} (${line.product_code})</td>
<td class="text-right">${line.quantity}</td>
<td class="text-right">€ ${line.unit_price.toFixed(2)}</td>
<td class="text-right">€ ${line.total_amount.toFixed(2)}</td>
</tr>`;
});
linesHtml += '</tbody></table>';
document.getElementById('modalTitle').textContent = `Ordine: ${data.order_number}`;
document.getElementById('modalBody').innerHTML = `
<div class="detail-grid">
<div class="detail-item">
<label>Numero Ordine</label>
<span>${data.order_number}</span>
</div>
<div class="detail-item">
<label>Data Ordine</label>
<span>${orderDate}</span>
</div>
<div class="detail-item">
<label>Fornitore</label>
<span>${data.supplier_name}</span>
</div>
<div class="detail-item">
<label>Stato</label>
<span class="badge status-${data.status}">
${data.status.replace('_', ' ').toUpperCase()}
</span>
</div>
<div class="detail-item">
<label>Data Consegna Prevista</label>
<span>${deliveryDate}</span>
</div>
<div class="detail-item">
<label>Importo Totale</label>
<span class="text-orange" style="font-size: 1.2em; font-weight: bold;">€ ${data.total_amount.toFixed(2)}</span>
</div>
</div>
<div style="margin-top: 20px;">
<h4>Righe Ordine</h4>
${linesHtml}
</div>
`;
document.getElementById('orderModal').classList.add('show');
});
}
function openCreateOrderModal() {
alert('Creazione nuovo ordine (da implementare)');
}
function closeModal(event) {
if (event && event.target.id !== 'orderModal') return;
document.getElementById('orderModal').classList.remove('show');
function viewOrder(id) {
fetch(`/api/purchase-orders/${id}`).then(r=>r.json()).then(d=>{
let rows = d.lines.map(l=>`<tr><td>${l.product_description} <span class="text-mute">(${l.product_code})</span></td>
<td class="text-right">${l.quantity}</td><td class="text-right">€ ${l.unit_price.toFixed(2)}</td>
<td class="text-right">€ ${l.total_amount.toFixed(2)}</td></tr>`).join('');
openGenericModal('Ordine: ' + d.order_number, `
<div style="padding:16px">
<div class="form-grid-2">
${field('Numero Ordine', d.order_number)}${field('Data', fmtDate(d.order_date))}
${field('Fornitore', d.supplier_name)}${field('Stato', d.status)}
${field('Consegna Prevista', fmtDate(d.expected_delivery_date))}${field('Totale', '€ ' + d.total_amount.toFixed(2))}
</div>
<div class="form-section-title">Righe Ordine</div>
<table class="data-table-nested"><thead><tr><th>Articolo</th><th class="text-right">Q.tà</th><th class="text-right">Prezzo</th><th class="text-right">Totale</th></tr></thead><tbody>${rows}</tbody></table>
</div>`);
});
}
</script>
{% endblock %}
+49 -123
View File
@@ -1,60 +1,40 @@
{% extends "base.html" %}
{% block title %}Ordini Vendita - Mago4 Demo{% endblock %}
{% block page_title %}Ordini Vendita{% endblock %}
{% block title %}Ordini Cliente - Mago4 Demo{% endblock %}
{% block window_tabs %}<a href="/sales-orders" class="window-tab active"><i class="material-icons">receipt_long</i> Ordini Cliente</a>{% endblock %}
{% block content %}
<div class="page-header">
<button class="btn btn-primary" onclick="openCreateOrderModal()">
<i class="material-icons">add</i> Nuovo Ordine
</button>
{% if pending %}
<div class="alert alert-info">
<i class="material-icons">info</i>
{{ pending|length }} ordine/i in sospeso
</div>
{% endif %}
<div class="module-bar">
<div class="module-title">Ordini Cliente</div>
<div class="breadcrumb"><a href="/">Mago4</a><span class="sep">»</span><a href="/vendite">Vendite</a><span class="sep">»</span><span class="current">Ordini Cliente</span></div>
</div>
<div class="tab-strip">
<a href="/sales-orders" class="active">Ordini Cliente</a>
<a href="/vendite">Documenti Vendita</a>
</div>
<div class="widget-card">
<div class="widget-header">
<h3 class="widget-title">Elenco Ordini Vendita</h3>
</div>
<div class="widget-body">
<div class="doc-toolbar">
<button class="tb-btn" title="Nuovo" onclick="alert('Nuovo ordine (demo)')"><i class="material-icons">add_box</i></button>
<button class="tb-btn" title="Cerca"><i class="material-icons">search</i></button>
<div class="tb-sep"></div>
<button class="tb-btn" title="Stampa"><i class="material-icons">print</i></button>
</div>
<div class="content-pad">
{% if pending %}<div class="alert alert-info"><i class="material-icons">info</i> {{ pending|length }} ordine/i in sospeso</div>{% endif %}
<div class="panel">
<div class="panel-header"><h3><i class="material-icons">receipt_long</i> Elenco Ordini Cliente</h3></div>
<table class="data-table">
<thead>
<tr>
<th>Data</th>
<th>Numero Ordine</th>
<th>Cliente</th>
<th>Importo Totale</th>
<th>Data Consegna</th>
<th>Stato</th>
<th>Azioni</th>
</tr>
</thead>
<thead><tr><th>Data</th><th>Numero</th><th>Cliente</th><th class="text-right">Importo</th><th>Consegna</th><th>Stato</th><th></th></tr></thead>
<tbody>
{% for order in orders %}
{% for o in orders %}
<tr>
<td>{{ order.order_date.strftime("%d/%m/%Y") }}</td>
<td><strong>{{ order.order_number }}</strong></td>
<td>{{ order.customer_name }}</td>
<td class="text-right">€ {{ "%.2f"|format(order.total_amount) }}</td>
<td>
{% if order.delivery_date %}
{{ order.delivery_date.strftime("%d/%m/%Y") }}
{% else %}
{% endif %}
</td>
<td>
<span class="badge status-{{ order.status.value }}">{{ order.status.value }}</span>
</td>
<td>
<button class="btn-small btn-info" onclick="viewOrder({{ order.id }})">
<i class="material-icons">visibility</i>
</button>
</td>
<td>{{ o.order_date.strftime("%d/%m/%Y") }}</td>
<td class="text-bold mono">{{ o.order_number }}</td>
<td>{{ o.customer_name }}</td>
<td class="text-right">€ {{ "%.2f"|format(o.total_amount) }}</td>
<td>{{ o.delivery_date.strftime("%d/%m/%Y") if o.delivery_date else '—' }}</td>
<td><span class="badge status-{{ o.status.value }}">{{ o.status.value }}</span></td>
<td class="text-center"><button class="btn-icon-sm act-view" onclick="viewOrder({{ o.id }})"><i class="material-icons">visibility</i></button></td>
</tr>
{% endfor %}
</tbody>
@@ -62,84 +42,30 @@
</div>
</div>
<div id="orderModal" class="modal" onclick="closeModal(event)">
<div class="modal-content" onclick="event.stopPropagation()">
<div class="modal-header">
<h2 id="modalTitle">Dettagli Ordine Vendita</h2>
<button class="btn-close" onclick="closeModal()">
<i class="material-icons">close</i>
</button>
</div>
<div class="modal-body" id="modalBody">
</div>
<div id="genericModal" class="modal" onclick="if(event.target.id==='genericModal')closeGenericModal()">
<div class="modal-content">
<div class="modal-header"><h2 id="gmTitle">Ordine</h2><button class="modal-close" onclick="closeGenericModal()"><i class="material-icons">close</i></button></div>
<div class="modal-body" id="gmBody"></div>
</div>
</div>
<script>
function viewOrder(orderId) {
fetch(`/api/sales-orders/${orderId}`)
.then(r => r.json())
.then(data => {
const deliveryDate = data.delivery_date ? new Date(data.delivery_date).toLocaleDateString('it-IT') : '—';
const orderDate = new Date(data.order_date).toLocaleDateString('it-IT');
let linesHtml = '<table class="data-table-nested"><thead><tr><th>Articolo</th><th>Quantità</th><th>Prezzo Unit.</th><th>Totale</th></tr></thead><tbody>';
data.lines.forEach(line => {
linesHtml += `<tr>
<td>${line.product_description} (${line.product_code})</td>
<td class="text-right">${line.quantity}</td>
<td class="text-right">€ ${line.unit_price.toFixed(2)}</td>
<td class="text-right">€ ${line.total_amount.toFixed(2)}</td>
</tr>`;
});
linesHtml += '</tbody></table>';
document.getElementById('modalTitle').textContent = `Ordine: ${data.order_number}`;
document.getElementById('modalBody').innerHTML = `
<div class="detail-grid">
<div class="detail-item">
<label>Numero Ordine</label>
<span>${data.order_number}</span>
</div>
<div class="detail-item">
<label>Data Ordine</label>
<span>${orderDate}</span>
</div>
<div class="detail-item">
<label>Cliente</label>
<span>${data.customer_name}</span>
</div>
<div class="detail-item">
<label>Stato</label>
<span class="badge status-${data.status}">
${data.status.replace('_', ' ').toUpperCase()}
</span>
</div>
<div class="detail-item">
<label>Data Consegna Prevista</label>
<span>${deliveryDate}</span>
</div>
<div class="detail-item">
<label>Importo Totale</label>
<span class="text-success" style="font-size: 1.2em; font-weight: bold;">€ ${data.total_amount.toFixed(2)}</span>
</div>
</div>
<div style="margin-top: 20px;">
<h4>Righe Ordine</h4>
${linesHtml}
</div>
`;
document.getElementById('orderModal').classList.add('show');
});
}
function openCreateOrderModal() {
alert('Creazione nuovo ordine (da implementare)');
}
function closeModal(event) {
if (event && event.target.id !== 'orderModal') return;
document.getElementById('orderModal').classList.remove('show');
function viewOrder(id) {
fetch(`/api/sales-orders/${id}`).then(r=>r.json()).then(d=>{
let rows = d.lines.map(l=>`<tr><td>${l.product_description} <span class="text-mute">(${l.product_code})</span></td>
<td class="text-right">${l.quantity}</td><td class="text-right">€ ${l.unit_price.toFixed(2)}</td>
<td class="text-right">€ ${l.total_amount.toFixed(2)}</td></tr>`).join('');
openGenericModal('Ordine: ' + d.order_number, `
<div style="padding:16px">
<div class="form-grid-2">
${field('Numero Ordine', d.order_number)}${field('Data', fmtDate(d.order_date))}
${field('Cliente', d.customer_name)}${field('Stato', d.status)}
${field('Consegna Prevista', fmtDate(d.delivery_date))}${field('Totale', '€ ' + d.total_amount.toFixed(2))}
</div>
<div class="form-section-title">Righe Ordine</div>
<table class="data-table-nested"><thead><tr><th>Articolo</th><th class="text-right">Q.tà</th><th class="text-right">Prezzo</th><th class="text-right">Totale</th></tr></thead><tbody>${rows}</tbody></table>
</div>`);
});
}
</script>
{% endblock %}
+78
View File
@@ -0,0 +1,78 @@
{% extends "base.html" %}
{% block title %}Scadenzario - Mago4 Demo{% endblock %}
{% block window_tabs %}<a href="/scadenzario" class="window-tab active"><i class="material-icons">event_note</i> Scadenzario</a>{% 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">Scadenzario — Partite Aperte</div>
<div class="breadcrumb"><a href="/">Mago4</a><span class="sep">»</span><a href="/amministrazione">Amministrazione</a><span class="sep">»</span><span class="current">Scadenzario</span></div>
</div>
<div class="tab-strip">
<a href="/scadenzario" class="{% if selected_type == 'all' %}active{% endif %}">Tutte</a>
<a href="/scadenzario?type=receivable" class="{% if selected_type == 'receivable' %}active{% endif %}">Incassi (Crediti)</a>
<a href="/scadenzario?type=payable" class="{% if selected_type == 'payable' %}active{% endif %}">Pagamenti (Debiti)</a>
</div>
<div class="doc-toolbar">
<button class="tb-btn" title="Nuova partita" onclick="alert('Nuova partita (demo)')"><i class="material-icons">add_box</i></button>
<button class="tb-btn" title="Cerca"><i class="material-icons">search</i></button>
<div class="tb-sep"></div>
<button class="tb-btn" title="Stampa scadenzario"><i class="material-icons">print</i></button>
<button class="tb-btn" title="Presentazione effetti"><i class="material-icons">request_page</i></button>
</div>
<div class="content-pad">
<div class="panel">
<div class="panel-header"><h3><i class="material-icons">event_note</i> Partite ({{ schedules|length }})</h3></div>
<table class="data-table">
<thead><tr><th>Tipo</th><th>Scadenza</th><th class="text-center">Giorni</th><th>Cliente/Fornitore</th><th>Documento</th><th class="text-center">Modalità</th><th class="text-right">Importo</th><th class="text-center">Stato</th><th></th></tr></thead>
<tbody>
{% for s in schedules %}
{% set st = sched_status(s) %}
{% set days = sched_days(s) %}
<tr {% if st == 'overdue' %}class="low-stock"{% endif %}>
<td>
{% if s.type == RECEIVABLE %}<span class="badge badge-load"><i class="material-icons">south_west</i> Incasso</span>
{% else %}<span class="badge badge-unload"><i class="material-icons">north_east</i> Pagamento</span>{% endif %}
</td>
<td class="text-bold">{{ s.due_date.strftime("%d/%m/%Y") }}</td>
<td class="text-center">
{% if s.closed %}<span class="text-mute"></span>
{% elif days < 0 %}<span class="text-danger text-bold">{{ days }}</span>
{% elif days <= 7 %}<span class="text-warning text-bold">+{{ days }}</span>
{% else %}<span class="text-mute">+{{ days }}</span>{% endif %}
</td>
<td>{{ s.custsupp_name }}</td>
<td><span class="mono">{{ s.doc_no }}</span>{% if s.is_credit_note %} <span class="badge badge-grey">NC</span>{% endif %}</td>
<td class="text-center">{{ s.payment_method }}</td>
<td class="text-right text-bold {% if s.is_credit_note %}text-danger{% endif %}">
{% if s.is_credit_note %}{% endif %}€ {{ "%.2f"|format(s.amount) }}
</td>
<td class="text-center"><span class="badge {{ status_badge[st] }}">{{ status_label[st] }}</span></td>
<td class="text-center">
{% if not s.closed %}
<button class="btn-icon-sm act-cart" title="{{ 'Registra incasso' if s.type == RECEIVABLE else 'Registra pagamento' }}" onclick="settle({{ s.id }})"><i class="material-icons">task_alt</i></button>
{% else %}
<i class="material-icons text-success" style="font-size:17px;" title="Saldata">check_circle</i>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<script>
function settle(id) {
if (!confirm('Registrare l\'avvenuto pagamento/incasso della partita?')) return;
fetch(`/scadenzario/${id}/settle`, { method: 'POST' })
.then(r => r.json())
.then(() => { showNotification('Partita saldata'); setTimeout(() => location.reload(), 700); })
.catch(() => showNotification('Errore', 'error'));
}
</script>
{% endblock %}
+51 -111
View File
@@ -1,53 +1,42 @@
{% extends "base.html" %}
{% block title %}Fornitori - Mago4 Demo{% endblock %}
{% block page_title %}Fornitori{% endblock %}
{% block window_tabs %}<a href="/suppliers" class="window-tab active"><i class="material-icons">local_shipping</i> Fornitori</a>{% endblock %}
{% block content %}
<div class="page-header">
<button class="btn btn-primary" onclick="openCreateSupplierModal()">
<i class="material-icons">add</i> Nuovo Fornitore
</button>
<div class="module-bar">
<div class="module-title">Fornitori</div>
<div class="breadcrumb"><a href="/">Mago4</a><span class="sep">»</span><a href="/anagrafiche">Anagrafiche</a><span class="sep">»</span><span class="current">Fornitori</span></div>
</div>
<div class="tab-strip">
<a href="/anagrafiche">Anagrafiche</a>
<a href="/customers">Clienti</a>
<a href="/suppliers" class="active">Fornitori</a>
<a href="/products">Articoli</a>
</div>
<div class="widget-card">
<div class="widget-header">
<h3 class="widget-title">Elenco Fornitori</h3>
</div>
<div class="widget-body">
<div class="doc-toolbar">
<button class="tb-btn" title="Nuovo" onclick="alert('Nuovo fornitore (demo)')"><i class="material-icons">add_box</i></button>
<button class="tb-btn" title="Cerca"><i class="material-icons">search</i></button>
<div class="tb-sep"></div>
<button class="tb-btn" title="Stampa"><i class="material-icons">print</i></button>
</div>
<div class="content-pad">
<div class="panel">
<div class="panel-header"><h3><i class="material-icons">local_shipping</i> Elenco Fornitori</h3></div>
<table class="data-table">
<thead>
<tr>
<th>Codice</th>
<th>Ragione Sociale</th>
<th>Città</th>
<th>Paese</th>
<th>Telefono</th>
<th>Termini Pagamento</th>
<th>Saldo</th>
<th>Azioni</th>
</tr>
</thead>
<thead><tr><th>Codice</th><th>Ragione Sociale</th><th>Partita IVA</th><th>Città</th><th>Paese</th><th class="text-center">Pagamento</th><th class="text-right">Saldo</th><th></th></tr></thead>
<tbody>
{% for supplier in suppliers %}
{% for s in suppliers %}
<tr>
<td><strong>{{ supplier.code }}</strong></td>
<td>{{ supplier.name }}</td>
<td>{{ supplier.city }}</td>
<td>{{ supplier.country }}</td>
<td>{{ supplier.phone }}</td>
<td class="text-center">{{ supplier.payment_terms_days }} gg</td>
<td class="text-right {% if supplier.balance > 0 %}text-warning{% endif %}">
€ {{ "%.2f"|format(supplier.balance) }}
</td>
<td>
<button class="btn-small btn-info" onclick="viewSupplier({{ supplier.id }})">
<i class="material-icons">visibility</i>
</button>
<button class="btn-small btn-warning" onclick="editSupplier({{ supplier.id }})">
<i class="material-icons">edit</i>
</button>
</td>
<td class="text-bold mono">{{ s.code }}</td>
<td>{{ s.name }}</td>
<td class="mono">{{ s.vat_number or '—' }}</td>
<td>{{ s.city }}</td>
<td>{{ s.country }}</td>
<td class="text-center">{{ s.payment_terms_days }} gg</td>
<td class="text-right {% if s.balance > 0 %}text-warning{% endif %}">€ {{ "%.2f"|format(s.balance) }}</td>
<td class="text-center"><button class="btn-icon-sm act-view" onclick="viewSupplier({{ s.id }})"><i class="material-icons">visibility</i></button></td>
</tr>
{% endfor %}
</tbody>
@@ -55,80 +44,31 @@
</div>
</div>
<div id="supplierModal" class="modal" onclick="closeModal(event)">
<div class="modal-content" onclick="event.stopPropagation()">
<div class="modal-header">
<h2 id="modalTitle">Dettagli Fornitore</h2>
<button class="btn-close" onclick="closeModal()">
<i class="material-icons">close</i>
</button>
</div>
<div class="modal-body" id="modalBody">
</div>
<div id="genericModal" class="modal" onclick="if(event.target.id==='genericModal')closeGenericModal()">
<div class="modal-content">
<div class="modal-header"><h2 id="gmTitle">Dettagli</h2><button class="modal-close" onclick="closeGenericModal()"><i class="material-icons">close</i></button></div>
<div class="modal-body" id="gmBody"></div>
</div>
</div>
<script>
function viewSupplier(supplierId) {
fetch(`/api/suppliers/${supplierId}`)
.then(r => r.json())
.then(data => {
document.getElementById('modalTitle').textContent = `Fornitore: ${data.name}`;
document.getElementById('modalBody').innerHTML = `
<div class="detail-grid">
<div class="detail-item">
<label>Codice</label>
<span>${data.code}</span>
</div>
<div class="detail-item">
<label>Ragione Sociale</label>
<span>${data.name}</span>
</div>
<div class="detail-item">
<label>Email</label>
<span>${data.email}</span>
</div>
<div class="detail-item">
<label>Telefono</label>
<span>${data.phone}</span>
</div>
<div class="detail-item">
<label>Indirizzo</label>
<span>${data.address}</span>
</div>
<div class="detail-item">
<label>Città</label>
<span>${data.city}</span>
</div>
<div class="detail-item">
<label>Paese</label>
<span>${data.country}</span>
</div>
<div class="detail-item">
<label>Termini Pagamento</label>
<span>${data.payment_terms_days} giorni</span>
</div>
<div class="detail-item">
<label>Saldo Debito</label>
<span class="${data.balance > 0 ? 'text-warning' : ''}">€ ${data.balance.toFixed(2)}</span>
</div>
</div>
`;
document.getElementById('supplierModal').classList.add('show');
});
}
function editSupplier(supplierId) {
alert('Modifica fornitore: ' + supplierId + ' (da implementare)');
}
function openCreateSupplierModal() {
alert('Creazione nuovo fornitore (da implementare)');
}
function closeModal(event) {
if (event && event.target.id !== 'supplierModal') return;
document.getElementById('supplierModal').classList.remove('show');
function viewSupplier(id) {
fetch(`/api/suppliers/${id}`).then(r=>r.json()).then(d=>{
openGenericModal('Fornitore: ' + d.name, `
<div style="padding:16px">
<div class="form-section-title">Dati Principali</div>
<div class="form-grid-2">
${field('Codice', d.code)}${field('Ragione Sociale', d.name)}
${field('Partita IVA', d.vat_number || '—')}${field('Email', d.email)}
${field('Telefono', d.phone)}${field('Termini Pagamento', d.payment_terms_days + ' giorni')}
</div>
<div class="form-section-title">Indirizzo</div>
<div class="form-grid-2">
${field('Indirizzo', d.address)}${field('Città', d.city)}
${field('Paese', d.country)}${field('Saldo Debito', '€ ' + d.balance.toFixed(2))}
</div>
</div>`);
});
}
</script>
{% endblock %}
+53
View File
@@ -0,0 +1,53 @@
{% extends "base.html" %}
{% block title %}Vendite - Mago4 Demo{% endblock %}
{% block window_tabs %}<a href="/vendite" class="window-tab active"><i class="material-icons">point_of_sale</i> Vendite</a>{% endblock %}
{% block content %}
<div class="module-bar">
<div class="module-title">Documenti Vendita</div>
<div class="breadcrumb"><a href="/">Mago4</a><span class="sep">»</span><a href="/vendite">Vendite</a><span class="sep">»</span><span class="current">Documenti Vendita</span></div>
</div>
<div class="tab-strip">
<a href="/sales-orders">Ordini Cliente</a>
<a href="/vendite" class="active">Documenti Vendita</a>
<a href="#">Politiche Vendita</a>
<a href="#">Statistiche</a>
</div>
<div class="cards-grid">
<div class="menu-card">
<div class="menu-card-header"><h3>Fatture</h3><span class="collapse-dot">○—</span></div>
<div class="menu-card-body">
<a href="/invoices?type=immediate_invoice" class="menu-link"><i class="material-icons ml-icon mtype-form">request_quote</i><span class="ml-text">Fatture Immediate</span><i class="material-icons ml-star">star_border</i></a>
<a href="/invoices?type=accompanying_invoice" class="menu-link"><i class="material-icons ml-icon mtype-form">receipt</i><span class="ml-text">Fatture Accompagnatorie</span><i class="material-icons ml-star">star_border</i></a>
<a href="/invoices?type=proforma_invoice" class="menu-link"><i class="material-icons ml-icon mtype-list">description</i><span class="ml-text">Fatture ProForma</span><i class="material-icons ml-star">star_border</i></a>
<a href="/invoices" class="menu-link"><i class="material-icons ml-icon mtype-print">print</i><span class="ml-text">Portafoglio Clienti</span><i class="material-icons ml-star">star_border</i></a>
</div>
</div>
<div class="menu-card">
<div class="menu-card-header"><h3>Documenti di Trasporto</h3><span class="collapse-dot">○—</span></div>
<div class="menu-card-body">
<a href="/invoices?type=delivery_note" class="menu-link"><i class="material-icons ml-icon mtype-form">local_shipping</i><span class="ml-text">Documenti di Trasporto</span><i class="material-icons ml-star">star_border</i></a>
<a href="/invoices?type=delivery_note" class="menu-link"><i class="material-icons ml-icon mtype-list">list_alt</i><span class="ml-text">Lista Documenti di Trasporto</span><i class="material-icons ml-star">star_border</i></a>
</div>
</div>
<div class="menu-card">
<div class="menu-card-header"><h3>Note di Credito / Debito</h3><span class="collapse-dot">○—</span></div>
<div class="menu-card-body">
<a href="/invoices?type=credit_note" class="menu-link"><i class="material-icons ml-icon mtype-form">undo</i><span class="ml-text">Note di Credito</span><i class="material-icons ml-star">star_border</i></a>
<a href="/invoices?type=debit_note" class="menu-link"><i class="material-icons ml-icon mtype-form">redo</i><span class="ml-text">Note di Debito</span><i class="material-icons ml-star">star_border</i></a>
</div>
</div>
<div class="menu-card">
<div class="menu-card-header"><h3>Procedure</h3><span class="collapse-dot">○—</span></div>
<div class="menu-card-body">
<a href="#" class="menu-link"><i class="material-icons ml-icon mtype-proc">bolt</i><span class="ml-text">Fatturazione Differita DDT</span><i class="material-icons ml-star">star_border</i></a>
<a href="#" class="menu-link"><i class="material-icons ml-icon mtype-proc">bolt</i><span class="ml-text">Evasione Picking List</span><i class="material-icons ml-star">star_border</i></a>
<a href="#" class="menu-link"><i class="material-icons ml-icon mtype-print">bar_chart</i><span class="ml-text">Grafici di Fatturato</span><i class="material-icons ml-star">star_border</i></a>
</div>
</div>
</div>
{% endblock %}
+59 -119
View File
@@ -1,131 +1,77 @@
{% extends "base.html" %}
{% block title %}Magazzino - Mago4 Demo{% endblock %}
{% block page_title %}Magazzino{% endblock %}
{% block title %}Giacenze - Mago4 Demo{% endblock %}
{% block window_tabs %}<a href="/warehouse" class="window-tab active"><i class="material-icons">inventory</i> Giacenze</a>{% endblock %}
{% block content %}
<div class="page-header">
<div class="module-bar">
<div class="module-title">Giacenze Articoli</div>
<div class="breadcrumb"><a href="/">Mago4</a><span class="sep">»</span><a href="/magazzino">Logistica</a><span class="sep">»</span><span class="current">Giacenze</span></div>
</div>
<div class="tab-strip">
<a href="/magazzino">Magazzino</a>
<a href="/inventory-movements">Movimenti</a>
<a href="/warehouse" class="active">Giacenze</a>
<a href="/inventory-reasons">Causali</a>
</div>
<div class="content-pad">
<div class="kpi-grid">
<div class="kpi-card" style="border-left-color: var(--c-blue)">
<div class="kpi-title">Articoli in Catalogo</div>
<div class="kpi-row"><div class="kpi-icon"><i class="material-icons" style="color:var(--c-blue)">inventory_2</i></div><div class="kpi-value">{{ products|length }}</div></div>
</div>
<div class="kpi-card" style="border-left-color: var(--c-red)">
<div class="kpi-title">Articoli Sotto Scorta</div>
<div class="kpi-row"><div class="kpi-icon"><i class="material-icons" style="color:var(--c-red)">warning</i></div><div class="kpi-value">{{ low_stock|length }}</div></div>
</div>
<div class="kpi-card" style="border-left-color: var(--c-purple)">
<div class="kpi-title">Valore Magazzino (a costo)</div>
<div class="kpi-row"><div class="kpi-icon"><i class="material-icons" style="color:var(--c-purple)">euro_symbol</i></div><div class="kpi-value">€ {{ "{:,.0f}".format(warehouse_value) }}</div></div>
</div>
</div>
{% if low_stock %}
<div class="alert alert-danger" style="flex: 1;">
<i class="material-icons">error</i>
<strong>Attenzione!</strong> {{ low_stock|length }} articolo/i in sottosorta
</div>
{% endif %}
</div>
<!-- Summary Stats -->
<div class="widget-row" style="margin-bottom: 20px;">
<div class="widget-card stat-card" style="border-left-color: var(--color-blue)">
<div class="widget-header">
<h3 class="widget-title">Articoli in Catalogo</h3>
</div>
<div class="widget-body stat-body">
<div class="stat-value">{{ products|length }}</div>
</div>
</div>
<div class="widget-card stat-card" style="border-left-color: var(--color-red)">
<div class="widget-header">
<h3 class="widget-title">Articoli in Sottosorta</h3>
</div>
<div class="widget-body stat-body">
<div class="stat-icon" style="color: var(--color-red)">
<i class="material-icons">warning</i>
</div>
<div class="stat-value">{{ low_stock|length }}</div>
</div>
</div>
</div>
<!-- Low Stock Alert -->
{% if low_stock %}
<div class="widget-card">
<div class="widget-header">
<h3 class="widget-title">
<i class="material-icons">warning</i> Articoli Sotto Soglia Riordino
</h3>
</div>
<div class="widget-body">
<div class="panel">
<div class="panel-header"><h3><i class="material-icons" style="color:var(--c-red)">warning</i> Articoli Sotto Scorta Minima</h3></div>
<table class="data-table">
<thead>
<tr>
<th>Codice</th>
<th>Descrizione</th>
<th>Giacenza</th>
<th>Soglia Riordino</th>
<th>Scostamento</th>
<th>Azioni</th>
</tr>
</thead>
<thead><tr><th>Codice</th><th>Descrizione</th><th class="text-right">Giacenza</th><th class="text-right">Scorta Min.</th><th class="text-right">Da Riordinare</th><th></th></tr></thead>
<tbody>
{% for product in low_stock %}
<tr class="highlight-danger">
<td><strong>{{ product.code }}</strong></td>
<td>{{ product.description }}</td>
<td class="text-danger text-bold">{{ product.quantity_in_stock }}</td>
<td class="text-right">{{ product.reorder_level }}</td>
<td class="text-right text-danger">
-{{ product.reorder_level - product.quantity_in_stock }} unità
</td>
<td>
<button class="btn-small btn-primary" onclick="createPOForProduct({{ product.id }})">
<i class="material-icons">add_shopping_cart</i>
</button>
</td>
{% for p in low_stock %}
<tr class="low-stock">
<td class="text-bold mono">{{ p.code }}</td>
<td>{{ p.description }}</td>
<td class="text-right text-danger text-bold">{{ p.quantity_in_stock }} {{ p.uom }}</td>
<td class="text-right">{{ p.reorder_level }} {{ p.uom }}</td>
<td class="text-right text-danger">{{ p.max_stock - p.quantity_in_stock }} {{ p.uom }}</td>
<td class="text-center"><button class="btn-icon-sm act-cart" title="Genera ordine" onclick="alert('Genera ordine di acquisto (demo)')"><i class="material-icons">add_shopping_cart</i></button></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endif %}
{% endif %}
<!-- All Products -->
<div class="widget-card">
<div class="widget-header">
<h3 class="widget-title">Inventario Completo</h3>
</div>
<div class="widget-body">
<div class="panel">
<div class="panel-header"><h3><i class="material-icons">inventory</i> Inventario Completo — Deposito MAG01</h3></div>
<table class="data-table">
<thead>
<tr>
<th>Codice</th>
<th>Descrizione</th>
<th>Categoria</th>
<th>Giacenza</th>
<th>Soglia Riordino</th>
<th>Prezzo Unit.</th>
<th>Valore Magazzino</th>
<th>Stato</th>
</tr>
</thead>
<thead><tr><th>Codice</th><th>Descrizione</th><th>Categoria</th><th class="text-right">Giacenza</th><th class="text-right">Scorta Min.</th><th class="text-right">Costo Unit.</th><th class="text-right">Valore</th><th class="text-center">Stato</th></tr></thead>
<tbody>
{% for product in products %}
<tr class="{% if product.quantity_in_stock <= product.reorder_level %}low-stock{% endif %}">
<td><strong>{{ product.code }}</strong></td>
<td>{{ product.description }}</td>
<td>{{ product.category }}</td>
<td class="text-right {% if product.quantity_in_stock <= product.reorder_level %}text-danger text-bold{% endif %}">
{{ product.quantity_in_stock }}
</td>
<td class="text-right">{{ product.reorder_level }}</td>
<td class="text-right">€ {{ "%.2f"|format(product.unit_price) }}</td>
<td class="text-right text-bold">
€ {{ "%.2f"|format(product.quantity_in_stock * product.unit_price) }}
</td>
<td>
{% if product.quantity_in_stock <= product.reorder_level %}
<span class="badge badge-danger">
<i class="material-icons">warning</i> SOTTOSORTA
</span>
{% elif product.quantity_in_stock <= product.reorder_level + 20 %}
<span class="badge badge-warning">
<i class="material-icons">info</i> PROSSIMA SOGLIA
</span>
{% for p in products %}
<tr class="{% if p.quantity_in_stock <= p.reorder_level %}low-stock{% endif %}">
<td class="text-bold mono">{{ p.code }}</td>
<td>{{ p.description }}</td>
<td>{{ p.category }}</td>
<td class="text-right {% if p.quantity_in_stock <= p.reorder_level %}text-danger text-bold{% endif %}">{{ p.quantity_in_stock }} {{ p.uom }}</td>
<td class="text-right">{{ p.reorder_level }} {{ p.uom }}</td>
<td class="text-right text-mute">€ {{ "%.2f"|format(p.purchase_price) }}</td>
<td class="text-right text-bold">{{ "%.2f"|format(p.quantity_in_stock * p.purchase_price) }}</td>
<td class="text-center">
{% if p.quantity_in_stock <= p.reorder_level %}
<span class="badge badge-danger"><i class="material-icons">warning</i> Sottoscorta</span>
{% elif p.quantity_in_stock <= p.reorder_level + 20 %}
<span class="badge badge-warning"><i class="material-icons">info</i> In esaurimento</span>
{% else %}
<span class="badge badge-success">
<i class="material-icons">check</i> OK
</span>
<span class="badge badge-success"><i class="material-icons">check</i> OK</span>
{% endif %}
</td>
</tr>
@@ -134,10 +80,4 @@
</table>
</div>
</div>
<script>
function createPOForProduct(productId) {
alert('Creazione ordine di acquisto per articolo #' + productId + ' (da implementare)');
}
</script>
{% endblock %}