Sistema di Gestione Magazzino Basato su Inventari
Panoramica
Il sistema di gestione magazzino è basato su snapshot di inventario che rappresentano lo stato delle scorte in una data specifica. Le scorte correnti vengono calcolate automaticamente sottraendo i consumi (basati sulle vendite e le ricette) dall’ultimo inventario.
Concetti Chiave
1. Inventario Snapshot
Un inventario rappresenta una “fotografia” delle scorte in un momento specifico. Ogni inventario contiene:
- Data snapshot: quando è stato effettuato il conteggio
- Prodotti: lista di prodotti con quantità in confezioni
- Note: informazioni aggiuntive sul conteggio
- Responsabile: chi ha eseguito il conteggio
2. Calcolo Consumi
Il sistema calcola automaticamente quante confezioni sono state consumate dall’ultimo inventario:
Esempio pratico:
- Prodotto: Burrata (confezione da 500g)
- Inventario del 1 dicembre: 10 confezioni
- Vendite successive:
- 10 carbonare (50g di burrata ciascuna) = 500g = 1 confezione
- 5 insalate (100g di burrata ciascuna) = 500g = 1 confezione
- Consumo totale: 2 confezioni
- Scorta attuale: 10 - 2 = 8 confezioni
3. Scorte Correnti
Le scorte vengono mostrate in unità di confezione (non in grammi/ml individuali):
Scorta Attuale = Quantità Inventario - Consumo dalle VenditeStruttura Database
InventorySnapshot Model
{
snapshot_date: Date, // Data del conteggio
items: [
{
product_id: ObjectId, // Riferimento al prodotto
product_name: string, // Nome prodotto
physical_count: number, // Quantità contata (in confezioni)
estimated_count: number, // Quantità stimata dal sistema
unit: string, // Unità di misura (pz, kg, l)
variance: number, // Differenza tra fisico e stimato
variance_percentage: number,
value_at_count: number // Valore al momento del conteggio
}
],
total_variance_value: number, // Valore totale delle differenze
notes: string, // Note aggiuntive
performed_by: string, // Chi ha fatto il conteggio
tenant_id: ObjectId
}Product Model (campi rilevanti)
{
name: string,
quantity: number, // Dimensione confezione (es: 500 per 500g)
buyUnit: string, // Unità di acquisto (es: "confezione 500g")
sellUnit: string, // Unità di vendita (es: "g")
price: number, // Prezzo per confezione
supplier: ObjectId
}API Endpoints
GET /api/inventory/current-stock
Calcola le scorte correnti basandosi sull’ultimo snapshot.
Response:
{
"success": true,
"current_stock": [
{
"product_id": "...",
"product_name": "Burrata 500g",
"snapshot_quantity": 10, // Quantità nell'inventario
"consumed_quantity": 2.5, // Consumato dalle vendite
"current_quantity": 7.5, // Scorta attuale
"buy_unit": "confezione 500g",
"package_size": 500, // Grammi per confezione
"supplier": "Fornitore X",
"price_per_package": 5.5,
"current_value": 41.25,
"stock_status": "medium"
}
],
"stats": {
"total_products": 45,
"total_value": 2500.0,
"out_of_stock": 3,
"low_stock": 8,
"snapshot_date": "2025-12-01T10:00:00Z"
},
"snapshot_date": "2025-12-01T10:00:00Z"
}Logica di Calcolo Consumo:
- Per ogni prodotto, trova tutti i prodotti vendibili che lo usano nella ricetta
- Per ogni prodotto vendibile, leggi le vendite dal giorno dell’inventario
- Calcola:
grammi_consumati = vendite × quantità_in_ricetta - Converti in confezioni:
confezioni = grammi_consumati / dimensione_confezione
POST /api/inventory/snapshots
Crea un nuovo snapshot di inventario.
Body:
{
"items": [
{
"product_id": "PRODUCT_ID",
"physical_count": 10.5
}
],
"notes": "Inventario mensile",
"performed_by": "Mario Rossi"
}GET /api/inventory/snapshots
Recupera lo storico degli snapshot.
Query params:
limit: numero massimo risultati (default: 10)skip: paginazione (default: 0)
Flusso di Lavoro
1. Creazione Primo Inventario
- Vai su
/magazzino/inventario - Cerca e aggiungi i prodotti da contare
- Inserisci la quantità fisica per ogni prodotto (in confezioni)
- Aggiungi note e nome del responsabile
- Salva lo snapshot
2. Monitoraggio Scorte
- La pagina
/magazzinomostra automaticamente:- Data ultimo inventario
- Scorte calcolate per ogni prodotto
- Consumo dall’ultimo inventario
- Status (alto/medio/basso/esaurito)
- Le scorte vengono ricalcolate in tempo reale basandosi sulle vendite
3. Nuovo Inventario Periodico
- Esegui un nuovo conteggio fisico (mensile/trimestrale)
- Crea un nuovo snapshot
- Il sistema inizierà a calcolare i consumi dal nuovo snapshot
Interfaccia Utente
Pagina Magazzino (/magazzino)
Card Statistiche:
- Totale prodotti tracciati
- Valore totale giacenze
- Prodotti con scorte basse
- Prodotti esauriti
Tabella Scorte:
| Prodotto | Inventario Iniziale | Consumato | Scorta Attuale | Dim. Confezione | Prezzo | Valore | Status |
|---|---|---|---|---|---|---|---|
| Burrata | 10 conf. | -2.5 conf. | 7.5 conf. | 500g | €5.50 | €41.25 | Medio |
Colori Status:
- 🟢 Alto (>20 confezioni): Verde
- 🟡 Medio (5-20 confezioni): Giallo
- 🟠 Basso (<5 confezioni): Arancione
- 🔴 Esaurito (0 confezioni): Rosso
Pagina Nuovo Inventario (/magazzino/inventario)
- Ricerca prodotto: campo di ricerca per trovare prodotti
- Aggiunta prodotto: click per aggiungere al conteggio
- Tabella conteggio:
- Prodotto
- Quantità stimata (dal sistema)
- Quantità fisica (da inserire)
- Differenza
- Azioni (rimuovi)
- Note e responsabile: campi opzionali
- Salva snapshot: crea nuovo inventario
Pagina Storico (/magazzino/snapshots)
Lista cronologica di tutti gli inventari con:
- Data snapshot
- Numero prodotti contati
- Valore totale
- Varianza rispetto a stima
- Responsabile
- Note
Calcolo Avanzato
Gestione Ricette Complesse
Il sistema supporta ricette con:
- Perdite di cottura: se un prodotto perde peso in cottura
- Perdite di preparazione: scarti durante la preparazione
- Conversioni unità: automatiche tra g, kg, ml, l
Esempio con Perdite:
// Prodotto finale: Pasta alla Carbonara
recipe: [
{
product_id: "GUANCIALE_ID",
quantity: 100, // grammi
wastePercentage: 10, // 10% di scarto
preparationLoss: 5, // 5% di perdita in preparazione
},
];
// Calcolo consumo reale:
// 10 carbonare vendute
// Scarto totale: 15%
// Consumo: 10 × (100g / (1 - 0.15)) = 10 × 117.6g = 1176g
// Se confezione = 500g → 2.35 confezioni consumatePerformance e Ottimizzazioni
- Caching: I calcoli vengono cachati per ridurre carico DB
- Aggregazioni MongoDB: Query ottimizzate con pipeline
- Lazy Loading: Calcolo on-demand solo per prodotti visualizzati
- Background Jobs: Ricalcolo notturno per aggiornare stime
Requisiti e Dipendenze
Dati Necessari
Per il corretto funzionamento servono:
- ✅ Prodotti con
quantity(dimensione confezione) - ✅ Prodotti con
buyUnit(unità di acquisto) - ✅ Ricette complete nei prodotti vendibili
- ✅ Dati vendite in
salesDatadei SellingProducts
Integrazioni
- Cassa in Cloud: Importazione vendite automatica
- Ricette: Link tra prodotti vendibili e ingredienti
- Fatture: Aggiornamento prezzi prodotti
Best Practices
Frequenza Inventari
- Ristoranti: Inventario settimanale o mensile
- Prodotti deperibili: Inventario settimanale
- Prodotti secchi: Inventario mensile
Gestione Scarti
Quando fai un nuovo inventario:
- La differenza tra stimato e fisico rappresenta gli scarti
- Il sistema calcola automaticamente la varianza
- Puoi aggiungere note per spiegare discrepanze
Monitoraggio Continuo
- Controlla giornalmente i prodotti in status “basso”
- Pianifica ordini basandoti sulle scorte correnti
- Usa lo storico per identificare pattern di consumo
Troubleshooting
”Nessun inventario disponibile”
Soluzione: Crea il primo snapshot da /magazzino/inventario
Consumo errato calcolato
Cause possibili:
- Ricetta mancante o incompleta
quantity(dimensione confezione) non impostata- Vendite non sincronizzate
Debug:
# Verifica ricette
db.sellingproducts.find({ "recipe.product_id": PRODUCT_ID })
# Verifica vendite
db.sellingproducts.find({ _id: SELLING_PRODUCT_ID }, { salesData: 1 })Scorte negative
Causa: Più vendite/consumo di quanto registrato in inventario Soluzione: Sistema imposta automaticamente minimo a 0, esegui nuovo inventario fisico
Roadmap Future
Funzionalità Pianificate
- Notifiche automatiche scorte basse
- Suggerimenti ordini basati su storico
- Previsioni consumo con ML
- Export Excel degli inventari
- Codici a barre per conteggio rapido
- App mobile per inventario
Miglioramenti Tecnici
- Real-time updates con WebSocket
- Compressione dati storici
- API per integrazioni esterne
- Dashboard analytics avanzata