| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008 |
- 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 '../../../database/daos/sconti_dao.dart';
- import '../../../providers/auth_provider.dart';
- import '../../widgets/cod_desc_dropdown_item.dart';
- import '../../../providers/order_provider.dart';
- import '../../../providers/database_provider.dart';
- import '../../../database/database.dart';
- import '../../../database/daos/listini_dao.dart';
- import '../../widgets/article_image.dart';
- import 'selezione_cliente_page.dart';
- class OrderEditPage extends ConsumerStatefulWidget {
- final int? id;
- final int? idCliente;
- const OrderEditPage({super.key, this.id, this.idCliente});
- @override
- ConsumerState<OrderEditPage> createState() => _OrderEditPageState();
- }
- class _OrderEditPageState extends ConsumerState<OrderEditPage>
- with SingleTickerProviderStateMixin {
- late TabController _tabController;
- final _artCtrl = TextEditingController();
- final _noteClienteCtrl = TextEditingController();
- final _noteOrdineCtrl = TextEditingController();
- final _riferimentoCtrl = TextEditingController();
- List<Articolo> _searchResults = [];
- bool _searching = false;
- bool _usaListinoCliente = true;
- List<Filiale> _filiali = [];
- List<Listino> _listini = [];
- List<Pagamento> _pagamenti = [];
- Cliente? _cliente;
- int? _selectedFiliale;
- int? _selectedListino;
- int? _selectedPagamento;
- bool _dataLoaded = false;
- @override
- void initState() {
- super.initState();
- _tabController = TabController(length: 2, vsync: this);
- _tabController.addListener(() {
- if (_tabController.index == 1 && _searchResults.isEmpty && _artCtrl.text.isEmpty) {
- _searchArticles('');
- }
- });
- WidgetsBinding.instance.addPostFrameCallback((_) => _init());
- }
- @override
- void dispose() {
- _tabController.dispose();
- _artCtrl.dispose();
- _noteClienteCtrl.dispose();
- _noteOrdineCtrl.dispose();
- _riferimentoCtrl.dispose();
- super.dispose();
- }
- Future<void> _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;
- 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;
- });
- }
- Future<void> _searchArticles(String q) async {
- setState(() => _searching = true);
- final dao = ref.read(articoliDaoProvider);
- final order = ref.read(orderProvider).order;
- final dataOrdine = order?.dataOrdine ?? DateTime.now().toIso8601String();
- List<Articolo> results;
- if (_usaListinoCliente && _cliente != null) {
- results = await dao.getArticoliPerListinoCliente(_cliente!.idCliente, dataOrdine);
- } else {
- results = await dao.getArticoliPerListinoAttivo(dataOrdine);
- }
- if (q.isNotEmpty) {
- final lower = q.toLowerCase();
- results = results.where((a) {
- final cod = (a.codArticolo ?? '').toLowerCase();
- final desc = (a.descrizione ?? '').toLowerCase();
- final ean = (a.ean ?? '').toLowerCase();
- return cod.contains(lower) || desc.contains(lower) || ean.contains(lower);
- }).toList();
- }
- setState(() {
- _searchResults = results;
- _searching = false;
- });
- }
- void _showArticlePicker(Articolo art) async {
- final agente = ref.read(authProvider).agente;
- final canEditPrice = agente?.modificaPrezzi == 1;
- final order = ref.read(orderProvider).order;
- final dataOrdine = order?.dataOrdine ?? DateTime.now().toIso8601String();
- final listini = await ref
- .read(listiniDaoProvider)
- .getListiniPerArticolo(art.idArticolo, dataOrdine);
- final listiniDao = ref.read(listiniDaoProvider);
- final scontiDao = ref.read(scontiDaoProvider);
- if (!context.mounted) return;
- showModalBottomSheet(
- context: context,
- isScrollControlled: true,
- builder: (_) => _ArticlePickerSheet(
- articolo: art,
- listini: listini,
- listiniDao: listiniDao,
- scontiDao: scontiDao,
- dataOrdine: dataOrdine,
- canEditPrezzo: canEditPrice,
- idListinoDefault: _selectedListino,
- onConfirm: (
- colli,
- quantita,
- prezzoLordo,
- prezzoNetto,
- listinoId, {
- double sconto1 = 0,
- double sconto2 = 0,
- double sconto3 = 0,
- double sconto4 = 0,
- double sconto5 = 0,
- }) {
- _addArticleWithDetails(
- art: art,
- idListino: listinoId,
- colli: colli,
- quantita: quantita,
- prezzoLordo: prezzoLordo,
- prezzoNetto: prezzoNetto,
- sconto1: sconto1,
- sconto2: sconto2,
- sconto3: sconto3,
- sconto4: sconto4,
- sconto5: sconto5,
- );
- },
- ),
- );
- }
- Future<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,
- }) async {
- final orderState = ref.read(orderProvider);
- var idOrdine = orderState.order?.idOrdine;
- if (idOrdine == null || idOrdine == 0) {
- await ref.read(orderProvider.notifier).saveOrder();
- idOrdine = ref.read(orderProvider).order?.idOrdine;
- if (idOrdine == null || idOrdine == 0) return;
- }
- await ref
- .read(orderProvider.notifier)
- .addLine(
- RigaOrdine(
- idRigaOrdine: 0,
- idOrdine: idOrdine,
- 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,
- ),
- );
- _artCtrl.clear();
- setState(() => _searchResults = []);
- }
- Future<void> _selezionaCliente() async {
- final agente = ref.read(authProvider).agente;
- if (agente == null) return;
- final cliente = await Navigator.push<Cliente>(
- 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<void> _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();
- 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('Ordine #${orderState.order?.numeroOrdine ?? 'nuovo'}'),
- 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 && orderState.order?.idOrdine != null
- ? FloatingActionButton.extended(
- onPressed: _salva,
- icon: const Icon(Icons.save),
- label: const Text('Salva'),
- )
- : 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.surfaceVariant,
- 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,
- ),
- ),
- ],
- ),
- ),
- IconButton(
- icon: Icon(Icons.search, color: cs.primary),
- onPressed: _selezionaCliente,
- ),
- ],
- ),
- ),
- ),
- const SizedBox(height: 16),
- DropdownButtonFormField<int>(
- value: _selectedFiliale,
- decoration: const InputDecoration(labelText: 'Filiale'),
- items: _filiali
- .map(
- (f) => DropdownMenuItem(
- value: f.idFiliale,
- child: CodDescDropdownItem(
- codice: f.codFiliale,
- descrizione: f.descrizione,
- ),
- ),
- )
- .toList(),
- onChanged: (v) => setState(() => _selectedFiliale = v),
- ),
- const SizedBox(height: 16),
- DropdownButtonFormField<int>(
- 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: (v) => setState(() => _selectedListino = v),
- ),
- const SizedBox(height: 16),
- DropdownButtonFormField<int>(
- 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: (v) => setState(() => _selectedPagamento = v),
- ),
- const SizedBox(height: 16),
- TextFormField(
- controller: _noteClienteCtrl,
- decoration: const InputDecoration(
- labelText: 'Note Cliente',
- alignLabelWithHint: true,
- ),
- maxLines: 3,
- ),
- const SizedBox(height: 16),
- TextFormField(
- controller: _noteOrdineCtrl,
- decoration: const InputDecoration(
- labelText: 'Note Ordine',
- alignLabelWithHint: true,
- ),
- maxLines: 3,
- ),
- const SizedBox(height: 16),
- TextFormField(
- controller: _riferimentoCtrl,
- decoration: const InputDecoration(labelText: 'Riferimento'),
- maxLines: 1,
- ),
- ],
- ),
- );
- }
- Widget _buildLinesTab(ThemeData theme, OrderState orderState) {
- return Column(
- children: [
- Padding(
- padding: const EdgeInsets.all(12),
- child: Row(
- children: [
- Expanded(
- child: TextField(
- controller: _artCtrl,
- decoration: InputDecoration(
- hintText: 'Cerca articolo...',
- prefixIcon: const Icon(Icons.search),
- suffixIcon: _searching
- ? const SizedBox(
- width: 20,
- height: 20,
- child: CircularProgressIndicator(strokeWidth: 2),
- )
- : null,
- ),
- onChanged: _searchArticles,
- ),
- ),
- const SizedBox(width: 8),
- FilterChip(
- label: const Text('Listino cliente'),
- selected: _usaListinoCliente,
- onSelected: (v) {
- setState(() => _usaListinoCliente = v);
- _searchArticles(_artCtrl.text);
- },
- ),
- ],
- ),
- ),
- if (_searchResults.isNotEmpty)
- SizedBox(
- height: 200,
- child: ListView.builder(
- itemCount: _searchResults.length,
- itemBuilder: (_, i) => ListTile(
- leading: ArticleImage(
- idArticolo: _searchResults[i].idArticolo,
- codArticolo: _searchResults[i].codArticolo,
- ),
- title: Text(_searchResults[i].descrizione ?? ''),
- subtitle: Text(_searchResults[i].codArticolo ?? ''),
- trailing: TextButton(
- onPressed: () => _showArticlePicker(_searchResults[i]),
- child: const Text('Aggiungi'),
- ),
- ),
- ),
- ),
- Expanded(
- child: orderState.lines.isEmpty
- ? const Center(child: Text('Nessun articolo'))
- : ListView.builder(
- itemCount: orderState.lines.length,
- itemBuilder: (_, i) => _LineCard(
- line: orderState.lines[i],
- onDelete: () => ref
- .read(orderProvider.notifier)
- .removeLine(orderState.lines[i].idRigaOrdine),
- theme: theme,
- ),
- ),
- ),
- Container(
- padding: const EdgeInsets.all(16),
- decoration: BoxDecoration(
- color: theme.colorScheme.surfaceContainerHighest,
- border: Border(top: BorderSide(color: theme.dividerColor)),
- ),
- 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,
- ),
- ),
- ],
- ),
- ),
- ],
- );
- }
- }
- class _LineCard extends StatelessWidget {
- final RigaOrdine line;
- final VoidCallback onDelete;
- final ThemeData theme;
- const _LineCard({
- required this.line,
- 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(
- '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"}€',
- ),
- 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)
- IconButton(
- icon: const Icon(Icons.delete_outline, size: 20),
- onPressed: onDelete,
- ),
- ],
- ),
- ),
- );
- }
- }
- class _ArticlePickerSheet extends StatefulWidget {
- final Articolo articolo;
- final List<Listino> listini;
- final ListiniDao listiniDao;
- final ScontiDao scontiDao;
- final String dataOrdine;
- final bool canEditPrezzo;
- final int? idListinoDefault;
- final void Function(
- double colli,
- double quantita,
- double prezzoLordo,
- double prezzoNetto,
- int listinoId, {
- double sconto1,
- double sconto2,
- double sconto3,
- double sconto4,
- double sconto5,
- })
- onConfirm;
- const _ArticlePickerSheet({
- required this.articolo,
- required this.listini,
- required this.listiniDao,
- required this.scontiDao,
- required this.dataOrdine,
- required this.canEditPrezzo,
- this.idListinoDefault,
- required this.onConfirm,
- });
- @override
- State<_ArticlePickerSheet> createState() => _ArticlePickerSheetState();
- }
- class _ArticlePickerSheetState extends State<_ArticlePickerSheet> {
- final _colliCtrl = TextEditingController();
- final _qtaCtrl = TextEditingController();
- final _prezzoCtrl = TextEditingController();
- final _sconto1Ctrl = TextEditingController();
- final _sconto2Ctrl = TextEditingController();
- final _sconto3Ctrl = TextEditingController();
- final _sconto4Ctrl = TextEditingController();
- final _sconto5Ctrl = TextEditingController();
- int? _selectedListino;
- double _prezzo = 0;
- double _prezzoNetto = 0;
- double _sconto1 = 0;
- double _sconto2 = 0;
- double _sconto3 = 0;
- double _sconto4 = 0;
- double _sconto5 = 0;
- bool _updatingColli = false;
- bool _updatingQta = false;
- @override
- void initState() {
- super.initState();
- _selectedListino = widget.idListinoDefault;
- if (_selectedListino != null) {
- _loadPrezzo(_selectedListino!);
- }
- }
- @override
- void dispose() {
- _colliCtrl.dispose();
- _qtaCtrl.dispose();
- _prezzoCtrl.dispose();
- _sconto1Ctrl.dispose();
- _sconto2Ctrl.dispose();
- _sconto3Ctrl.dispose();
- _sconto4Ctrl.dispose();
- _sconto5Ctrl.dispose();
- super.dispose();
- }
- Future<void> _loadPrezzo(int idListino) async {
- final lp = await widget.listiniDao.findListinoArticolo(
- idListino,
- widget.articolo.idArticolo,
- );
- if (lp != null) {
- if (lp.prezzo != null) {
- setState(() => _prezzo = lp.prezzo!);
- _prezzoCtrl.text = _prezzo.toStringAsFixed(2);
- }
- if (lp.idSconto != null) {
- final sconto = await widget.scontiDao.findById(lp.idSconto!);
- setState(() {
- _sconto1 = sconto?.sconto1 ?? 0;
- _sconto2 = sconto?.sconto2 ?? 0;
- _sconto3 = sconto?.sconto3 ?? 0;
- _sconto4 = sconto?.sconto4 ?? 0;
- _sconto5 = sconto?.sconto5 ?? 0;
- });
- _sconto1Ctrl.text = _sconto1 > 0 ? _sconto1.toStringAsFixed(1) : '';
- _sconto2Ctrl.text = _sconto2 > 0 ? _sconto2.toStringAsFixed(1) : '';
- _sconto3Ctrl.text = _sconto3 > 0 ? _sconto3.toStringAsFixed(1) : '';
- _sconto4Ctrl.text = _sconto4 > 0 ? _sconto4.toStringAsFixed(1) : '';
- _sconto5Ctrl.text = _sconto5 > 0 ? _sconto5.toStringAsFixed(1) : '';
- } else {
- _resetSconti();
- }
- _calcolaPrezzoNetto();
- }
- }
- void _resetSconti() {
- setState(() {
- _sconto1 = 0;
- _sconto2 = 0;
- _sconto3 = 0;
- _sconto4 = 0;
- _sconto5 = 0;
- });
- _sconto1Ctrl.clear();
- _sconto2Ctrl.clear();
- _sconto3Ctrl.clear();
- _sconto4Ctrl.clear();
- _sconto5Ctrl.clear();
- }
- void _calcolaPrezzoNetto() {
- double n = _prezzo;
- n *= (100 - _sconto1) / 100;
- n *= (100 - _sconto2) / 100;
- n *= (100 - _sconto3) / 100;
- n *= (100 - _sconto4) / 100;
- n *= (100 - _sconto5) / 100;
- setState(() => _prezzoNetto = n);
- }
- void _onPrezzoChanged(String v) {
- setState(() => _prezzo = double.tryParse(v) ?? 0);
- _calcolaPrezzoNetto();
- }
- void _onScontoChanged(int index, String v) {
- final val = double.tryParse(v) ?? 0;
- setState(() {
- switch (index) {
- case 1:
- _sconto1 = val;
- case 2:
- _sconto2 = val;
- case 3:
- _sconto3 = val;
- case 4:
- _sconto4 = val;
- case 5:
- _sconto5 = val;
- }
- });
- _calcolaPrezzoNetto();
- }
- void _onColliChanged(String v) {
- if (_updatingColli) return;
- _updatingQta = true;
- final colli = double.tryParse(v) ?? 0;
- final pezzi = widget.articolo.pezziConfezione ?? 0;
- if (colli > 0 && pezzi > 0) {
- _qtaCtrl.text = (colli * pezzi).toStringAsFixed(1);
- } else if (colli == 0) {
- _qtaCtrl.text = '';
- }
- _updatingQta = false;
- }
- void _onQtaChanged(String v) {
- if (_updatingQta) return;
- _updatingColli = true;
- final qta = double.tryParse(v) ?? 0;
- if (qta > 0) {
- _colliCtrl.text = '0';
- } else if (qta == 0) {
- _colliCtrl.text = '';
- }
- _updatingColli = false;
- }
- void _confirm() {
- final colli = double.tryParse(_colliCtrl.text) ?? 0;
- final qta = double.tryParse(_qtaCtrl.text) ?? 0;
- final prezzoLordo = double.tryParse(_prezzoCtrl.text) ?? 0;
- final listinoId = _selectedListino ?? 0;
- widget.onConfirm(
- colli,
- qta,
- prezzoLordo,
- _prezzoNetto,
- listinoId,
- sconto1: _sconto1,
- sconto2: _sconto2,
- sconto3: _sconto3,
- sconto4: _sconto4,
- sconto5: _sconto5,
- );
- Navigator.pop(context);
- }
- @override
- Widget build(BuildContext context) {
- final theme = Theme.of(context);
- return Padding(
- padding: EdgeInsets.only(
- bottom: MediaQuery.of(context).viewInsets.bottom,
- left: 16,
- right: 16,
- top: 16,
- ),
- child: SingleChildScrollView(
- child: Column(
- mainAxisSize: MainAxisSize.min,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- widget.articolo.descrizione ?? '',
- style: theme.textTheme.titleMedium,
- ),
- const SizedBox(height: 4),
- Text(
- widget.articolo.codArticolo ?? '',
- style: theme.textTheme.bodySmall,
- ),
- if (widget.articolo.pezziConfezione != null)
- Text(
- 'Pezzi/confezione: ${widget.articolo.pezziConfezione}',
- style: theme.textTheme.bodySmall,
- ),
- const SizedBox(height: 16),
- DropdownButtonFormField<int>(
- value: _selectedListino,
- decoration: const InputDecoration(labelText: 'Listino'),
- isExpanded: true,
- items: widget.listini
- .map(
- (l) => DropdownMenuItem(
- value: l.idListino,
- child: CodDescDropdownItem(
- codice: l.codListino,
- descrizione: l.descrizione,
- ),
- ),
- )
- .toList(),
- onChanged: (v) {
- setState(() => _selectedListino = v);
- if (v != null) _loadPrezzo(v);
- },
- ),
- const SizedBox(height: 12),
- TextField(
- controller: _prezzoCtrl,
- decoration: const InputDecoration(labelText: 'Prezzo lordo'),
- keyboardType: const TextInputType.numberWithOptions(
- decimal: true,
- ),
- enabled: widget.canEditPrezzo,
- onChanged: _onPrezzoChanged,
- ),
- const SizedBox(height: 12),
- Row(
- children: [
- Expanded(
- child: TextField(
- controller: _sconto1Ctrl,
- decoration: const InputDecoration(labelText: 'Sconto 1 %'),
- keyboardType: const TextInputType.numberWithOptions(
- decimal: true,
- ),
- onChanged: (v) => _onScontoChanged(1, v),
- ),
- ),
- const SizedBox(width: 12),
- Expanded(
- child: TextField(
- controller: _sconto2Ctrl,
- decoration: const InputDecoration(labelText: 'Sconto 2 %'),
- keyboardType: const TextInputType.numberWithOptions(
- decimal: true,
- ),
- onChanged: (v) => _onScontoChanged(2, v),
- ),
- ),
- ],
- ),
- const SizedBox(height: 12),
- Row(
- children: [
- Expanded(
- child: TextField(
- controller: _sconto3Ctrl,
- decoration: const InputDecoration(labelText: 'Sconto 3 %'),
- keyboardType: const TextInputType.numberWithOptions(
- decimal: true,
- ),
- onChanged: (v) => _onScontoChanged(3, v),
- ),
- ),
- const SizedBox(width: 12),
- Expanded(
- child: TextField(
- controller: _sconto4Ctrl,
- decoration: const InputDecoration(labelText: 'Sconto 4 %'),
- keyboardType: const TextInputType.numberWithOptions(
- decimal: true,
- ),
- onChanged: (v) => _onScontoChanged(4, v),
- ),
- ),
- ],
- ),
- const SizedBox(height: 12),
- SizedBox(
- width: 140,
- child: TextField(
- controller: _sconto5Ctrl,
- decoration: const InputDecoration(labelText: 'Sconto 5 %'),
- keyboardType: const TextInputType.numberWithOptions(
- decimal: true,
- ),
- onChanged: (v) => _onScontoChanged(5, v),
- ),
- ),
- const SizedBox(height: 16),
- Row(
- children: [
- Text('Prezzo netto: ', style: theme.textTheme.bodyLarge),
- Text(
- _prezzoNetto.toStringAsFixed(2),
- style: theme.textTheme.bodyLarge?.copyWith(
- fontWeight: FontWeight.bold,
- ),
- ),
- ],
- ),
- const SizedBox(height: 12),
- Row(
- children: [
- Expanded(
- child: TextField(
- controller: _colliCtrl,
- decoration: const InputDecoration(labelText: 'Colli'),
- keyboardType: TextInputType.number,
- onChanged: _onColliChanged,
- ),
- ),
- const SizedBox(width: 12),
- Expanded(
- child: TextField(
- controller: _qtaCtrl,
- decoration: const InputDecoration(labelText: 'Quantità'),
- keyboardType: TextInputType.number,
- onChanged: _onQtaChanged,
- ),
- ),
- ],
- ),
- const SizedBox(height: 20),
- SizedBox(
- width: double.infinity,
- child: ElevatedButton(
- onPressed: _confirm,
- child: const Text('Aggiungi'),
- ),
- ),
- const SizedBox(height: 8),
- ],
- ),
- ),
- );
- }
- }
|