import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; import 'package:ristoris/core/credit_score_color.dart'; import '../../../providers/auth_provider.dart'; import '../../widgets/cod_desc_dropdown_item.dart'; import '../../../providers/order_provider.dart'; import '../../../providers/dashboard_provider.dart'; import '../../../providers/database_provider.dart'; import '../../../database/database.dart'; import '../../../core/constants.dart'; import 'selezione_cliente_page.dart'; import 'selezione_articolo_page.dart'; class OrderEditPage extends ConsumerStatefulWidget { final int? id; final int? idCliente; const OrderEditPage({super.key, this.id, this.idCliente}); @override ConsumerState createState() => _OrderEditPageState(); } class _OrderEditPageState extends ConsumerState with SingleTickerProviderStateMixin { late TabController _tabController; final _noteClienteCtrl = TextEditingController(); final _noteOrdineCtrl = TextEditingController(); final _riferimentoCtrl = TextEditingController(); List _filiali = []; List _listini = []; List _pagamenti = []; Cliente? _cliente; int? _selectedFiliale; int? _selectedListino; int? _selectedPagamento; bool _dataLoaded = false; bool _readOnly = false; @override void initState() { super.initState(); _tabController = TabController(length: 2, vsync: this); _tabController.addListener(() => setState(() {})); WidgetsBinding.instance.addPostFrameCallback((_) => _init()); } @override void dispose() { _tabController.dispose(); _noteClienteCtrl.dispose(); _noteOrdineCtrl.dispose(); _riferimentoCtrl.dispose(); super.dispose(); } Future _init() async { final agente = ref.read(authProvider).agente; if (agente == null) return; if (widget.id != null) { await ref.read(orderProvider.notifier).loadOrder(widget.id!); } else if (widget.idCliente != null) { await ref .read(orderProvider.notifier) .createOrder(agente.idAgente, idCliente: widget.idCliente!); } else { await ref.read(orderProvider.notifier).createOrder(agente.idAgente); } final orderState = ref.read(orderProvider); final order = orderState.order; if (order == null) return; if (widget.id != null && order.stato != AppConstants.kStatusNew) { _readOnly = true; } final cli = order.idCliente; final clientiDao = ref.read(clientiDaoProvider); final filialiDao = ref.read(filialiDaoProvider); final listiniDao = ref.read(listiniDaoProvider); final pagamentiDao = ref.read(pagamentiDaoProvider); if (cli != null) { _cliente = await clientiDao.getById(cli); _filiali = await filialiDao.getDestinationsForCustomer(cli); } _listini = await listiniDao.list(); _pagamenti = await pagamentiDao.searchActive(); setState(() { _selectedFiliale = order.idFiliale; _selectedListino = order.idListino ?? _cliente?.idListino; _selectedPagamento = order.idPagamento ?? _cliente?.idPagamento; _noteClienteCtrl.text = order.noteCliente ?? _cliente?.noteOrdine ?? ''; _noteOrdineCtrl.text = order.noteOrdine ?? ''; _riferimentoCtrl.text = order.riferimento ?? ''; _dataLoaded = true; }); } void _aggiungiArticolo() async { final order = ref.read(orderProvider).order; final dataOrdine = order?.dataOrdine ?? DateTime.now().toIso8601String(); final result = await Navigator.push( context, MaterialPageRoute( builder: (_) => SelezioneArticoloPage( idCliente: _cliente?.idCliente ?? 0, dataOrdine: dataOrdine, idListinoDefault: _selectedListino, ), ), ); if (result != null) { _addArticleWithDetails( art: result.articolo, idListino: result.idListino, colli: result.colli, quantita: result.quantita, prezzoLordo: result.prezzoLordo, prezzoNetto: result.prezzoNetto, sconto1: result.sconto1, sconto2: result.sconto2, sconto3: result.sconto3, sconto4: result.sconto4, sconto5: result.sconto5, ); } } void _addArticleWithDetails({ required Articolo art, required int idListino, required double colli, required double quantita, required double prezzoLordo, required double prezzoNetto, double? sconto1 = 0, double? sconto2 = 0, double? sconto3 = 0, double? sconto4 = 0, double? sconto5 = 0, }) { ref.read(orderProvider.notifier).addLine( VRigheOrdineData( idRigaOrdine: 0, idOrdine: ref.read(orderProvider).order?.idOrdine ?? 0, idArticolo: art.idArticolo, idListino: idListino, quantita: quantita, prezzoLordo: prezzoLordo, prezzoNetto: prezzoNetto, sconto1: sconto1, sconto2: sconto2, sconto3: sconto3, sconto4: sconto4, sconto5: sconto5, totale: prezzoNetto * quantita, promozione: 0, rigaPromozione: 0, colli: colli, codArticolo: art.codArticolo, descrizione: art.descrizione, ), ); } Future _selezionaCliente() async { final agente = ref.read(authProvider).agente; if (agente == null) return; final cliente = await Navigator.push( context, MaterialPageRoute( builder: (_) => SelezioneClientePage(idAgente: agente.idAgente), ), ); if (cliente != null) _onClienteSelezionato(cliente); } void _onClienteSelezionato(Cliente cliente) async { ref.read(orderProvider.notifier).setIdCliente(cliente.idCliente); final filialiDao = ref.read(filialiDaoProvider); final filiali = await filialiDao.getDestinationsForCustomer( cliente.idCliente, ); setState(() { _cliente = cliente; _selectedFiliale = null; _selectedPagamento = cliente.idPagamento; _selectedListino = cliente.idListino; _filiali = filiali; _noteClienteCtrl.text = cliente.noteOrdine ?? ''; }); } Future _salva() async { final notifier = ref.read(orderProvider.notifier); notifier.setIdFiliale(_selectedFiliale); notifier.setIdListino(_selectedListino); notifier.setIdPagamento(_selectedPagamento); notifier.setNoteCliente(_noteClienteCtrl.text); notifier.setNoteOrdine(_noteOrdineCtrl.text); notifier.setRiferimento(_riferimentoCtrl.text); await notifier.saveOrder(); final agente = ref.read(authProvider).agente; if (agente != null) { ref.invalidate(ordersViewProvider(agente.idAgente)); ref.invalidate(ordersSearchViewProvider); ref.invalidate(orderStatsProvider(agente.idAgente)); ref.invalidate(dashboardProvider(agente.idAgente)); } if (context.mounted) Navigator.pop(context); } @override Widget build(BuildContext context) { final orderState = ref.watch(orderProvider); final theme = Theme.of(context); return Scaffold( appBar: AppBar( title: Text(_readOnly ? 'Ordine #${orderState.order?.numeroOrdine} - Trasmesso' : 'Ordine #${orderState.order?.numeroOrdine ?? 'nuovo'}'), actions: [ if (!_readOnly) IconButton( icon: const Icon(Icons.save), onPressed: _salva, ), ], bottom: TabBar( controller: _tabController, tabs: const [ Tab(text: 'Testata'), Tab(text: 'Righe'), ], ), ), body: SafeArea( child: orderState.isLoading || !_dataLoaded ? const Center(child: CircularProgressIndicator()) : TabBarView( controller: _tabController, children: [ _buildHeaderTab(theme), _buildLinesTab(theme, orderState), ], ), ), floatingActionButton: _tabController.index == 1 && _cliente != null && !_readOnly ? FloatingActionButton( onPressed: _aggiungiArticolo, child: const Icon(Icons.add), ) : null, bottomNavigationBar: _tabController.index == 1 ? Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: theme.colorScheme.surfaceContainerHighest, border: Border(top: BorderSide(color: theme.dividerColor)), ), child: SafeArea( child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Qtà: ${orderState.totQta.toStringAsFixed(1)}'), Text( 'Totale: ${NumberFormat.currency(locale: 'it', symbol: '€').format(orderState.totale)}', style: theme.textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, ), ), ], ), ), ) : null, ); } Widget _buildHeaderTab(ThemeData theme) { final cs = theme.colorScheme; final bgColor = creditScoreBg(_cliente?.creditScoreColor); return SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Card( elevation: 0, color: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), side: BorderSide(color: cs.outlineVariant), ), child: Padding( padding: const EdgeInsets.all(12), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Cliente', style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: cs.onSurfaceVariant, ), ), const SizedBox(height: 4), if (_cliente != null) Row( children: [ Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 4, ), decoration: BoxDecoration( color: bgColor ?? cs.surfaceContainerHighest, borderRadius: BorderRadius.circular(4), ), child: Text( _cliente!.codCliente ?? '', style: TextStyle( fontSize: 12, height: 16 / 12, fontWeight: FontWeight.w500, color: bgColor != null ? Colors.white : cs.onSurfaceVariant, ), ), ), const SizedBox(width: 8), Expanded( child: Text( _cliente!.ragioneSociale ?? '', style: theme.textTheme.bodyMedium?.copyWith( fontWeight: FontWeight.w600, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), ], ) else Text( 'Nessun cliente selezionato', style: theme.textTheme.bodyMedium?.copyWith( color: cs.onSurfaceVariant, ), ), ], ), ), if (!_readOnly) IconButton( icon: Icon(Icons.search, color: cs.primary), onPressed: _selezionaCliente, ), ], ), ), ), const SizedBox(height: 16), DropdownButtonFormField( initialValue: _selectedFiliale, decoration: const InputDecoration(labelText: 'Filiale'), items: _filiali .map( (f) => DropdownMenuItem( value: f.idFiliale, child: CodDescDropdownItem( codice: f.codFiliale, descrizione: f.descrizione, ), ), ) .toList(), onChanged: _readOnly ? null : (v) => setState(() => _selectedFiliale = v), ), const SizedBox(height: 16), DropdownButtonFormField( initialValue: _selectedListino, decoration: const InputDecoration(labelText: 'Listino'), items: _listini .map( (l) => DropdownMenuItem( value: l.idListino, child: CodDescDropdownItem( codice: l.codListino, descrizione: l.descrizione, ), ), ) .toList(), onChanged: _readOnly ? null : (v) => setState(() => _selectedListino = v), ), const SizedBox(height: 16), DropdownButtonFormField( initialValue: _selectedPagamento, decoration: const InputDecoration(labelText: 'Pagamento'), items: _pagamenti .map( (p) => DropdownMenuItem( value: p.idPagamento, child: CodDescDropdownItem( codice: p.codPagamento, descrizione: p.descrizione, ), ), ) .toList(), onChanged: _readOnly ? null : (v) => setState(() => _selectedPagamento = v), ), const SizedBox(height: 16), TextFormField( controller: _noteClienteCtrl, enabled: !_readOnly, decoration: const InputDecoration( labelText: 'Note Cliente', alignLabelWithHint: true, ), maxLines: 3, ), const SizedBox(height: 16), TextFormField( controller: _noteOrdineCtrl, enabled: !_readOnly, decoration: const InputDecoration( labelText: 'Note Ordine', alignLabelWithHint: true, ), maxLines: 3, ), const SizedBox(height: 16), TextFormField( controller: _riferimentoCtrl, enabled: !_readOnly, decoration: const InputDecoration(labelText: 'Riferimento'), maxLines: 1, ), ], ), ); } Widget _buildLinesTab(ThemeData theme, OrderState orderState) { return Column( children: [ Expanded( child: orderState.lines.isEmpty ? const Center(child: Text('Nessun articolo')) : ListView.builder( itemCount: orderState.lines.length, itemBuilder: (_, i) => _LineCard( line: orderState.lines[i], readOnly: _readOnly, onDelete: () => ref.read(orderProvider.notifier).removeLine(i), theme: theme, ), ), ), ], ); } } class _LineCard extends StatelessWidget { final VRigheOrdineData line; final bool readOnly; final VoidCallback onDelete; final ThemeData theme; const _LineCard({ required this.line, required this.readOnly, required this.onDelete, required this.theme, }); @override Widget build(BuildContext context) { final isPromo = line.rigaPromozione == 1; return Card( margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), color: isPromo ? Colors.green.shade50 : null, child: ListTile( title: Text( line.codArticolo != null ? '${line.codArticolo} - ${line.descrizione ?? ''}' : 'Articolo #${line.idArticolo ?? ''}', style: TextStyle(fontWeight: isPromo ? FontWeight.bold : null), ), subtitle: Text( 'Qtà: ${line.quantita?.toStringAsFixed(1) ?? "0"} Prezzo: ${line.prezzoNetto?.toStringAsFixed(2) ?? "0,00"}€${line.listino != null ? ' Listino: ${line.listino}' : ''}', ), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ if (isPromo) Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( color: Colors.green, borderRadius: BorderRadius.circular(8), ), child: const Text( 'PROMO', style: TextStyle(color: Colors.white, fontSize: 10), ), ), if (!isPromo && !readOnly) IconButton( icon: const Icon(Icons.delete_outline, size: 20), onPressed: onDelete, ), ], ), ), ); } }