Skip to main content

Architettura Modulo Cassa (Flutter)

Panoramica

L'applicazione cassa (cassa_ui) e il cuore dell'interfaccia operatore del sistema POS. Costruita con Flutter, segue un'architettura modulare a plugin dove funzionalita verticali vengono caricate dinamicamente dal ModuleRegistry. L'app supporta Windows desktop e tablet Android con un design offline-first basato su Isar per lo storage locale.

Struttura dei Package

Il frontend e organizzato in package indipendenti:

  • pos_core: libreria condivisa con contratti (PosModule, IPosHostInterface), modelli dati, logica di stampa ESC/POS
  • cassa_ui: applicazione host che orchestra moduli, layout engine e workflow di cassa
  • pos_mod_tables: gestione tavoli e sale
  • pos_mod_bookings: prenotazioni
  • pos_mod_takeaway: ordini asporto e delivery
  • pos_mod_kitchen: display cucina (KDS)
  • pos_mod_cash_management: prima nota e gestione contante
  • pos_mod_warehouse: magazzino e ordini fornitori
  • pos_mod_fidelity: fidelizzazione clienti
  • editor_stampa_ui: editor template di stampa

Il Contratto PosModule

Ogni modulo implementa l'interfaccia astratta PosModule definita in pos_core:

abstract class PosModule {
String get id; // ID univoco (es. 'com.moley.tables')
String get name; // Nome per il menu
IconData get icon; // Icona nel menu
String get description; // Descrizione breve
List<CollectionSchema> get schemas; // Schemi Isar del modulo

Future<void> init(Isar isar, IPosHostInterface host, {Dio? dio});
Widget buildEntryPoint({String? initialRoute});
}

All'avvio, l'host raccoglie tutti gli schemi Isar dai moduli registrati, apre un'unica istanza del database e chiama init() su ciascun modulo passando l'istanza condivisa, l'interfaccia host e il client HTTP configurato.

ModuleRegistry

Il ModuleRegistry mantiene la lista dei moduli attivi. Attualmente la registrazione e statica:

class ModuleRegistry {
static final List<PosModule> _modules = [
PrinterEditorModule(), TablesModule(), BookingsModule(),
TakeawayModule(), KitchenModule(), FidelityModule(),
WarehouseModule(), ScratchCardsModule(), MealVoucherModule(),
CashManagementModule(), AutomaticCashModule(),
];
static List<PosModule> getActiveModules() => _modules;
}

In futuro la lista potra essere filtrata in base alla licenza del tenant.

IPosHostInterface

L'interfaccia IPosHostInterface consente ai moduli di comunicare con l'host senza dipendenze dirette:

  • processExternalOrder(orderId, origin) -- Carica un ordine esterno nel carrello per il pagamento
  • printComanda(...) -- Stampa comanda cucina con routing automatico per stampante
  • printFiscalReceipt(...) -- Emette scontrino fiscale per pagamenti split
  • navigateToPos() -- Torna alla schermata principale della cassa
  • showPrintQueue(context) -- Mostra la coda stampe
  • isAutomaticCashAvailable() -- Verifica disponibilita cassa automatica

Questo pattern permette, ad esempio, al modulo Tavoli di richiedere il pagamento di un conto tavolo direttamente nel workflow di cassa.

Layout Engine

Il Layout Engine e il sistema di configurazione dinamica dell'interfaccia cassa, contenuto in cassa_ui/lib/layout_engine/. Include:

  • ScreenComposer: composizione dinamica delle schermate a partire da configurazioni JSON
  • ButtonEvaluator: valutazione dei pulsanti con binding a prodotti e azioni
  • CartService / CartNotifier: gestione stato carrello con Riverpod
  • WorkflowNotifier: macchina a stati del flusso cassa (idle, ordering, checkout, payment)
  • PrintRouterService: instradamento stampe in base a regole configurabili
  • EventOrchestrator: coordinamento eventi NATS, sync e stampa

State Management

L'app usa Riverpod come framework di state management. I provider principali sono definiti in layout_engine/providers.dart e includono il client Dio autenticato, i servizi di sync e i notifier del carrello.

Offline-First con Isar

L'architettura offline-first garantisce operativita anche senza connessione al backend:

  1. Sync iniziale: al primo avvio, i dati (prodotti, categorie, configurazioni) vengono scaricati dal backend e salvati in Isar
  2. Operativita locale: ordini e operazioni vengono creati localmente in Isar
  3. Delta sync: periodicamente (e alla riconnessione), il SyncService sincronizza i delta con il backend usando il parametro lastSync
  4. Conflict resolution: il backend funge da source of truth; i conflitti vengono risolti con last-write-wins

Comunicazione Realtime

Il NatsOrchestrator gestisce il trasporto realtime con un'astrazione che supporta:

  • Cloud: connessione NATS diretta al broker
  • LAN Master: WebSocket server locale (per reti senza internet)
  • LAN Client: WebSocket client verso il master
  • Auto: failover automatico cloud/LAN

I messaggi NATS vengono usati per sincronizzare ordini, stati tavolo e notifiche tra dispositivi dello stesso tenant.

FAQ

D: Come aggiungo un nuovo modulo? R: Crea un package Flutter, implementa PosModule, definisci gli schemi Isar e registra il modulo in ModuleRegistry. L'host aggreagera automaticamente gli schemi al prossimo avvio.

D: Posso testare un modulo in isolamento? R: Si, ogni modulo e un package indipendente. Puoi creare un'app di test che inizializza solo quel modulo con un mock di IPosHostInterface.

D: Come funziona il binding dei pulsanti nel Layout Engine? R: Il ButtonEvaluator interpreta la configurazione JSON dei pulsanti, collegandoli a prodotti specifici, azioni di sistema o navigazione. L'editor visuale (PosLayoutEditorScreen) permette di configurare i layout senza codice.

Vedi Anche

Questa pagina ti è stata utile?