Fabio Dalle Ave 2 месяцев назад
Родитель
Сommit
a824a97bba
30 измененных файлов с 1842 добавлено и 687 удалено
  1. 3 0
      android/app/src/main/AndroidManifest.xml
  2. BIN
      assets/db/Ristoris.db
  3. 24 0
      lib/core/credit_score_color.dart
  4. 132 45
      lib/database/daos/articoli_dao.dart
  5. 63 25
      lib/database/daos/listini_dao.dart
  6. 111 60
      lib/database/daos/ordini_dao.dart
  7. 7 7
      lib/database/database.g.dart
  8. 4 1
      lib/database/db_connector_io.dart
  9. 8 4
      lib/database/tables/listini_cliente.dart
  10. 24 2
      lib/providers/auth_provider.dart
  11. 8 0
      lib/providers/order_provider.dart
  12. 26 6
      lib/providers/sync_provider.dart
  13. 3 0
      lib/services/auth_service.dart
  14. 14 1
      lib/services/sync/ordine_sync_service.dart
  15. 5 3
      lib/ui/pages/catalog/catalog_page.dart
  16. 38 34
      lib/ui/pages/customers/customer_detail_page.dart
  17. 41 39
      lib/ui/pages/customers/customer_list_page.dart
  18. 9 8
      lib/ui/pages/dashboard/dashboard_page.dart
  19. 12 5
      lib/ui/pages/login/init_page.dart
  20. 24 2
      lib/ui/pages/login/login_page.dart
  21. 540 121
      lib/ui/pages/orders/order_edit_page.dart
  22. 352 165
      lib/ui/pages/orders/order_list_page.dart
  23. 194 0
      lib/ui/pages/orders/selezione_cliente_page.dart
  24. 13 11
      lib/ui/pages/payments/payments_page.dart
  25. 13 11
      lib/ui/pages/promotions/promotion_list_page.dart
  26. 8 6
      lib/ui/pages/statistics/statistics_page.dart
  27. 7 5
      lib/ui/pages/sync/sync_page.dart
  28. 7 5
      lib/ui/pages/sync/sync_settings_page.dart
  29. 32 0
      lib/ui/widgets/cod_desc_dropdown_item.dart
  30. 120 121
      lib/ui/widgets/customer_card.dart

+ 3 - 0
android/app/src/main/AndroidManifest.xml

@@ -1,4 +1,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android">
 <manifest xmlns:android="http://schemas.android.com/apk/res/android">
+   
+   <uses-permission android:name="android.permission.INTERNET" />
+   
     <application
     <application
         android:label="ristoris"
         android:label="ristoris"
         android:name="${applicationName}"
         android:name="${applicationName}"

BIN
assets/db/Ristoris.db


+ 24 - 0
lib/core/credit_score_color.dart

@@ -0,0 +1,24 @@
+import 'package:flutter/material.dart';
+
+Color? creditScoreBg(String? colorName) {
+  switch (colorName?.toUpperCase()) {
+    case 'VERDE':
+      return const Color(0xFF008000);
+    case 'VERDE CHIARO':
+      return const Color(0xFF90EE90);
+    case 'VERDE SCURO':
+      return const Color(0xFF006400);
+    case 'GIALLO':
+      return const Color(0xFFFFA500);
+    case 'GRIGIO':
+      return const Color(0xFF808080);
+    case 'ROSSO VIVO':
+      return const Color(0xFFA80000);
+    case 'ROSSO SCURO':
+      return const Color(0xFF8B0000);
+    case 'ROSSO':
+      return const Color(0xFFFF0000);
+    default:
+      return null;
+  }
+}

+ 132 - 45
lib/database/daos/articoli_dao.dart

@@ -11,23 +11,30 @@ class ArticoliDao {
   ArticoliDao(this.db);
   ArticoliDao(this.db);
 
 
   Future<Articolo?> getByCode(String code) {
   Future<Articolo?> getByCode(String code) {
-    return (db.select(db.articoli)..where((t) => t.codArticolo.equals(code))).getSingleOrNull();
+    return (db.select(
+      db.articoli,
+    )..where((t) => t.codArticolo.equals(code))).getSingleOrNull();
   }
   }
 
 
   Future<List<Articolo>> getItems(String filter) async {
   Future<List<Articolo>> getItems(String filter) async {
     final words = filter.split(' ').where((w) => w.isNotEmpty).toList();
     final words = filter.split(' ').where((w) => w.isNotEmpty).toList();
     final q = db.select(db.articoli)
     final q = db.select(db.articoli)
-      ..where((t) =>
-        (t.gruppo.isNotNull() & t.gruppo.equals('*').not()) &
-        (t.categoria.isNotNull() & t.categoria.equals('PPP').not()) &
-        (t.descrizione.isNotNull() & t.descrizione.like('%.ANNULLATO%').not())
+      ..where(
+        (t) =>
+            (t.gruppo.isNotNull() & t.gruppo.equals('*').not()) &
+            (t.categoria.isNotNull() & t.categoria.equals('PPP').not()) &
+            (t.descrizione.isNotNull() &
+                t.descrizione.like('%.ANNULLATO%').not()),
       )
       )
       ..orderBy([(t) => OrderingTerm(expression: t.descrizione)])
       ..orderBy([(t) => OrderingTerm(expression: t.descrizione)])
       ..limit(200);
       ..limit(200);
     for (final word in words) {
     for (final word in words) {
       final pattern = '%$word%';
       final pattern = '%$word%';
-      q.where((t) =>
-        t.codArticolo.like(pattern) | t.descrizione.like(pattern) | t.ean.like(pattern)
+      q.where(
+        (t) =>
+            t.codArticolo.like(pattern) |
+            t.descrizione.like(pattern) |
+            t.ean.like(pattern),
       );
       );
     }
     }
     return q.get();
     return q.get();
@@ -43,56 +50,136 @@ class ArticoliDao {
   }
   }
 
 
   Future<List<Listino>> getListini() {
   Future<List<Listino>> getListini() {
-    return (db.select(db.listini)
-      ..where((t) =>
-        t.codListino.isNotNull() &
-        t.codListino.like('OF2').not() &
-        t.codListino.like('OF4').not() &
-        t.codListino.like('I0').not()
-      )
-    ).get();
+    return (db.select(db.listini)..where(
+          (t) =>
+              t.codListino.isNotNull() &
+              t.codListino.like('OF2').not() &
+              t.codListino.like('OF4').not() &
+              t.codListino.like('I0').not(),
+        ))
+        .get();
   }
   }
 
 
   Future<List<ListinoArticolo>> getListinoArticoli(int idListino) {
   Future<List<ListinoArticolo>> getListinoArticoli(int idListino) {
     return (db.select(db.listiniArticolo)
     return (db.select(db.listiniArticolo)
-      ..where((t) => t.idListino.equals(idListino) & (t.attivo.equals(1)))
-    ).get();
+          ..where((t) => t.idListino.equals(idListino) & (t.attivo.equals(1))))
+        .get();
   }
   }
 
 
-  Future<ListinoArticolo?> getListPrice(int idListino, int idArticolo, String date) {
-    return (db.select(db.listiniArticolo)
-      ..where((t) =>
-        t.idListino.equals(idListino) &
-        t.idArticolo.equals(idArticolo) &
-        (t.attivo.equals(1))
-      )
-    ).getSingleOrNull();
+  Future<ListinoArticolo?> getListPrice(
+    int idListino,
+    int idArticolo,
+    String date,
+  ) {
+    return (db.select(db.listiniArticolo)..where(
+          (t) =>
+              t.idListino.equals(idListino) &
+              t.idArticolo.equals(idArticolo) &
+              (t.attivo.equals(1)),
+        ))
+        .getSingleOrNull();
   }
   }
 
 
-  Future<ListinoCliente?> getCustomerListPrice(int idCliente, int idArticolo, String date) {
+  Future<ListinoCliente?> getCustomerListPrice(
+    int idCliente,
+    int idArticolo,
+    String date,
+  ) {
     return (db.select(db.listiniCliente)
     return (db.select(db.listiniCliente)
-      ..where((t) =>
-        t.idCliente.equals(idCliente) &
-        t.idArticolo.equals(idArticolo) &
-        (t.attivo.equals(1)) &
-        (t.annullato.equals('N'))
-      )
-      ..orderBy([(t) => OrderingTerm(expression: t.validoDa, mode: OrderingMode.desc)])
-      ..limit(1)
-    ).getSingleOrNull();
+          ..where(
+            (t) =>
+                t.idCliente.equals(idCliente) &
+                t.idArticolo.equals(idArticolo) &
+                (t.attivo.equals(1)) &
+                (t.annullato.equals('N')),
+          )
+          ..orderBy([
+            (t) =>
+                OrderingTerm(expression: t.validoDa, mode: OrderingMode.desc),
+          ])
+          ..limit(1))
+        .getSingleOrNull();
   }
   }
 
 
   Future<List<Listino>> getPriceCodes(int idArticolo) {
   Future<List<Listino>> getPriceCodes(int idArticolo) {
     return (db.select(db.listini)
     return (db.select(db.listini)
-      ..join([
-        innerJoin(db.listiniArticolo, db.listiniArticolo.idListino.equalsExp(db.listini.idListino) & db.listiniArticolo.idArticolo.equals(idArticolo)),
-      ])
-      ..where((t) =>
-        t.codListino.isNotNull() &
-        t.codListino.like('OF2').not() &
-        t.codListino.like('OF4').not() &
-        t.codListino.like('I0').not()
-      )
-    ).get();
+          ..join([
+            innerJoin(
+              db.listiniArticolo,
+              db.listiniArticolo.idListino.equalsExp(db.listini.idListino) &
+                  db.listiniArticolo.idArticolo.equals(idArticolo),
+            ),
+          ])
+          ..where(
+            (t) =>
+                t.codListino.isNotNull() &
+                t.codListino.like('OF2').not() &
+                t.codListino.like('OF4').not() &
+                t.codListino.like('I0').not(),
+          ))
+        .get();
+  }
+
+  Future<List<Articolo>> getArticoliPerListinoAttivo(String dataOrdine) async {
+    final q =
+        db.select(db.articoli).join([
+            innerJoin(
+              db.listiniArticolo,
+              db.listiniArticolo.idArticolo.equalsExp(db.articoli.idArticolo),
+            ),
+          ])
+          ..where(
+            db.listiniArticolo.attivo.equals(1) &
+                db.listiniArticolo.validoDa.isSmallerOrEqualValue(dataOrdine) &
+                db.listiniArticolo.validoA.isBiggerOrEqualValue(dataOrdine) &
+                db.articoli.attivo.equals(1) &
+                db.articoli.gruppo.isNotNull() &
+                db.articoli.gruppo.equals('*').not() &
+                db.articoli.categoria.isNotNull() &
+                db.articoli.categoria.equals('PPP').not() &
+                db.articoli.descrizione.isNotNull() &
+                db.articoli.descrizione.like('%.ANNULLATO%').not(),
+          )
+          ..orderBy([OrderingTerm(expression: db.articoli.descrizione)]);
+
+    final results = await q.get();
+    final seen = <int>{};
+    final items = <Articolo>[];
+    for (final row in results) {
+      final art = row.readTable(db.articoli);
+      if (seen.add(art.idArticolo)) items.add(art);
+    }
+    return items;
+  }
+
+  Future<List<Articolo>> getArticoliPerListinoCliente(
+    int idCliente,
+    String dataOrdine,
+  ) async {
+    final q =
+        db.select(db.articoli).join([
+            innerJoin(
+              db.listiniCliente,
+              db.listiniCliente.idArticolo.equalsExp(db.articoli.idArticolo),
+            ),
+          ])
+          ..where(
+            db.listiniCliente.idCliente.equals(idCliente) &
+                db.listiniCliente.attivo.equals(1) &
+                db.listiniCliente.annullato.equals('N') &
+                db.listiniCliente.validoDa.isSmallerOrEqualValue(dataOrdine) &
+                db.listiniCliente.validoA.isBiggerOrEqualValue(dataOrdine) &
+                db.articoli.attivo.equals(1),
+          )
+          ..orderBy([OrderingTerm(expression: db.articoli.descrizione)]);
+
+    final results = await q.get();
+    final seen = <int>{};
+    final items = <Articolo>[];
+    for (final row in results) {
+      final art = row.readTable(db.articoli);
+      if (seen.add(art.idArticolo)) items.add(art);
+    }
+    return items;
   }
   }
 }
 }

+ 63 - 25
lib/database/daos/listini_dao.dart

@@ -1,8 +1,5 @@
 import 'package:drift/drift.dart';
 import 'package:drift/drift.dart';
 import '../database.dart';
 import '../database.dart';
-import '../tables/listini.dart';
-import '../tables/listini_articolo.dart';
-import '../tables/listini_cliente.dart';
 
 
 class ListiniDao {
 class ListiniDao {
   final AppDatabase db;
   final AppDatabase db;
@@ -10,39 +7,80 @@ class ListiniDao {
 
 
   Future<List<Listino>> list() {
   Future<List<Listino>> list() {
     return (db.select(db.listini)
     return (db.select(db.listini)
-      ..where((t) =>
-        t.codListino.like('OF2').not() &
-        t.codListino.like('OF4').not() &
-        t.codListino.like('I0').not()
-      )
-      ..orderBy([(t) => OrderingTerm(expression: t.descrizione)])
-    ).get();
+          ..where(
+            (t) =>
+                t.codListino.like('OF2').not() &
+                t.codListino.like('OF4').not() &
+                t.codListino.like('I0').not() &
+                t.codListino.like('A0').not(),
+          )
+          ..orderBy([(t) => OrderingTerm(expression: t.codListino)]))
+        .get();
   }
   }
 
 
   Future<List<Listino>> listSenzaFiltro() {
   Future<List<Listino>> listSenzaFiltro() {
-    return (db.select(db.listini)..orderBy([(t) => OrderingTerm(expression: t.descrizione)])).get();
+    return (db.select(
+      db.listini,
+    )..orderBy([(t) => OrderingTerm(expression: t.descrizione)])).get();
   }
   }
 
 
   Future<Listino?> findByCod(String code) {
   Future<Listino?> findByCod(String code) {
-    return (db.select(db.listini)..where((t) => t.codListino.equals(code))).getSingleOrNull();
+    return (db.select(
+      db.listini,
+    )..where((t) => t.codListino.equals(code))).getSingleOrNull();
   }
   }
 
 
   Future<ListinoArticolo?> findListinoArticolo(int idListino, int idArticolo) {
   Future<ListinoArticolo?> findListinoArticolo(int idListino, int idArticolo) {
-    return (db.select(db.listiniArticolo)
-      ..where((t) => t.idListino.equals(idListino) & t.idArticolo.equals(idArticolo))
-    ).getSingleOrNull();
+    return (db.select(db.listiniArticolo)..where(
+          (t) =>
+              t.idListino.equals(idListino) & t.idArticolo.equals(idArticolo),
+        ))
+        .getSingleOrNull();
   }
   }
 
 
-  Future<ListinoCliente?> getListinoCliente(int idCliente, int idArticolo, String date) {
+  Future<ListinoCliente?> getListinoCliente(
+    int idCliente,
+    int idArticolo,
+    String date,
+  ) {
     return (db.select(db.listiniCliente)
     return (db.select(db.listiniCliente)
-      ..where((t) =>
-        t.idCliente.equals(idCliente) &
-        t.idArticolo.equals(idArticolo) &
-        (t.attivo.equals(1)) &
-        (t.annullato.equals('N'))
-      )
-      ..orderBy([(t) => OrderingTerm(expression: t.validoDa, mode: OrderingMode.desc)])
-      ..limit(1)
-    ).getSingleOrNull();
+          ..where(
+            (t) =>
+                t.idCliente.equals(idCliente) &
+                t.idArticolo.equals(idArticolo) &
+                (t.attivo.equals(1)) &
+                (t.annullato.equals('N')),
+          )
+          ..orderBy([
+            (t) =>
+                OrderingTerm(expression: t.validoDa, mode: OrderingMode.desc),
+          ])
+          ..limit(1))
+        .getSingleOrNull();
+  }
+
+  Future<List<Listino>> getListiniPerArticolo(
+    int idArticolo,
+    String dataOrdine,
+  ) {
+    return (db.select(db.listini)
+          ..join([
+            innerJoin(
+              db.listiniArticolo,
+              db.listiniArticolo.idListino.equalsExp(db.listini.idListino) &
+                  db.listiniArticolo.idArticolo.equals(idArticolo),
+            ),
+          ])
+          ..where(
+            (t) =>
+                db.listiniArticolo.attivo.equals(1) &
+                db.listiniArticolo.validoDa.isSmallerOrEqualValue(dataOrdine) &
+                db.listiniArticolo.validoA.isBiggerOrEqualValue(dataOrdine) &
+                t.codListino.isNotNull() &
+                t.codListino.like('OF2').not() &
+                t.codListino.like('OF4').not() &
+                t.codListino.like('I0').not(),
+          ))
+        .get();
   }
   }
 }
 }

+ 111 - 60
lib/database/daos/ordini_dao.dart

@@ -6,52 +6,71 @@ class OrdiniDao {
   OrdiniDao(this.db);
   OrdiniDao(this.db);
 
 
   Future<Ordine?> getById(int id) {
   Future<Ordine?> getById(int id) {
-    return (db.select(db.ordini)..where((t) => t.idOrdine.equals(id))).getSingleOrNull();
+    return (db.select(
+      db.ordini,
+    )..where((t) => t.idOrdine.equals(id))).getSingleOrNull();
   }
   }
 
 
   Future<Ordine?> getByNumber(int numeroOrdine) {
   Future<Ordine?> getByNumber(int numeroOrdine) {
-    return (db.select(db.ordini)..where((t) => t.numeroOrdine.equals(numeroOrdine))).getSingleOrNull();
+    return (db.select(
+      db.ordini,
+    )..where((t) => t.numeroOrdine.equals(numeroOrdine))).getSingleOrNull();
   }
   }
 
 
   Future<List<Ordine>> customerOrders(int idCliente, bool includeReferences) {
   Future<List<Ordine>> customerOrders(int idCliente, bool includeReferences) {
     return (db.select(db.ordini)
     return (db.select(db.ordini)
-      ..where((t) => t.idCliente.equals(idCliente))
-      ..orderBy([(t) => OrderingTerm(expression: t.dataOrdine, mode: OrderingMode.desc)])
-      ..limit(200)
-    ).get();
+          ..where((t) => t.idCliente.equals(idCliente))
+          ..orderBy([
+            (t) =>
+                OrderingTerm(expression: t.dataOrdine, mode: OrderingMode.desc),
+          ])
+          ..limit(200))
+        .get();
   }
   }
 
 
   Future<List<Ordine>> getLastOrders(int idAgente, int max) {
   Future<List<Ordine>> getLastOrders(int idAgente, int max) {
     return (db.select(db.ordini)
     return (db.select(db.ordini)
-      ..where((t) => t.idAgente.equals(idAgente))
-      ..orderBy([(t) => OrderingTerm(expression: t.dataOrdine, mode: OrderingMode.desc)])
-      ..limit(max)
-    ).get();
+          ..where((t) => t.idAgente.equals(idAgente))
+          ..orderBy([
+            (t) =>
+                OrderingTerm(expression: t.dataOrdine, mode: OrderingMode.desc),
+          ])
+          ..limit(max))
+        .get();
   }
   }
 
 
   Future<List<VOrdiniData>> getOrdersView(int idAgente, {int limit = 200}) {
   Future<List<VOrdiniData>> getOrdersView(int idAgente, {int limit = 200}) {
     return (db.select(db.vOrdini)
     return (db.select(db.vOrdini)
-      ..where((t) => t.idAgente.equals(idAgente))
-      ..orderBy([(t) => OrderingTerm(expression: t.dataOrdine, mode: OrderingMode.desc)])
-      ..limit(limit)
-    ).get();
-  }
-
-  Future<List<VOrdiniData>> searchOrdersView(int idAgente, String filter) async {
+          ..where((t) => t.idAgente.equals(idAgente))
+          ..orderBy([
+            (t) =>
+                OrderingTerm(expression: t.dataOrdine, mode: OrderingMode.desc),
+          ])
+          ..limit(limit))
+        .get();
+  }
+
+  Future<List<VOrdiniData>> searchOrdersView(
+    int idAgente,
+    String filter,
+  ) async {
     final words = filter.split(' ').where((w) => w.isNotEmpty).toList();
     final words = filter.split(' ').where((w) => w.isNotEmpty).toList();
     final patterns = words.map((w) => '%$w%').toList();
     final patterns = words.map((w) => '%$w%').toList();
 
 
     final query = db.select(db.vOrdini)
     final query = db.select(db.vOrdini)
       ..where((t) => t.idAgente.equals(idAgente))
       ..where((t) => t.idAgente.equals(idAgente))
-      ..orderBy([(t) => OrderingTerm(expression: t.dataOrdine, mode: OrderingMode.desc)]);
+      ..orderBy([
+        (t) => OrderingTerm(expression: t.dataOrdine, mode: OrderingMode.desc),
+      ]);
 
 
     for (final p in patterns) {
     for (final p in patterns) {
-      query.where((t) =>
-        t.ragioneSociale.like(p) |
-        t.filiale.like(p) |
-        t.indirizzo.like(p) |
-        t.citta.like(p) |
-        CustomExpression<String>('CAST(numeroOrdine AS TEXT)').like(p)
+      query.where(
+        (t) =>
+            t.ragioneSociale.like(p) |
+            t.filiale.like(p) |
+            t.indirizzo.like(p) |
+            t.citta.like(p) |
+            CustomExpression<String>('CAST(numeroOrdine AS TEXT)').like(p),
       );
       );
     }
     }
 
 
@@ -59,16 +78,16 @@ class OrdiniDao {
   }
   }
 
 
   Future<int> countNewOrdersForAgent(int idAgente) async {
   Future<int> countNewOrdersForAgent(int idAgente) async {
-    final rows = await (db.select(db.vOrdini)
-      ..where((t) => t.idAgente.equals(idAgente) & t.stato.equals('N'))
-    ).get();
+    final rows = await (db.select(
+      db.vOrdini,
+    )..where((t) => t.idAgente.equals(idAgente) & t.stato.equals('N'))).get();
     return rows.length;
     return rows.length;
   }
   }
 
 
   Future<int> countOrdersForAgent(int idAgente) async {
   Future<int> countOrdersForAgent(int idAgente) async {
-    final rows = await (db.select(db.vOrdini)
-      ..where((t) => t.idAgente.equals(idAgente))
-    ).get();
+    final rows = await (db.select(
+      db.vOrdini,
+    )..where((t) => t.idAgente.equals(idAgente))).get();
     return rows.length;
     return rows.length;
   }
   }
 
 
@@ -79,22 +98,28 @@ class OrdiniDao {
         '${firstOfMonth.year.toString().padLeft(4, '0')}-'
         '${firstOfMonth.year.toString().padLeft(4, '0')}-'
         '${firstOfMonth.month.toString().padLeft(2, '0')}-01';
         '${firstOfMonth.month.toString().padLeft(2, '0')}-01';
 
 
-    final rows = await (db.select(db.vOrdini)
-      ..where((t) =>
-          t.idAgente.equals(idAgente) &
-          t.dataOrdine.isNotNull() &
-          t.dataOrdine.isBiggerOrEqualValue(dateStr))
-    ).get();
+    final rows =
+        await (db.select(db.vOrdini)..where(
+              (t) =>
+                  t.idAgente.equals(idAgente) &
+                  t.dataOrdine.isNotNull() &
+                  t.dataOrdine.isBiggerOrEqualValue(dateStr),
+            ))
+            .get();
     return rows.fold<double>(0, (sum, r) => sum + (r.totale ?? 0));
     return rows.fold<double>(0, (sum, r) => sum + (r.totale ?? 0));
   }
   }
 
 
   Future<int> countNewOrders() async {
   Future<int> countNewOrders() async {
-    final rows = await (db.select(db.ordini)..where((t) => t.stato.equals('N'))).get();
+    final rows = await (db.select(
+      db.ordini,
+    )..where((t) => t.stato.equals('N'))).get();
     return rows.length;
     return rows.length;
   }
   }
 
 
   Future<int> countOrdersOnHold() async {
   Future<int> countOrdersOnHold() async {
-    final rows = await (db.select(db.ordini)..where((t) => t.stato.equals('H'))).get();
+    final rows = await (db.select(
+      db.ordini,
+    )..where((t) => t.stato.equals('H'))).get();
     return rows.length;
     return rows.length;
   }
   }
 
 
@@ -104,28 +129,34 @@ class OrdiniDao {
 
 
   Future<List<Ordine>> getUnsentOrders(int max) {
   Future<List<Ordine>> getUnsentOrders(int max) {
     return (db.select(db.ordini)
     return (db.select(db.ordini)
-      ..where((t) => t.stato.equals('N') | t.stato.equals('H'))
-      ..limit(max)
-    ).get();
+          ..where((t) => t.stato.equals('N') | t.stato.equals('H'))
+          ..limit(max))
+        .get();
   }
   }
 
 
   Future<int> generaNumeroOrdine(int idAgente) async {
   Future<int> generaNumeroOrdine(int idAgente) async {
-    final result = await (db.select(db.ordini)
-      ..where((t) => t.idAgente.equals(idAgente))
-      ..orderBy([(t) => OrderingTerm(expression: t.numeroOrdine, mode: OrderingMode.desc)])
-      ..limit(1)
-    ).getSingleOrNull();
+    final result =
+        await (db.select(db.ordini)
+              ..where((t) => t.idAgente.equals(idAgente))
+              ..orderBy([
+                (t) => OrderingTerm(
+                  expression: t.numeroOrdine,
+                  mode: OrderingMode.desc,
+                ),
+              ])
+              ..limit(1))
+            .getSingleOrNull();
     return (result?.numeroOrdine ?? 0) + 1;
     return (result?.numeroOrdine ?? 0) + 1;
   }
   }
 
 
   Future<void> markAsSent(int idOrdine, int idAssegnato) {
   Future<void> markAsSent(int idOrdine, int idAssegnato) {
     return (db.update(db.ordini)..where((t) => t.idOrdine.equals(idOrdine)))
     return (db.update(db.ordini)..where((t) => t.idOrdine.equals(idOrdine)))
-      .write(OrdiniCompanion(stato: const Value('T')));
+        .write(OrdiniCompanion(stato: const Value('T')));
   }
   }
 
 
   Future<void> markAsSentStatus(int idOrdine) {
   Future<void> markAsSentStatus(int idOrdine) {
     return (db.update(db.ordini)..where((t) => t.idOrdine.equals(idOrdine)))
     return (db.update(db.ordini)..where((t) => t.idOrdine.equals(idOrdine)))
-      .write(OrdiniCompanion(stato: const Value('T')));
+        .write(OrdiniCompanion(stato: const Value('T')));
   }
   }
 
 
   Future<int> insertOrder(Ordine order) {
   Future<int> insertOrder(Ordine order) {
@@ -137,7 +168,9 @@ class OrdiniDao {
   }
   }
 
 
   Future<void> deleteOrder(int idOrdine) {
   Future<void> deleteOrder(int idOrdine) {
-    return (db.delete(db.ordini)..where((t) => t.idOrdine.equals(idOrdine))).go();
+    return (db.delete(
+      db.ordini,
+    )..where((t) => t.idOrdine.equals(idOrdine))).go();
   }
   }
 
 
   Future<int> insertOrderLine(RigaOrdine line) {
   Future<int> insertOrderLine(RigaOrdine line) {
@@ -149,36 +182,54 @@ class OrdiniDao {
   }
   }
 
 
   Future<List<RigaOrdine>> getOrderLines(int idOrdine) {
   Future<List<RigaOrdine>> getOrderLines(int idOrdine) {
-    return (db.select(db.righeOrdine)..where((t) => t.idOrdine.equals(idOrdine))).get();
+    return (db.select(
+      db.righeOrdine,
+    )..where((t) => t.idOrdine.equals(idOrdine))).get();
   }
   }
 
 
   Future<void> deleteOrderLine(int idRigaOrdine) {
   Future<void> deleteOrderLine(int idRigaOrdine) {
-    return (db.delete(db.righeOrdine)..where((t) => t.idRigaOrdine.equals(idRigaOrdine))).go();
+    return (db.delete(
+      db.righeOrdine,
+    )..where((t) => t.idRigaOrdine.equals(idRigaOrdine))).go();
   }
   }
 
 
   Future<void> zapOrderLines(int idOrdine) {
   Future<void> zapOrderLines(int idOrdine) {
-    return (db.delete(db.righeOrdine)..where((t) => t.idOrdine.equals(idOrdine))).go();
+    return (db.delete(
+      db.righeOrdine,
+    )..where((t) => t.idOrdine.equals(idOrdine))).go();
   }
   }
 
 
   Future<Ordine?> findByNumeroOrdineSede(String numSede) {
   Future<Ordine?> findByNumeroOrdineSede(String numSede) {
-    return (db.select(db.ordini)..where((t) => t.numeroOrdineSede.equals(numSede))).getSingleOrNull();
+    return (db.select(
+      db.ordini,
+    )..where((t) => t.numeroOrdineSede.equals(numSede))).getSingleOrNull();
   }
   }
 
 
   Future<Ordine?> findByIdOrdineSede(int idSede) {
   Future<Ordine?> findByIdOrdineSede(int idSede) {
-    return (db.select(db.ordini)..where((t) => t.idOrdineSede.equals(idSede))).getSingleOrNull();
+    return (db.select(
+      db.ordini,
+    )..where((t) => t.idOrdineSede.equals(idSede))).getSingleOrNull();
   }
   }
 
 
   Future<double> totalAmountItems(int idOrdine) async {
   Future<double> totalAmountItems(int idOrdine) async {
-    final lines = await (db.select(db.righeOrdine)
-      ..where((t) => t.idOrdine.equals(idOrdine) & (t.rigaPromozione.equals(0) | t.rigaPromozione.isNull()))
-    ).get();
+    final lines =
+        await (db.select(db.righeOrdine)..where(
+              (t) =>
+                  t.idOrdine.equals(idOrdine) &
+                  (t.rigaPromozione.equals(0) | t.rigaPromozione.isNull()),
+            ))
+            .get();
     return lines.fold<double>(0.0, (sum, l) => sum + (l.totale ?? 0.0));
     return lines.fold<double>(0.0, (sum, l) => sum + (l.totale ?? 0.0));
   }
   }
 
 
   Future<double> totalQtyItems(int idOrdine) async {
   Future<double> totalQtyItems(int idOrdine) async {
-    final lines = await (db.select(db.righeOrdine)
-      ..where((t) => t.idOrdine.equals(idOrdine) & (t.rigaPromozione.equals(0) | t.rigaPromozione.isNull()))
-    ).get();
+    final lines =
+        await (db.select(db.righeOrdine)..where(
+              (t) =>
+                  t.idOrdine.equals(idOrdine) &
+                  (t.rigaPromozione.equals(0) | t.rigaPromozione.isNull()),
+            ))
+            .get();
     return lines.fold<double>(0.0, (sum, l) => sum + (l.quantita ?? 0.0));
     return lines.fold<double>(0.0, (sum, l) => sum + (l.quantita ?? 0.0));
   }
   }
 }
 }

+ 7 - 7
lib/database/database.g.dart

@@ -8359,7 +8359,7 @@ class $ListiniClienteTable extends ListiniCliente
   );
   );
   @override
   @override
   late final GeneratedColumn<int> idListinoCliente = GeneratedColumn<int>(
   late final GeneratedColumn<int> idListinoCliente = GeneratedColumn<int>(
-    'id_listino_cliente',
+    'idListinoCliente',
     aliasedName,
     aliasedName,
     false,
     false,
     hasAutoIncrement: true,
     hasAutoIncrement: true,
@@ -8513,11 +8513,11 @@ class $ListiniClienteTable extends ListiniCliente
   }) {
   }) {
     final context = VerificationContext();
     final context = VerificationContext();
     final data = instance.toColumns(true);
     final data = instance.toColumns(true);
-    if (data.containsKey('id_listino_cliente')) {
+    if (data.containsKey('idListinoCliente')) {
       context.handle(
       context.handle(
         _idListinoClienteMeta,
         _idListinoClienteMeta,
         idListinoCliente.isAcceptableOrUnknown(
         idListinoCliente.isAcceptableOrUnknown(
-          data['id_listino_cliente']!,
+          data['idListinoCliente']!,
           _idListinoClienteMeta,
           _idListinoClienteMeta,
         ),
         ),
       );
       );
@@ -8602,7 +8602,7 @@ class $ListiniClienteTable extends ListiniCliente
     return ListinoCliente(
     return ListinoCliente(
       idListinoCliente: attachedDatabase.typeMapping.read(
       idListinoCliente: attachedDatabase.typeMapping.read(
         DriftSqlType.int,
         DriftSqlType.int,
-        data['${effectivePrefix}id_listino_cliente'],
+        data['${effectivePrefix}idListinoCliente'],
       )!,
       )!,
       idListino: attachedDatabase.typeMapping.read(
       idListino: attachedDatabase.typeMapping.read(
         DriftSqlType.int,
         DriftSqlType.int,
@@ -8687,7 +8687,7 @@ class ListinoCliente extends DataClass implements Insertable<ListinoCliente> {
   @override
   @override
   Map<String, Expression> toColumns(bool nullToAbsent) {
   Map<String, Expression> toColumns(bool nullToAbsent) {
     final map = <String, Expression>{};
     final map = <String, Expression>{};
-    map['id_listino_cliente'] = Variable<int>(idListinoCliente);
+    map['idListinoCliente'] = Variable<int>(idListinoCliente);
     if (!nullToAbsent || idListino != null) {
     if (!nullToAbsent || idListino != null) {
       map['idListino'] = Variable<int>(idListino);
       map['idListino'] = Variable<int>(idListino);
     }
     }
@@ -8956,7 +8956,7 @@ class ListiniClienteCompanion extends UpdateCompanion<ListinoCliente> {
     Expression<String>? stato,
     Expression<String>? stato,
   }) {
   }) {
     return RawValuesInsertable({
     return RawValuesInsertable({
-      if (idListinoCliente != null) 'id_listino_cliente': idListinoCliente,
+      if (idListinoCliente != null) 'idListinoCliente': idListinoCliente,
       if (idListino != null) 'idListino': idListino,
       if (idListino != null) 'idListino': idListino,
       if (idCliente != null) 'idCliente': idCliente,
       if (idCliente != null) 'idCliente': idCliente,
       if (idArticolo != null) 'idArticolo': idArticolo,
       if (idArticolo != null) 'idArticolo': idArticolo,
@@ -9005,7 +9005,7 @@ class ListiniClienteCompanion extends UpdateCompanion<ListinoCliente> {
   Map<String, Expression> toColumns(bool nullToAbsent) {
   Map<String, Expression> toColumns(bool nullToAbsent) {
     final map = <String, Expression>{};
     final map = <String, Expression>{};
     if (idListinoCliente.present) {
     if (idListinoCliente.present) {
-      map['id_listino_cliente'] = Variable<int>(idListinoCliente.value);
+      map['idListinoCliente'] = Variable<int>(idListinoCliente.value);
     }
     }
     if (idListino.present) {
     if (idListino.present) {
       map['idListino'] = Variable<int>(idListino.value);
       map['idListino'] = Variable<int>(idListino.value);

+ 4 - 1
lib/database/db_connector_io.dart

@@ -7,7 +7,10 @@ import 'package:flutter/services.dart' show rootBundle;
 import '../core/constants.dart';
 import '../core/constants.dart';
 
 
 QueryExecutor createDb(String dirPath, String dbName) {
 QueryExecutor createDb(String dirPath, String dbName) {
-  return NativeDatabase(File(p.join(dirPath, dbName)));
+  return NativeDatabase(
+    File(p.join(dirPath, dbName)),
+    logStatements: true,
+  );
 }
 }
 
 
 Future<String> ensureDbReady() async {
 Future<String> ensureDbReady() async {

+ 8 - 4
lib/database/tables/listini_cliente.dart

@@ -2,7 +2,8 @@ import 'package:drift/drift.dart';
 
 
 @DataClassName('ListinoCliente')
 @DataClassName('ListinoCliente')
 class ListiniCliente extends Table {
 class ListiniCliente extends Table {
-  IntColumn get idListinoCliente => integer().autoIncrement()();
+  IntColumn get idListinoCliente =>
+      integer().named('idListinoCliente').autoIncrement()();
   IntColumn get idListino => integer().named('idListino').nullable()();
   IntColumn get idListino => integer().named('idListino').nullable()();
   IntColumn get idCliente => integer().named('idCliente').nullable()();
   IntColumn get idCliente => integer().named('idCliente').nullable()();
   IntColumn get idArticolo => integer().named('idArticolo').nullable()();
   IntColumn get idArticolo => integer().named('idArticolo').nullable()();
@@ -10,9 +11,12 @@ class ListiniCliente extends Table {
   TextColumn get validoDa => text().named('validoDa').nullable()();
   TextColumn get validoDa => text().named('validoDa').nullable()();
   TextColumn get validoA => text().named('validoA').nullable()();
   TextColumn get validoA => text().named('validoA').nullable()();
   RealColumn get prezzo => real().named('prezzo').nullable()();
   RealColumn get prezzo => real().named('prezzo').nullable()();
-  IntColumn get attivo => integer().named('attivo').withDefault(const Constant(1))();
-  TextColumn get annullato => text().named('annullato').withDefault(const Constant('N'))();
-  TextColumn get listinoSostitutivo => text().named('listinoSostitutivo').nullable()();
+  IntColumn get attivo =>
+      integer().named('attivo').withDefault(const Constant(1))();
+  TextColumn get annullato =>
+      text().named('annullato').withDefault(const Constant('N'))();
+  TextColumn get listinoSostitutivo =>
+      text().named('listinoSostitutivo').nullable()();
   TextColumn get stato => text().named('stato').nullable()();
   TextColumn get stato => text().named('stato').nullable()();
 
 
   @override
   @override

+ 24 - 2
lib/providers/auth_provider.dart

@@ -5,6 +5,9 @@ import 'database_provider.dart';
 import '../../services/auth_service.dart';
 import '../../services/auth_service.dart';
 import 'sync_provider.dart';
 import 'sync_provider.dart';
 
 
+const _kRememberedUsername = 'REMEMBERED_USERNAME';
+const _kRememberedPassword = 'REMEMBERED_PASSWORD';
+
 class AuthState {
 class AuthState {
   final Agente? agente;
   final Agente? agente;
   final bool isLoading;
   final bool isLoading;
@@ -42,14 +45,31 @@ class AuthNotifier extends Notifier<AuthState> {
     state = AuthState(isInitialized: initialized);
     state = AuthState(isInitialized: initialized);
   }
   }
 
 
-  Future<void> login(String code, String password, String url) async {
+  Future<void> login(
+    String code,
+    String password,
+    String url, {
+    bool rememberMe = false,
+  }) async {
     state = const AuthState(isLoading: true);
     state = const AuthState(isLoading: true);
     try {
     try {
-      await ref.read(parametriDaoProvider).set(AppConstants.kUrlParam, url);
+      final dao = ref.read(parametriDaoProvider);
+      await dao.set(AppConstants.kUrlParam, url);
+
       final authService = ref.read(authServiceProvider);
       final authService = ref.read(authServiceProvider);
+      //print("Attempting login with code: $code, password: $password, url: $url");
       final agente = await authService.login(code, password);
       final agente = await authService.login(code, password);
+      print(agente);
       if (agente != null) {
       if (agente != null) {
         state = AuthState(agente: agente, isInitialized: true);
         state = AuthState(agente: agente, isInitialized: true);
+
+        if (rememberMe) {
+          await dao.set(_kRememberedUsername, code);
+          await dao.set(_kRememberedPassword, password);
+        } else {
+          await dao.set(_kRememberedUsername, '');
+          await dao.set(_kRememberedPassword, '');
+        }
       } else {
       } else {
         state = const AuthState(
         state = const AuthState(
           error: 'Codice agente o password errati',
           error: 'Codice agente o password errati',
@@ -62,6 +82,7 @@ class AuthNotifier extends Notifier<AuthState> {
   }
   }
 
 
   Future<void> initialize({
   Future<void> initialize({
+    required int idAgente,
     required String codAgente,
     required String codAgente,
     required String password,
     required String password,
     String? ragioneSociale,
     String? ragioneSociale,
@@ -71,6 +92,7 @@ class AuthNotifier extends Notifier<AuthState> {
     try {
     try {
       final authService = ref.read(authServiceProvider);
       final authService = ref.read(authServiceProvider);
       await authService.initializeAgent(
       await authService.initializeAgent(
+        idAgente: idAgente,
         codAgente: codAgente,
         codAgente: codAgente,
         pwd: password,
         pwd: password,
         ragioneSociale: ragioneSociale,
         ragioneSociale: ragioneSociale,

+ 8 - 0
lib/providers/order_provider.dart

@@ -57,6 +57,14 @@ class OrderNotifier extends Notifier<OrderState> {
     }
     }
   }
   }
 
 
+  void setIdCliente(int idCliente) {
+    if (state.order == null) return;
+    state = OrderState(
+      order: state.order!.copyWith(idCliente: Value<int?>(idCliente)),
+      lines: state.lines,
+    );
+  }
+
   Future<void> addLine(RigaOrdine line) async {
   Future<void> addLine(RigaOrdine line) async {
     if (state.order == null) return;
     if (state.order == null) return;
     final dao = ref.read(ordiniDaoProvider);
     final dao = ref.read(ordiniDaoProvider);

+ 26 - 6
lib/providers/sync_provider.dart

@@ -41,6 +41,7 @@ final ordineSyncServiceProvider = Provider<OrdineSyncService>((ref) {
     ref.read(ordiniDaoProvider),
     ref.read(ordiniDaoProvider),
     ref.read(clientiDaoProvider),
     ref.read(clientiDaoProvider),
     ref.read(filialiDaoProvider),
     ref.read(filialiDaoProvider),
+    ref.read(agentiDaoProvider),
   );
   );
 });
 });
 
 
@@ -86,8 +87,15 @@ class SyncNotifier extends Notifier<SyncState> {
   @override
   @override
   SyncState build() => const SyncState();
   SyncState build() => const SyncState();
 
 
-  Future<void> startFullSync(int idAgente, String codAgente, {bool forceFullSync = false}) async {
-    state = const SyncState(isSyncing: true, message: 'Avvio sincronizzazione...');
+  Future<void> startFullSync(
+    int idAgente,
+    String codAgente, {
+    bool forceFullSync = false,
+  }) async {
+    state = const SyncState(
+      isSyncing: true,
+      message: 'Avvio sincronizzazione...',
+    );
     try {
     try {
       final agentiDao = ref.read(agentiDaoProvider);
       final agentiDao = ref.read(agentiDaoProvider);
       final agente = await agentiDao.findByCode(codAgente);
       final agente = await agentiDao.findByCode(codAgente);
@@ -114,7 +122,11 @@ class SyncNotifier extends Notifier<SyncState> {
       _update('Clienti attivi scaricati', 0.16);
       _update('Clienti attivi scaricati', 0.16);
       await filialeSync.uploadNewDestinations(idAgente, codAgente);
       await filialeSync.uploadNewDestinations(idAgente, codAgente);
       _update('Destinazioni inviate', 0.18);
       _update('Destinazioni inviate', 0.18);
-      await filialeSync.downloadDestinations(idAgente, codAgente, lastUpdateStr);
+      await filialeSync.downloadDestinations(
+        idAgente,
+        codAgente,
+        lastUpdateStr,
+      );
       _update('Destinazioni scaricate', 0.20);
       _update('Destinazioni scaricate', 0.20);
       await ordineSync.uploadNewOrders(idAgente, codAgente);
       await ordineSync.uploadNewOrders(idAgente, codAgente);
       _update('Ordini inviati', 0.22);
       _update('Ordini inviati', 0.22);
@@ -147,7 +159,10 @@ class SyncNotifier extends Notifier<SyncState> {
           '${now.year}${_pad(now.month)}${_pad(now.day)}${_pad(now.hour)}${_pad(now.minute)}';
           '${now.year}${_pad(now.month)}${_pad(now.day)}${_pad(now.hour)}${_pad(now.minute)}';
       await parametriDao.set('lastUpdate', newLastUpdate);
       await parametriDao.set('lastUpdate', newLastUpdate);
 
 
-      state = const SyncState(message: 'Sincronizzazione completata!', progress: 1.0);
+      state = const SyncState(
+        message: 'Sincronizzazione completata!',
+        progress: 1.0,
+      );
 
 
       ref.invalidate(articleSearchProvider);
       ref.invalidate(articleSearchProvider);
       ref.invalidate(activeArticleSearchProvider);
       ref.invalidate(activeArticleSearchProvider);
@@ -162,7 +177,10 @@ class SyncNotifier extends Notifier<SyncState> {
       ref.invalidate(dashboardProvider);
       ref.invalidate(dashboardProvider);
       ref.invalidate(paymentsProvider);
       ref.invalidate(paymentsProvider);
     } catch (e) {
     } catch (e) {
-      state = SyncState(error: e.toString(), message: 'Errore durante la sincronizzazione');
+      state = SyncState(
+        error: e.toString(),
+        message: 'Errore durante la sincronizzazione',
+      );
     }
     }
   }
   }
 
 
@@ -173,4 +191,6 @@ class SyncNotifier extends Notifier<SyncState> {
   }
   }
 }
 }
 
 
-final syncProvider = NotifierProvider<SyncNotifier, SyncState>(SyncNotifier.new);
+final syncProvider = NotifierProvider<SyncNotifier, SyncState>(
+  SyncNotifier.new,
+);

+ 3 - 0
lib/services/auth_service.dart

@@ -4,6 +4,7 @@ import 'package:http/http.dart' as http;
 import '../database/daos/agenti_dao.dart';
 import '../database/daos/agenti_dao.dart';
 import '../database/daos/parametri_dao.dart';
 import '../database/daos/parametri_dao.dart';
 import '../database/database.dart';
 import '../database/database.dart';
+import '../database/tables/parametri.dart';
 import '../core/constants.dart';
 import '../core/constants.dart';
 import 'api_service.dart';
 import 'api_service.dart';
 
 
@@ -51,6 +52,7 @@ class AuthService {
   }
   }
 
 
   Future<void> initializeAgent({
   Future<void> initializeAgent({
+    required int idAgente,
     required String codAgente,
     required String codAgente,
     required String pwd,
     required String pwd,
     String? ragioneSociale,
     String? ragioneSociale,
@@ -59,6 +61,7 @@ class AuthService {
     await _parametriDao.set(AppConstants.kUrlParam, url);
     await _parametriDao.set(AppConstants.kUrlParam, url);
     await _agentiDao.insertAgente(
     await _agentiDao.insertAgente(
       AgentiCompanion(
       AgentiCompanion(
+	idAgente: Value(idAgente),
         codAgente: Value(codAgente),
         codAgente: Value(codAgente),
         pwd: Value(pwd),
         pwd: Value(pwd),
         ragioneSociale: Value(ragioneSociale ?? codAgente),
         ragioneSociale: Value(ragioneSociale ?? codAgente),

+ 14 - 1
lib/services/sync/ordine_sync_service.dart

@@ -1,4 +1,5 @@
 import 'package:drift/drift.dart';
 import 'package:drift/drift.dart';
+import 'package:ristoris/database/daos/agenti_dao.dart';
 import '../api_service.dart';
 import '../api_service.dart';
 import '../../database/database.dart';
 import '../../database/database.dart';
 import '../../database/daos/ordini_dao.dart';
 import '../../database/daos/ordini_dao.dart';
@@ -11,12 +12,14 @@ class OrdineSyncService {
   final OrdiniDao _ordiniDao;
   final OrdiniDao _ordiniDao;
   final ClientiDao _clientiDao;
   final ClientiDao _clientiDao;
   final FilialiDao _filialiDao;
   final FilialiDao _filialiDao;
+  final AgentiDao _agentiDao;
 
 
   OrdineSyncService(
   OrdineSyncService(
     this._api,
     this._api,
     this._ordiniDao,
     this._ordiniDao,
     this._clientiDao,
     this._clientiDao,
     this._filialiDao,
     this._filialiDao,
+    this._agentiDao,
   );
   );
 
 
   Future<int> uploadNewOrders(int idAgente, String codAgente) async {
   Future<int> uploadNewOrders(int idAgente, String codAgente) async {
@@ -89,6 +92,7 @@ class OrdineSyncService {
       );
       );
       final db = _ordiniDao.db;
       final db = _ordiniDao.db;
       final cacheCliente = <String, int?>{};
       final cacheCliente = <String, int?>{};
+      final cacheAgente = <int, Agente>{};
       final cacheFilialeById = <int, int?>{};
       final cacheFilialeById = <int, int?>{};
       final cacheFilialeByRemoteId = <int, int?>{};
       final cacheFilialeByRemoteId = <int, int?>{};
       int count = 0;
       int count = 0;
@@ -122,6 +126,15 @@ class OrdineSyncService {
             continue;
             continue;
           }
           }
 
 
+          final codAgente = json['codAgente'] as String?;
+          Agente? agente = cacheAgente[idAgente];
+          if (agente == null) {
+            agente = await _agentiDao.findByCode(codAgente!);
+            if (agente != null) {
+              cacheAgente[idAgente] = agente;
+            }
+          }
+
           final codCliente = json['codCliente'] as String?;
           final codCliente = json['codCliente'] as String?;
           int? localIdCliente;
           int? localIdCliente;
           if (codCliente != null) {
           if (codCliente != null) {
@@ -170,7 +183,7 @@ class OrdineSyncService {
             idFiliale: Value(localIdFiliale),
             idFiliale: Value(localIdFiliale),
             stato: Value('T'),
             stato: Value('T'),
             idListino: Value(null),
             idListino: Value(null),
-            idAgente: Value(idAgente),
+            idAgente: Value(agente!.idAgente),
             idPagamento: Value(json['idPagamento'] as int?),
             idPagamento: Value(json['idPagamento'] as int?),
           );
           );
 
 

+ 5 - 3
lib/ui/pages/catalog/catalog_page.dart

@@ -31,9 +31,10 @@ class _CatalogPageState extends ConsumerState<CatalogPage> {
 
 
     return Scaffold(
     return Scaffold(
       appBar: AppBar(title: const Text('Catalogo')),
       appBar: AppBar(title: const Text('Catalogo')),
-      body: Column(
-        children: [
-          sw.SearchBarWidget(
+      body: SafeArea(
+        child: Column(
+          children: [
+            sw.SearchBarWidget(
             controller: _searchCtrl,
             controller: _searchCtrl,
             hint: 'Cerca articolo...',
             hint: 'Cerca articolo...',
             onChanged: (v) => setState(() => _filter = v),
             onChanged: (v) => setState(() => _filter = v),
@@ -67,6 +68,7 @@ class _CatalogPageState extends ConsumerState<CatalogPage> {
           ),
           ),
         ],
         ],
       ),
       ),
+      ),
     );
     );
   }
   }
 }
 }

+ 38 - 34
lib/ui/pages/customers/customer_detail_page.dart

@@ -41,24 +41,26 @@ class CustomerDetailPage extends ConsumerWidget {
             ],
             ],
           ),
           ),
         ),
         ),
-        body: FutureBuilder<Cliente?>(
-          future: clienteAsync,
-          builder: (_, snap) {
-            final cliente = snap.data;
-            if (cliente == null)
-              return const Center(child: CircularProgressIndicator());
-            return TabBarView(
-              children: [
-                _InfoTab(cliente: cliente, theme: theme),
-                _OrdersTab(idCliente: id, theme: theme),
-                _DestinationsTab(idCliente: id, theme: theme),
-                _PaymentsTab(
-                  idCliente: cliente.idClienteRemoto ?? 0,
-                  theme: theme,
-                ),
-              ],
-            );
-          },
+        body: SafeArea(
+          child: FutureBuilder<Cliente?>(
+            future: clienteAsync,
+            builder: (_, snap) {
+              final cliente = snap.data;
+              if (cliente == null)
+                return const Center(child: CircularProgressIndicator());
+              return TabBarView(
+                children: [
+                  _InfoTab(cliente: cliente, theme: theme),
+                  _OrdersTab(idCliente: id, theme: theme),
+                  _DestinationsTab(idCliente: id, theme: theme),
+                  _PaymentsTab(
+                    idCliente: cliente.idClienteRemoto ?? 0,
+                    theme: theme,
+                  ),
+                ],
+              );
+            },
+          ),
         ),
         ),
       ),
       ),
     );
     );
@@ -145,22 +147,24 @@ class _OrdersTab extends ConsumerWidget {
   Widget build(BuildContext context, WidgetRef ref) {
   Widget build(BuildContext context, WidgetRef ref) {
     final ordiniDao = ref.read(ordiniDaoProvider);
     final ordiniDao = ref.read(ordiniDaoProvider);
     return Scaffold(
     return Scaffold(
-      body: FutureBuilder(
-        future: ordiniDao.customerOrders(idCliente, false),
-        builder: (_, snap) {
-          if (!snap.hasData)
-            return const Center(child: CircularProgressIndicator());
-          final orders = snap.data!;
-          if (orders.isEmpty) return const Center(child: Text('Nessun ordine'));
-          return ListView.builder(
-            itemCount: orders.length,
-            itemBuilder: (_, i) => ListTile(
-              title: Text('Ordine #${orders[i].numeroOrdine ?? ""}'),
-              subtitle: Text(orders[i].dataOrdine ?? ''),
-              onTap: () => context.push('/dashboard/orders/${orders[i].idOrdine}'),
-            ),
-          );
-        },
+      body: SafeArea(
+        child: FutureBuilder(
+          future: ordiniDao.customerOrders(idCliente, false),
+          builder: (_, snap) {
+            if (!snap.hasData)
+              return const Center(child: CircularProgressIndicator());
+            final orders = snap.data!;
+            if (orders.isEmpty) return const Center(child: Text('Nessun ordine'));
+            return ListView.builder(
+              itemCount: orders.length,
+              itemBuilder: (_, i) => ListTile(
+                title: Text('Ordine #${orders[i].numeroOrdine ?? ""}'),
+                subtitle: Text(orders[i].dataOrdine ?? ''),
+                onTap: () => context.push('/dashboard/orders/${orders[i].idOrdine}'),
+              ),
+            );
+          },
+        ),
       ),
       ),
       floatingActionButton: FloatingActionButton(
       floatingActionButton: FloatingActionButton(
         heroTag: 'addOrder',
         heroTag: 'addOrder',

+ 41 - 39
lib/ui/pages/customers/customer_list_page.dart

@@ -39,46 +39,48 @@ class _CustomerListPageState extends ConsumerState<CustomerListPage> {
 
 
     return Scaffold(
     return Scaffold(
       appBar: AppBar(title: const Text('Clienti')),
       appBar: AppBar(title: const Text('Clienti')),
-      body: Column(
-        children: [
-          sw.SearchBarWidget(
-            controller: _searchCtrl,
-            hint: 'Cerca cliente...',
-            onChanged: (v) => setState(() => _filter = v),
-            onClear: () {
-              _searchCtrl.clear();
-              setState(() => _filter = '');
-            },
-          ),
-          Expanded(
-            child:
-                customersAsync?.when(
-                  data: (customers) {
-                    if (customers.isEmpty)
-                      return const EmptyState(
-                        icon: Icons.people_outline,
-                        title: 'Nessun cliente',
+      body: SafeArea(
+        child: Column(
+          children: [
+            sw.SearchBarWidget(
+              controller: _searchCtrl,
+              hint: 'Cerca cliente...',
+              onChanged: (v) => setState(() => _filter = v),
+              onClear: () {
+                _searchCtrl.clear();
+                setState(() => _filter = '');
+              },
+            ),
+            Expanded(
+              child:
+                  customersAsync?.when(
+                    data: (customers) {
+                      if (customers.isEmpty)
+                        return const EmptyState(
+                          icon: Icons.people_outline,
+                          title: 'Nessun cliente',
+                        );
+                      return GridView.builder(
+                        padding: const EdgeInsets.all(16),
+                        gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
+                          maxCrossAxisExtent: 450,
+                          mainAxisSpacing: 16,
+                          crossAxisSpacing: 16,
+                          childAspectRatio: 1.2,
+                        ),
+                        itemCount: customers.length,
+                        itemBuilder: (_, i) =>
+                            CustomerCard(cliente: customers[i]),
                       );
                       );
-                    return GridView.builder(
-                      padding: const EdgeInsets.all(16),
-                      gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
-                        maxCrossAxisExtent: 470,
-                        mainAxisSpacing: 16,
-                        crossAxisSpacing: 16,
-                        childAspectRatio: 1.2,
-                      ),
-                      itemCount: customers.length,
-                      itemBuilder: (_, i) =>
-                          CustomerCard(cliente: customers[i]),
-                    );
-                  },
-                  loading: () =>
-                      const Center(child: CircularProgressIndicator()),
-                  error: (e, _) => Center(child: Text('Errore: $e')),
-                ) ??
-                const Center(child: CircularProgressIndicator()),
-          ),
-        ],
+                    },
+                    loading: () =>
+                        const Center(child: CircularProgressIndicator()),
+                    error: (e, _) => Center(child: Text('Errore: $e')),
+                  ) ??
+                  const Center(child: CircularProgressIndicator()),
+            ),
+          ],
+        ),
       ),
       ),
     );
     );
   }
   }

+ 9 - 8
lib/ui/pages/dashboard/dashboard_page.dart

@@ -33,14 +33,15 @@ class DashboardPage extends ConsumerWidget {
         onSync: () => context.go('/dashboard/sync'),
         onSync: () => context.go('/dashboard/sync'),
         onLogout: () => ref.read(authProvider.notifier).logout(),
         onLogout: () => ref.read(authProvider.notifier).logout(),
       ),
       ),
-      body:
-          dashboardAsync?.when(
-            data: (data) =>
-                _DashboardContent(data: data, theme: theme, context: context),
-            loading: () => const Center(child: CircularProgressIndicator()),
-            error: (e, _) => Center(child: Text('Errore: $e')),
-          ) ??
-          const Center(child: CircularProgressIndicator()),
+      body: SafeArea(
+        child: dashboardAsync?.when(
+          data: (data) =>
+              _DashboardContent(data: data, theme: theme, context: context),
+          loading: () => const Center(child: CircularProgressIndicator()),
+          error: (e, _) => Center(child: Text('Errore: $e')),
+        ) ??
+        const Center(child: CircularProgressIndicator()),
+      ),
     );
     );
   }
   }
 }
 }

+ 12 - 5
lib/ui/pages/login/init_page.dart

@@ -45,8 +45,10 @@ class _InitPageState extends ConsumerState<InitPage> {
     final cs = theme.colorScheme;
     final cs = theme.colorScheme;
 
 
     return Scaffold(
     return Scaffold(
-      body: Stack(
-        children: [
+      body: SafeArea(
+        top: false,
+        child: Stack(
+          children: [
           Positioned(
           Positioned(
             top: -MediaQuery.of(context).size.height * 0.08,
             top: -MediaQuery.of(context).size.height * 0.08,
             right: -MediaQuery.of(context).size.width * 0.05,
             right: -MediaQuery.of(context).size.width * 0.05,
@@ -92,6 +94,7 @@ class _InitPageState extends ConsumerState<InitPage> {
           ),
           ),
         ],
         ],
       ),
       ),
+      ),
     );
     );
   }
   }
 
 
@@ -187,7 +190,10 @@ class _InitPageState extends ConsumerState<InitPage> {
                     ? null
                     ? null
                     : () {
                     : () {
                         if (_formKey.currentState!.validate()) {
                         if (_formKey.currentState!.validate()) {
-                          ref.read(authProvider.notifier).initialize(
+                          ref
+                              .read(authProvider.notifier)
+                              .initialize(
+                                idAgente: 1,
                                 codAgente: _codiceCtrl.text,
                                 codAgente: _codiceCtrl.text,
                                 password: _passwordCtrl.text,
                                 password: _passwordCtrl.text,
                                 ragioneSociale: _ragsocCtrl.text.isEmpty
                                 ragioneSociale: _ragsocCtrl.text.isEmpty
@@ -208,7 +214,8 @@ class _InitPageState extends ConsumerState<InitPage> {
                       )
                       )
                     : const Icon(Icons.arrow_forward),
                     : const Icon(Icons.arrow_forward),
                 label: Text(
                 label: Text(
-                    authState.isLoading ? 'Configurazione...' : 'Configura'),
+                  authState.isLoading ? 'Configurazione...' : 'Configura',
+                ),
               ),
               ),
               if (authState.error != null) ...[
               if (authState.error != null) ...[
                 const SizedBox(height: 16),
                 const SizedBox(height: 16),
@@ -272,7 +279,7 @@ class _InitPageState extends ConsumerState<InitPage> {
           controller: _passwordCtrl,
           controller: _passwordCtrl,
           obscureText: _obscurePassword,
           obscureText: _obscurePassword,
           decoration: InputDecoration(
           decoration: InputDecoration(
-            hintText: '\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022',
+            hintText: '',
             prefixIcon: const Icon(Icons.lock_outline, size: 20),
             prefixIcon: const Icon(Icons.lock_outline, size: 20),
             suffixIcon: IconButton(
             suffixIcon: IconButton(
               icon: Icon(
               icon: Icon(

+ 24 - 2
lib/ui/pages/login/login_page.dart

@@ -23,6 +23,7 @@ class _LoginPageState extends ConsumerState<LoginPage> {
   void initState() {
   void initState() {
     super.initState();
     super.initState();
     _loadUrl();
     _loadUrl();
+    _loadRememberedCredentials();
   }
   }
 
 
   Future<void> _loadUrl() async {
   Future<void> _loadUrl() async {
@@ -32,6 +33,23 @@ class _LoginPageState extends ConsumerState<LoginPage> {
     }
     }
   }
   }
 
 
+  Future<void> _loadRememberedCredentials() async {
+    final dao = ref.read(parametriDaoProvider);
+    final username = await dao.read('REMEMBERED_USERNAME');
+    final password = await dao.read('REMEMBERED_PASSWORD');
+    if (username != null &&
+        username.isNotEmpty &&
+        password != null &&
+        password.isNotEmpty &&
+        mounted) {
+      _codiceCtrl.text = username;
+      _passwordCtrl.text = password;
+      setState(() {
+        _rememberMe = true;
+      });
+    }
+  }
+
   @override
   @override
   void dispose() {
   void dispose() {
     _codiceCtrl.dispose();
     _codiceCtrl.dispose();
@@ -47,8 +65,10 @@ class _LoginPageState extends ConsumerState<LoginPage> {
     final cs = theme.colorScheme;
     final cs = theme.colorScheme;
 
 
     return Scaffold(
     return Scaffold(
-      body: Stack(
-        children: [
+      body: SafeArea(
+        top: false,
+        child: Stack(
+          children: [
           Positioned(
           Positioned(
             top: -MediaQuery.of(context).size.height * 0.08,
             top: -MediaQuery.of(context).size.height * 0.08,
             right: -MediaQuery.of(context).size.width * 0.05,
             right: -MediaQuery.of(context).size.width * 0.05,
@@ -95,6 +115,7 @@ class _LoginPageState extends ConsumerState<LoginPage> {
           ),
           ),
         ],
         ],
       ),
       ),
+      ),
     );
     );
   }
   }
 
 
@@ -193,6 +214,7 @@ class _LoginPageState extends ConsumerState<LoginPage> {
                                 _codiceCtrl.text,
                                 _codiceCtrl.text,
                                 _passwordCtrl.text,
                                 _passwordCtrl.text,
                                 _urlCtrl.text,
                                 _urlCtrl.text,
+                                rememberMe: _rememberMe,
                               );
                               );
                         }
                         }
                       },
                       },

+ 540 - 121
lib/ui/pages/orders/order_edit_page.dart

@@ -1,12 +1,16 @@
 import 'package:flutter/material.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:intl/intl.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 '../../../providers/auth_provider.dart';
+import '../../widgets/cod_desc_dropdown_item.dart';
 import '../../../providers/order_provider.dart';
 import '../../../providers/order_provider.dart';
 import '../../../providers/database_provider.dart';
 import '../../../providers/database_provider.dart';
 import '../../../database/database.dart';
 import '../../../database/database.dart';
 import '../../../database/daos/listini_dao.dart';
 import '../../../database/daos/listini_dao.dart';
 import '../../widgets/article_image.dart';
 import '../../widgets/article_image.dart';
+import 'selezione_cliente_page.dart';
 
 
 class OrderEditPage extends ConsumerStatefulWidget {
 class OrderEditPage extends ConsumerStatefulWidget {
   final int? id;
   final int? id;
@@ -28,6 +32,7 @@ class _OrderEditPageState extends ConsumerState<OrderEditPage>
 
 
   List<Articolo> _searchResults = [];
   List<Articolo> _searchResults = [];
   bool _searching = false;
   bool _searching = false;
+  bool _usaListinoCliente = true;
 
 
   List<Filiale> _filiali = [];
   List<Filiale> _filiali = [];
   List<Listino> _listini = [];
   List<Listino> _listini = [];
@@ -44,6 +49,11 @@ class _OrderEditPageState extends ConsumerState<OrderEditPage>
   void initState() {
   void initState() {
     super.initState();
     super.initState();
     _tabController = TabController(length: 2, vsync: this);
     _tabController = TabController(length: 2, vsync: this);
+    _tabController.addListener(() {
+      if (_tabController.index == 1 && _searchResults.isEmpty && _artCtrl.text.isEmpty) {
+        _searchArticles('');
+      }
+    });
     WidgetsBinding.instance.addPostFrameCallback((_) => _init());
     WidgetsBinding.instance.addPostFrameCallback((_) => _init());
   }
   }
 
 
@@ -100,16 +110,25 @@ class _OrderEditPageState extends ConsumerState<OrderEditPage>
   }
   }
 
 
   Future<void> _searchArticles(String q) async {
   Future<void> _searchArticles(String q) async {
-    if (q.length < 2) {
-      setState(() {
-        _searchResults = [];
-        _searching = false;
-      });
-      return;
-    }
     setState(() => _searching = true);
     setState(() => _searching = true);
     final dao = ref.read(articoliDaoProvider);
     final dao = ref.read(articoliDaoProvider);
-    final results = await dao.getItems(q);
+    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(() {
     setState(() {
       _searchResults = results;
       _searchResults = results;
       _searching = false;
       _searching = false;
@@ -119,8 +138,13 @@ class _OrderEditPageState extends ConsumerState<OrderEditPage>
   void _showArticlePicker(Articolo art) async {
   void _showArticlePicker(Articolo art) async {
     final agente = ref.read(authProvider).agente;
     final agente = ref.read(authProvider).agente;
     final canEditPrice = agente?.modificaPrezzi == 1;
     final canEditPrice = agente?.modificaPrezzi == 1;
-    final listini = await ref.read(articoliDaoProvider).getPriceCodes(art.idArticolo);
+    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 listiniDao = ref.read(listiniDaoProvider);
+    final scontiDao = ref.read(scontiDaoProvider);
     if (!context.mounted) return;
     if (!context.mounted) return;
 
 
     showModalBottomSheet(
     showModalBottomSheet(
@@ -130,14 +154,34 @@ class _OrderEditPageState extends ConsumerState<OrderEditPage>
         articolo: art,
         articolo: art,
         listini: listini,
         listini: listini,
         listiniDao: listiniDao,
         listiniDao: listiniDao,
+        scontiDao: scontiDao,
+        dataOrdine: dataOrdine,
         canEditPrezzo: canEditPrice,
         canEditPrezzo: canEditPrice,
         idListinoDefault: _selectedListino,
         idListinoDefault: _selectedListino,
-        onConfirm: (colli, quantita, prezzo, listinoId) {
+        onConfirm: (
+          colli,
+          quantita,
+          prezzoLordo,
+          prezzoNetto,
+          listinoId, {
+          double sconto1 = 0,
+          double sconto2 = 0,
+          double sconto3 = 0,
+          double sconto4 = 0,
+          double sconto5 = 0,
+        }) {
           _addArticleWithDetails(
           _addArticleWithDetails(
             art: art,
             art: art,
+            idListino: listinoId,
             colli: colli,
             colli: colli,
             quantita: quantita,
             quantita: quantita,
-            prezzo: prezzo,
+            prezzoLordo: prezzoLordo,
+            prezzoNetto: prezzoNetto,
+            sconto1: sconto1,
+            sconto2: sconto2,
+            sconto3: sconto3,
+            sconto4: sconto4,
+            sconto5: sconto5,
           );
           );
         },
         },
       ),
       ),
@@ -146,30 +190,79 @@ class _OrderEditPageState extends ConsumerState<OrderEditPage>
 
 
   Future<void> _addArticleWithDetails({
   Future<void> _addArticleWithDetails({
     required Articolo art,
     required Articolo art,
+    required int idListino,
     required double colli,
     required double colli,
     required double quantita,
     required double quantita,
-    required double prezzo,
+    required double prezzoLordo,
+    required double prezzoNetto,
+    double? sconto1 = 0,
+    double? sconto2 = 0,
+    double? sconto3 = 0,
+    double? sconto4 = 0,
+    double? sconto5 = 0,
   }) async {
   }) async {
     final orderState = ref.read(orderProvider);
     final orderState = ref.read(orderProvider);
-    final idOrdine = orderState.order?.idOrdine;
-    if (idOrdine == null || idOrdine == 0) return;
-
-    await ref.read(orderProvider.notifier).addLine(RigaOrdine(
-          idRigaOrdine: 0,
-          idOrdine: idOrdine,
-          idArticolo: art.idArticolo,
-          quantita: quantita,
-          prezzoLordo: prezzo,
-          prezzoNetto: prezzo,
-          totale: prezzo * quantita,
-          promozione: 0,
-          rigaPromozione: 0,
-          colli: colli,
-        ));
+    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();
     _artCtrl.clear();
     setState(() => _searchResults = []);
     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 {
   Future<void> _salva() async {
     final notifier = ref.read(orderProvider.notifier);
     final notifier = ref.read(orderProvider.notifier);
     notifier.setIdFiliale(_selectedFiliale);
     notifier.setIdFiliale(_selectedFiliale);
@@ -190,8 +283,7 @@ class _OrderEditPageState extends ConsumerState<OrderEditPage>
 
 
     return Scaffold(
     return Scaffold(
       appBar: AppBar(
       appBar: AppBar(
-        title:
-            Text('Ordine #${orderState.order?.numeroOrdine ?? 'nuovo'}'),
+        title: Text('Ordine #${orderState.order?.numeroOrdine ?? 'nuovo'}'),
         bottom: TabBar(
         bottom: TabBar(
           controller: _tabController,
           controller: _tabController,
           tabs: const [
           tabs: const [
@@ -200,17 +292,19 @@ class _OrderEditPageState extends ConsumerState<OrderEditPage>
           ],
           ],
         ),
         ),
       ),
       ),
-      body: orderState.isLoading || !_dataLoaded
-          ? const Center(child: CircularProgressIndicator())
-          : TabBarView(
-              controller: _tabController,
-              children: [
-                _buildHeaderTab(theme),
-                _buildLinesTab(theme, orderState),
-              ],
-            ),
-      floatingActionButton: _tabController.index == 1 &&
-              orderState.order?.idOrdine != null
+      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(
           ? FloatingActionButton.extended(
               onPressed: _salva,
               onPressed: _salva,
               icon: const Icon(Icons.save),
               icon: const Icon(Icons.save),
@@ -221,43 +315,141 @@ class _OrderEditPageState extends ConsumerState<OrderEditPage>
   }
   }
 
 
   Widget _buildHeaderTab(ThemeData theme) {
   Widget _buildHeaderTab(ThemeData theme) {
+    final cs = theme.colorScheme;
+    final bgColor = creditScoreBg(_cliente?.creditScoreColor);
+
     return SingleChildScrollView(
     return SingleChildScrollView(
       padding: const EdgeInsets.all(16),
       padding: const EdgeInsets.all(16),
       child: Column(
       child: Column(
         crossAxisAlignment: CrossAxisAlignment.start,
         crossAxisAlignment: CrossAxisAlignment.start,
         children: [
         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>(
           DropdownButtonFormField<int>(
             value: _selectedFiliale,
             value: _selectedFiliale,
             decoration: const InputDecoration(labelText: 'Filiale'),
             decoration: const InputDecoration(labelText: 'Filiale'),
             items: _filiali
             items: _filiali
-                .map((f) => DropdownMenuItem(
-                      value: f.idFiliale,
-                      child: Text(f.descrizione ?? ''),
-                    ))
+                .map(
+                  (f) => DropdownMenuItem(
+                    value: f.idFiliale,
+                    child: CodDescDropdownItem(
+                      codice: f.codFiliale,
+                      descrizione: f.descrizione,
+                    ),
+                  ),
+                )
                 .toList(),
                 .toList(),
             onChanged: (v) => setState(() => _selectedFiliale = v),
             onChanged: (v) => setState(() => _selectedFiliale = v),
           ),
           ),
           const SizedBox(height: 16),
           const SizedBox(height: 16),
           DropdownButtonFormField<int>(
           DropdownButtonFormField<int>(
-            value: _selectedListino,
+            initialValue: _selectedListino,
             decoration: const InputDecoration(labelText: 'Listino'),
             decoration: const InputDecoration(labelText: 'Listino'),
             items: _listini
             items: _listini
-                .map((l) => DropdownMenuItem(
-                      value: l.idListino,
-                      child: Text(l.descrizione ?? ''),
-                    ))
+                .map(
+                  (l) => DropdownMenuItem(
+                    value: l.idListino,
+                    child: CodDescDropdownItem(
+                      codice: l.codListino,
+                      descrizione: l.descrizione,
+                    ),
+                  ),
+                )
                 .toList(),
                 .toList(),
             onChanged: (v) => setState(() => _selectedListino = v),
             onChanged: (v) => setState(() => _selectedListino = v),
           ),
           ),
           const SizedBox(height: 16),
           const SizedBox(height: 16),
           DropdownButtonFormField<int>(
           DropdownButtonFormField<int>(
-            value: _selectedPagamento,
+            initialValue: _selectedPagamento,
             decoration: const InputDecoration(labelText: 'Pagamento'),
             decoration: const InputDecoration(labelText: 'Pagamento'),
             items: _pagamenti
             items: _pagamenti
-                .map((p) => DropdownMenuItem(
-                      value: p.idPagamento,
-                      child: Text(p.descrizione ?? ''),
-                    ))
+                .map(
+                  (p) => DropdownMenuItem(
+                    value: p.idPagamento,
+                    child: CodDescDropdownItem(
+                      codice: p.codPagamento,
+                      descrizione: p.descrizione,
+                    ),
+                  ),
+                )
                 .toList(),
                 .toList(),
             onChanged: (v) => setState(() => _selectedPagamento = v),
             onChanged: (v) => setState(() => _selectedPagamento = v),
           ),
           ),
@@ -295,20 +487,35 @@ class _OrderEditPageState extends ConsumerState<OrderEditPage>
       children: [
       children: [
         Padding(
         Padding(
           padding: const EdgeInsets.all(12),
           padding: const EdgeInsets.all(12),
-          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,
+          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)
         if (_searchResults.isNotEmpty)
@@ -318,13 +525,15 @@ class _OrderEditPageState extends ConsumerState<OrderEditPage>
               itemCount: _searchResults.length,
               itemCount: _searchResults.length,
               itemBuilder: (_, i) => ListTile(
               itemBuilder: (_, i) => ListTile(
                 leading: ArticleImage(
                 leading: ArticleImage(
-                    idArticolo: _searchResults[i].idArticolo,
-                    codArticolo: _searchResults[i].codArticolo),
+                  idArticolo: _searchResults[i].idArticolo,
+                  codArticolo: _searchResults[i].codArticolo,
+                ),
                 title: Text(_searchResults[i].descrizione ?? ''),
                 title: Text(_searchResults[i].descrizione ?? ''),
                 subtitle: Text(_searchResults[i].codArticolo ?? ''),
                 subtitle: Text(_searchResults[i].codArticolo ?? ''),
                 trailing: TextButton(
                 trailing: TextButton(
-                    onPressed: () => _showArticlePicker(_searchResults[i]),
-                    child: const Text('Aggiungi')),
+                  onPressed: () => _showArticlePicker(_searchResults[i]),
+                  child: const Text('Aggiungi'),
+                ),
               ),
               ),
             ),
             ),
           ),
           ),
@@ -346,8 +555,7 @@ class _OrderEditPageState extends ConsumerState<OrderEditPage>
           padding: const EdgeInsets.all(16),
           padding: const EdgeInsets.all(16),
           decoration: BoxDecoration(
           decoration: BoxDecoration(
             color: theme.colorScheme.surfaceContainerHighest,
             color: theme.colorScheme.surfaceContainerHighest,
-            border: Border(
-                top: BorderSide(color: theme.dividerColor)),
+            border: Border(top: BorderSide(color: theme.dividerColor)),
           ),
           ),
           child: Row(
           child: Row(
             mainAxisAlignment: MainAxisAlignment.spaceBetween,
             mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -355,8 +563,9 @@ class _OrderEditPageState extends ConsumerState<OrderEditPage>
               Text('Qtà: ${orderState.totQta.toStringAsFixed(1)}'),
               Text('Qtà: ${orderState.totQta.toStringAsFixed(1)}'),
               Text(
               Text(
                 'Totale: ${NumberFormat.currency(locale: 'it', symbol: '€').format(orderState.totale)}',
                 'Totale: ${NumberFormat.currency(locale: 'it', symbol: '€').format(orderState.totale)}',
-                style: theme.textTheme.titleMedium
-                    ?.copyWith(fontWeight: FontWeight.bold),
+                style: theme.textTheme.titleMedium?.copyWith(
+                  fontWeight: FontWeight.bold,
+                ),
               ),
               ),
             ],
             ],
           ),
           ),
@@ -371,7 +580,11 @@ class _LineCard extends StatelessWidget {
   final VoidCallback onDelete;
   final VoidCallback onDelete;
   final ThemeData theme;
   final ThemeData theme;
 
 
-  const _LineCard({required this.line, required this.onDelete, required this.theme});
+  const _LineCard({
+    required this.line,
+    required this.onDelete,
+    required this.theme,
+  });
 
 
   @override
   @override
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
@@ -380,29 +593,33 @@ class _LineCard extends StatelessWidget {
       margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
       margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
       color: isPromo ? Colors.green.shade50 : null,
       color: isPromo ? Colors.green.shade50 : null,
       child: ListTile(
       child: ListTile(
-        title: Text('Articolo #${line.idArticolo ?? ''}',
-            style: TextStyle(
-                fontWeight: isPromo ? FontWeight.bold : null)),
+        title: Text(
+          'Articolo #${line.idArticolo ?? ''}',
+          style: TextStyle(fontWeight: isPromo ? FontWeight.bold : null),
+        ),
         subtitle: Text(
         subtitle: Text(
-            'Qtà: ${line.quantita?.toStringAsFixed(1) ?? "0"}  Prezzo: ${line.prezzoNetto?.toStringAsFixed(2) ?? "0,00"}€'),
+          'Qtà: ${line.quantita?.toStringAsFixed(1) ?? "0"}  Prezzo: ${line.prezzoNetto?.toStringAsFixed(2) ?? "0,00"}€',
+        ),
         trailing: Row(
         trailing: Row(
           mainAxisSize: MainAxisSize.min,
           mainAxisSize: MainAxisSize.min,
           children: [
           children: [
             if (isPromo)
             if (isPromo)
               Container(
               Container(
-                padding: const EdgeInsets.symmetric(
-                    horizontal: 6, vertical: 2),
+                padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
                 decoration: BoxDecoration(
                 decoration: BoxDecoration(
-                    color: Colors.green,
-                    borderRadius: BorderRadius.circular(8)),
-                child: const Text('PROMO',
-                    style: TextStyle(
-                        color: Colors.white, fontSize: 10)),
+                  color: Colors.green,
+                  borderRadius: BorderRadius.circular(8),
+                ),
+                child: const Text(
+                  'PROMO',
+                  style: TextStyle(color: Colors.white, fontSize: 10),
+                ),
               ),
               ),
             if (!isPromo)
             if (!isPromo)
               IconButton(
               IconButton(
-                  icon: const Icon(Icons.delete_outline, size: 20),
-                  onPressed: onDelete),
+                icon: const Icon(Icons.delete_outline, size: 20),
+                onPressed: onDelete,
+              ),
           ],
           ],
         ),
         ),
       ),
       ),
@@ -414,15 +631,30 @@ class _ArticlePickerSheet extends StatefulWidget {
   final Articolo articolo;
   final Articolo articolo;
   final List<Listino> listini;
   final List<Listino> listini;
   final ListiniDao listiniDao;
   final ListiniDao listiniDao;
+  final ScontiDao scontiDao;
+  final String dataOrdine;
   final bool canEditPrezzo;
   final bool canEditPrezzo;
   final int? idListinoDefault;
   final int? idListinoDefault;
-  final void Function(double colli, double quantita, double prezzo, int listinoId)
-      onConfirm;
+  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({
   const _ArticlePickerSheet({
     required this.articolo,
     required this.articolo,
     required this.listini,
     required this.listini,
     required this.listiniDao,
     required this.listiniDao,
+    required this.scontiDao,
+    required this.dataOrdine,
     required this.canEditPrezzo,
     required this.canEditPrezzo,
     this.idListinoDefault,
     this.idListinoDefault,
     required this.onConfirm,
     required this.onConfirm,
@@ -436,9 +668,20 @@ class _ArticlePickerSheetState extends State<_ArticlePickerSheet> {
   final _colliCtrl = TextEditingController();
   final _colliCtrl = TextEditingController();
   final _qtaCtrl = TextEditingController();
   final _qtaCtrl = TextEditingController();
   final _prezzoCtrl = TextEditingController();
   final _prezzoCtrl = TextEditingController();
+  final _sconto1Ctrl = TextEditingController();
+  final _sconto2Ctrl = TextEditingController();
+  final _sconto3Ctrl = TextEditingController();
+  final _sconto4Ctrl = TextEditingController();
+  final _sconto5Ctrl = TextEditingController();
 
 
   int? _selectedListino;
   int? _selectedListino;
   double _prezzo = 0;
   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 _updatingColli = false;
   bool _updatingQta = false;
   bool _updatingQta = false;
@@ -457,18 +700,94 @@ class _ArticlePickerSheetState extends State<_ArticlePickerSheet> {
     _colliCtrl.dispose();
     _colliCtrl.dispose();
     _qtaCtrl.dispose();
     _qtaCtrl.dispose();
     _prezzoCtrl.dispose();
     _prezzoCtrl.dispose();
+    _sconto1Ctrl.dispose();
+    _sconto2Ctrl.dispose();
+    _sconto3Ctrl.dispose();
+    _sconto4Ctrl.dispose();
+    _sconto5Ctrl.dispose();
     super.dispose();
     super.dispose();
   }
   }
 
 
   Future<void> _loadPrezzo(int idListino) async {
   Future<void> _loadPrezzo(int idListino) async {
     final lp = await widget.listiniDao.findListinoArticolo(
     final lp = await widget.listiniDao.findListinoArticolo(
-        idListino, widget.articolo.idArticolo);
-    if (lp?.prezzo != null) {
-      setState(() => _prezzo = lp!.prezzo!);
-      _prezzoCtrl.text = _prezzo.toStringAsFixed(2);
+      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) {
   void _onColliChanged(String v) {
     if (_updatingColli) return;
     if (_updatingColli) return;
     _updatingQta = true;
     _updatingQta = true;
@@ -497,9 +816,20 @@ class _ArticlePickerSheetState extends State<_ArticlePickerSheet> {
   void _confirm() {
   void _confirm() {
     final colli = double.tryParse(_colliCtrl.text) ?? 0;
     final colli = double.tryParse(_colliCtrl.text) ?? 0;
     final qta = double.tryParse(_qtaCtrl.text) ?? 0;
     final qta = double.tryParse(_qtaCtrl.text) ?? 0;
-    final prezzo = double.tryParse(_prezzoCtrl.text) ?? 0;
+    final prezzoLordo = double.tryParse(_prezzoCtrl.text) ?? 0;
     final listinoId = _selectedListino ?? 0;
     final listinoId = _selectedListino ?? 0;
-    widget.onConfirm(colli, qta, prezzo, listinoId);
+    widget.onConfirm(
+      colli,
+      qta,
+      prezzoLordo,
+      _prezzoNetto,
+      listinoId,
+      sconto1: _sconto1,
+      sconto2: _sconto2,
+      sconto3: _sconto3,
+      sconto4: _sconto4,
+      sconto5: _sconto5,
+    );
     Navigator.pop(context);
     Navigator.pop(context);
   }
   }
 
 
@@ -509,31 +839,44 @@ class _ArticlePickerSheetState extends State<_ArticlePickerSheet> {
     return Padding(
     return Padding(
       padding: EdgeInsets.only(
       padding: EdgeInsets.only(
         bottom: MediaQuery.of(context).viewInsets.bottom,
         bottom: MediaQuery.of(context).viewInsets.bottom,
-        left: 16, right: 16, top: 16,
+        left: 16,
+        right: 16,
+        top: 16,
       ),
       ),
       child: SingleChildScrollView(
       child: SingleChildScrollView(
         child: Column(
         child: Column(
           mainAxisSize: MainAxisSize.min,
           mainAxisSize: MainAxisSize.min,
           crossAxisAlignment: CrossAxisAlignment.start,
           crossAxisAlignment: CrossAxisAlignment.start,
           children: [
           children: [
-            Text(widget.articolo.descrizione ?? '',
-                style: theme.textTheme.titleMedium),
+            Text(
+              widget.articolo.descrizione ?? '',
+              style: theme.textTheme.titleMedium,
+            ),
             const SizedBox(height: 4),
             const SizedBox(height: 4),
-            Text(widget.articolo.codArticolo ?? '',
-                style: theme.textTheme.bodySmall),
+            Text(
+              widget.articolo.codArticolo ?? '',
+              style: theme.textTheme.bodySmall,
+            ),
             if (widget.articolo.pezziConfezione != null)
             if (widget.articolo.pezziConfezione != null)
-              Text('Pezzi/confezione: ${widget.articolo.pezziConfezione}',
-                  style: theme.textTheme.bodySmall),
+              Text(
+                'Pezzi/confezione: ${widget.articolo.pezziConfezione}',
+                style: theme.textTheme.bodySmall,
+              ),
             const SizedBox(height: 16),
             const SizedBox(height: 16),
             DropdownButtonFormField<int>(
             DropdownButtonFormField<int>(
               value: _selectedListino,
               value: _selectedListino,
               decoration: const InputDecoration(labelText: 'Listino'),
               decoration: const InputDecoration(labelText: 'Listino'),
               isExpanded: true,
               isExpanded: true,
               items: widget.listini
               items: widget.listini
-                  .map((l) => DropdownMenuItem(
-                        value: l.idListino,
-                        child: Text(l.descrizione ?? ''),
-                      ))
+                  .map(
+                    (l) => DropdownMenuItem(
+                      value: l.idListino,
+                      child: CodDescDropdownItem(
+                        codice: l.codListino,
+                        descrizione: l.descrizione,
+                      ),
+                    ),
+                  )
                   .toList(),
                   .toList(),
               onChanged: (v) {
               onChanged: (v) {
                 setState(() => _selectedListino = v);
                 setState(() => _selectedListino = v);
@@ -541,13 +884,98 @@ class _ArticlePickerSheetState extends State<_ArticlePickerSheet> {
               },
               },
             ),
             ),
             const SizedBox(height: 12),
             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(
             Row(
               children: [
               children: [
                 Expanded(
                 Expanded(
                   child: TextField(
                   child: TextField(
                     controller: _colliCtrl,
                     controller: _colliCtrl,
-                    decoration: const InputDecoration(
-                        labelText: 'Colli'),
+                    decoration: const InputDecoration(labelText: 'Colli'),
                     keyboardType: TextInputType.number,
                     keyboardType: TextInputType.number,
                     onChanged: _onColliChanged,
                     onChanged: _onColliChanged,
                   ),
                   ),
@@ -556,22 +984,13 @@ class _ArticlePickerSheetState extends State<_ArticlePickerSheet> {
                 Expanded(
                 Expanded(
                   child: TextField(
                   child: TextField(
                     controller: _qtaCtrl,
                     controller: _qtaCtrl,
-                    decoration: const InputDecoration(
-                        labelText: 'Quantità'),
+                    decoration: const InputDecoration(labelText: 'Quantità'),
                     keyboardType: TextInputType.number,
                     keyboardType: TextInputType.number,
                     onChanged: _onQtaChanged,
                     onChanged: _onQtaChanged,
                   ),
                   ),
                 ),
                 ),
               ],
               ],
             ),
             ),
-            const SizedBox(height: 12),
-            TextField(
-              controller: _prezzoCtrl,
-              decoration: const InputDecoration(labelText: 'Prezzo'),
-              keyboardType:
-                  const TextInputType.numberWithOptions(decimal: true),
-              enabled: widget.canEditPrezzo,
-            ),
             const SizedBox(height: 20),
             const SizedBox(height: 20),
             SizedBox(
             SizedBox(
               width: double.infinity,
               width: double.infinity,

+ 352 - 165
lib/ui/pages/orders/order_list_page.dart

@@ -1,4 +1,3 @@
-import 'dart:math' as math;
 import 'package:flutter/material.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:go_router/go_router.dart';
 import 'package:go_router/go_router.dart';
@@ -53,6 +52,7 @@ class _StatoPill extends StatelessWidget {
       ),
       ),
       child: Text(
       child: Text(
         label,
         label,
+        textAlign: TextAlign.center,
         style: TextStyle(
         style: TextStyle(
           fontSize: 12,
           fontSize: 12,
           height: 16 / 12,
           height: 16 / 12,
@@ -107,47 +107,53 @@ class _OrderListPageState extends ConsumerState<OrderListPage> {
         onPressed: () => context.go('/dashboard/orders/new'),
         onPressed: () => context.go('/dashboard/orders/new'),
         child: const Icon(Icons.add),
         child: const Icon(Icons.add),
       ),
       ),
-      body: Column(
-        children: [
-          sw.SearchBarWidget(
-            controller: _searchCtrl,
-            hint: 'Cerca ordine, cliente, destinazione...',
-            onChanged: (v) => setState(() => _filter = v),
-            onClear: () {
-              _searchCtrl.clear();
-              setState(() => _filter = '');
-            },
-          ),
-          Expanded(
-            child: ordersAsync?.when(
-              data: (orders) {
-                if (orders.isEmpty) {
-                  return const EmptyState(
-                    icon: Icons.receipt_long,
-                    title: 'Nessun ordine',
-                  );
-                }
-                if (isPhone) {
-                  return ListView.builder(
-                    padding: const EdgeInsets.all(16),
-                    itemCount: orders.length,
-                    itemBuilder: (_, i) => _OrderCard(order: orders[i]),
-                  );
-                }
-                final screenWidth = MediaQuery.of(context).size.width;
-                return _OrderTable(orders: orders, availableWidth: screenWidth);
+      body: SafeArea(
+        child: Column(
+          children: [
+            sw.SearchBarWidget(
+              controller: _searchCtrl,
+              hint: 'Cerca ordine, cliente, destinazione...',
+              onChanged: (v) => setState(() => _filter = v),
+              onClear: () {
+                _searchCtrl.clear();
+                setState(() => _filter = '');
               },
               },
-              loading: () => const Center(child: CircularProgressIndicator()),
-              error: (e, _) => Center(child: Text('Errore: $e')),
-            ) ?? const Center(child: CircularProgressIndicator()),
-          ),
-          if (statsAsync != null)
-            statsAsync.when(
-              data: (stats) => _StatsBar(stats: stats),
-              loading: () => const SizedBox(height: 80),
-              error: (_, _) => const SizedBox.shrink(),
             ),
             ),
-        ],
+            Expanded(
+              child:
+                  ordersAsync?.when(
+                    data: (orders) {
+                      if (orders.isEmpty) {
+                        return const EmptyState(
+                          icon: Icons.receipt_long,
+                          title: 'Nessun ordine',
+                        );
+                      }
+                      if (isPhone) {
+                        return ListView.builder(
+                          padding: const EdgeInsets.all(16),
+                          itemCount: orders.length,
+                          itemBuilder: (_, i) => _OrderCard(order: orders[i]),
+                        );
+                      }
+                      return _OrderTable(orders: orders);
+                    },
+                    loading: () =>
+                        const Center(child: CircularProgressIndicator()),
+                    error: (e, _) {
+                      return Center(child: Text('Errore: $e'));
+                    },
+                  ) ??
+                  const Center(child: CircularProgressIndicator()),
+            ),
+            if (statsAsync != null)
+              statsAsync.when(
+                data: (stats) => _StatsBar(stats: stats),
+                loading: () => const SizedBox(height: 80),
+                error: (_, __) => const SizedBox.shrink(),
+              ),
+          ],
+        ),
       ),
       ),
     );
     );
   }
   }
@@ -162,7 +168,10 @@ class _OrderCard extends StatelessWidget {
     final theme = Theme.of(context);
     final theme = Theme.of(context);
     final cs = theme.colorScheme;
     final cs = theme.colorScheme;
     final dateFormat = DateFormat('dd/MM/yyyy');
     final dateFormat = DateFormat('dd/MM/yyyy');
-    final currencyFormat = NumberFormat.currency(symbol: '€ ', decimalDigits: 2);
+    final currencyFormat = NumberFormat.currency(
+      symbol: '€ ',
+      decimalDigits: 2,
+    );
 
 
     return Card(
     return Card(
       margin: const EdgeInsets.only(bottom: 12),
       margin: const EdgeInsets.only(bottom: 12),
@@ -181,7 +190,6 @@ class _OrderCard extends StatelessWidget {
             crossAxisAlignment: CrossAxisAlignment.start,
             crossAxisAlignment: CrossAxisAlignment.start,
             children: [
             children: [
               Row(
               Row(
-                crossAxisAlignment: CrossAxisAlignment.start,
                 children: [
                 children: [
                   Expanded(
                   Expanded(
                     child: Text(
                     child: Text(
@@ -199,43 +207,39 @@ class _OrderCard extends StatelessWidget {
                       color: cs.onSurfaceVariant,
                       color: cs.onSurfaceVariant,
                     ),
                     ),
                   ),
                   ),
+                  Expanded(
+                    child: Align(
+                      alignment: Alignment.centerRight,
+                      child: _StatoPill(stato: order.stato),
+                    ),
+                  ),
                 ],
                 ],
               ),
               ),
-              const SizedBox(height: 4),
+              const SizedBox(height: 8),
               Text(
               Text(
                 '${order.codCliente ?? ''} - ${order.ragioneSociale ?? ''}',
                 '${order.codCliente ?? ''} - ${order.ragioneSociale ?? ''}',
                 style: theme.textTheme.bodyMedium,
                 style: theme.textTheme.bodyMedium,
                 maxLines: 1,
                 maxLines: 1,
                 overflow: TextOverflow.ellipsis,
                 overflow: TextOverflow.ellipsis,
               ),
               ),
-              if ((order.filiale ?? '').isNotEmpty) ...[
-                const SizedBox(height: 4),
-                Text(
-                  'Filiale: ${order.filiale}',
-                  style: theme.textTheme.bodySmall?.copyWith(color: cs.onSurfaceVariant),
-                  maxLines: 1,
-                  overflow: TextOverflow.ellipsis,
-                ),
-              ],
-              if ((order.indirizzo ?? '').isNotEmpty) ...[
-                const SizedBox(height: 2),
-                Text(
-                  '${order.indirizzo}${order.citta != null ? ', ${order.citta}' : ''}',
-                  style: theme.textTheme.bodySmall?.copyWith(color: cs.onSurfaceVariant),
-                  maxLines: 1,
-                  overflow: TextOverflow.ellipsis,
+              const SizedBox(height: 4),
+              Text(
+                '${order.indirizzo ?? ''}${order.citta != null ? ', ${order.citta}' : ''}${order.provincia != null ? ' (${order.provincia})' : ''}',
+                style: theme.textTheme.bodySmall?.copyWith(
+                  color: cs.onSurfaceVariant,
                 ),
                 ),
-              ],
+                maxLines: 1,
+                overflow: TextOverflow.ellipsis,
+              ),
               const SizedBox(height: 12),
               const SizedBox(height: 12),
-              Row(
-                children: [
-                  Text(
-                    'Totale: ${currencyFormat.format(order.totale ?? 0)}',
-                    style: theme.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.bold),
+              Center(
+                child: Text(
+                  currencyFormat.format(order.totale ?? 0),
+                  style: theme.textTheme.titleLarge?.copyWith(
+                    fontWeight: FontWeight.bold,
                   ),
                   ),
-                  const Spacer(),
-                  _StatoPill(stato: order.stato),
-                ],
+                  textAlign: TextAlign.right,
+                ),
               ),
               ),
             ],
             ],
           ),
           ),
@@ -247,115 +251,291 @@ class _OrderCard extends StatelessWidget {
 
 
 class _OrderTable extends StatelessWidget {
 class _OrderTable extends StatelessWidget {
   final List<VOrdiniData> orders;
   final List<VOrdiniData> orders;
-  final double availableWidth;
-  const _OrderTable({required this.orders, required this.availableWidth});
+  const _OrderTable({required this.orders});
 
 
   @override
   @override
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
     final theme = Theme.of(context);
     final theme = Theme.of(context);
     final cs = theme.colorScheme;
     final cs = theme.colorScheme;
     final dateFormat = DateFormat('dd/MM/yyyy');
     final dateFormat = DateFormat('dd/MM/yyyy');
-    final currencyFormat = NumberFormat.currency(symbol: '€ ', decimalDigits: 2);
+    final currencyFormat = NumberFormat.currency(
+      symbol: '€ ',
+      decimalDigits: 2,
+    );
 
 
-    return SingleChildScrollView(
-      scrollDirection: Axis.horizontal,
-      child: SizedBox(
-        width: math.max(900, availableWidth),
-        child: SingleChildScrollView(
-          scrollDirection: Axis.vertical,
-          child: Column(
-            crossAxisAlignment: CrossAxisAlignment.stretch,
-            children: [
-              Container(
-                padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14),
-                decoration: BoxDecoration(
-                  color: cs.surfaceContainerHigh.withAlpha(50),
-                  border: Border(bottom: BorderSide(color: cs.outlineVariant)),
-                ),
-                child: Row(
-                  children: [
-                    _headerCell(context, 'Numero Ordine', flex: 2),
-                    _headerCell(context, 'Data', flex: 1),
-                    _headerCell(context, 'Cliente', flex: 3),
-                    _headerCell(context, 'Destinazione', flex: 2),
-                    _headerCell(context, 'Totale', flex: 1),
-                    _headerCell(context, 'Stato', flex: 1),
-                    _headerCell(context, 'Azioni', flex: 1),
-                  ],
-                ),
-              ),
-              ...orders.map((o) {
-                return Container(
-                  padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
+    return LayoutBuilder(
+      builder: (context, constraints) {
+        final isCompact = constraints.maxWidth < 1024;
+        return SingleChildScrollView(
+          scrollDirection: Axis.horizontal,
+          child: ConstrainedBox(
+            constraints: BoxConstraints(
+              minWidth: constraints.maxWidth,
+              maxWidth: constraints.maxWidth,
+            ),
+            child: Column(
+              children: [
+                Container(
+                  padding: const EdgeInsets.symmetric(
+                    horizontal: 24,
+                    vertical: 14,
+                  ),
                   decoration: BoxDecoration(
                   decoration: BoxDecoration(
-                    border: Border(bottom: BorderSide(color: cs.outlineVariant.withAlpha(80))),
+                    color: cs.surfaceContainerHigh.withAlpha(50),
+                    border: Border(
+                      bottom: BorderSide(color: cs.outlineVariant),
+                    ),
+                  ),
+                  child: Row(
+                    children: isCompact
+                        ? [
+                            _headerCell(context, 'Ordine', flex: 2),
+                            _headerCell(context, 'Cliente', flex: 5),
+                            _headerCell(context, 'Totale', flex: 1),
+                            _headerCell(context, 'Stato', flex: 1),
+                            _headerCell(context, 'Azioni', flex: 1),
+                          ]
+                        : [
+                            _headerCell(context, 'N. Ordine', flex: 1),
+                            _headerCell(context, 'Data', flex: 2),
+                            _headerCell(context, 'Cliente', flex: 4),
+                            _headerCell(context, 'Destinazione', flex: 6),
+                            _headerCell(context, 'Totale', flex: 2),
+                            _headerCell(context, 'Stato', flex: 1),
+                            _headerCell(context, 'Azioni', flex: 1),
+                          ],
                   ),
                   ),
-                  child: InkWell(
-                    onTap: () => context.push('/dashboard/orders/${o.idOrdine}'),
-                    child: Row(
+                ),
+                Expanded(
+                  child: SingleChildScrollView(
+                    scrollDirection: Axis.vertical,
+                    child: Column(
+                      crossAxisAlignment: CrossAxisAlignment.stretch,
                       children: [
                       children: [
-                        _cell(
-                          Text(
-                            '#${o.numeroOrdine ?? ''}',
-                            style: theme.textTheme.bodyMedium?.copyWith(
-                              fontWeight: FontWeight.bold,
-                              fontFamily: 'monospace',
+                        ...orders.map((o) {
+                          return Container(
+                            padding: const EdgeInsets.symmetric(
+                              horizontal: 24,
+                              vertical: 16,
+                            ),
+                            decoration: BoxDecoration(
+                              border: Border(
+                                bottom: BorderSide(
+                                  color: cs.outlineVariant.withAlpha(80),
+                                ),
+                              ),
                             ),
                             ),
-                          ),
-                          flex: 2,
-                        ),
-                        _cell(
-                          Text(
-                            o.dataOrdine != null
-                                ? dateFormat.format(DateTime.parse(o.dataOrdine!))
-                                : '',
-                            style: theme.textTheme.bodyMedium?.copyWith(color: cs.onSurfaceVariant),
-                          ),
-                          flex: 1,
-                        ),
-                        _cell(
-                          Text(
-                            '${o.codCliente ?? ''} - ${o.ragioneSociale ?? ''}',
-                            style: theme.textTheme.bodyMedium,
-                            maxLines: 1,
-                            overflow: TextOverflow.ellipsis,
-                          ),
-                          flex: 3,
-                        ),
-                        _cell(
-                          Text(
-                            '${o.citta ?? ''}${o.provincia != null ? ' (${o.provincia})' : ''}',
-                            style: theme.textTheme.bodyMedium?.copyWith(color: cs.onSurfaceVariant),
-                            maxLines: 1,
-                            overflow: TextOverflow.ellipsis,
-                          ),
-                          flex: 2,
-                        ),
-                        _cell(
-                          Text(
-                            currencyFormat.format(o.totale ?? 0),
-                            style: theme.textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.bold),
-                          ),
-                          flex: 1,
-                        ),
-                        _cell(_StatoPill(stato: o.stato), flex: 1),
-                        _cell(
-                          IconButton(
-                            icon: Icon(Icons.visibility, size: 20, color: cs.secondary),
-                            onPressed: () => context.push('/dashboard/orders/${o.idOrdine}'),
-                            visualDensity: VisualDensity.compact,
-                          ),
-                          flex: 1,
-                        ),
+                            child: InkWell(
+                              onTap: () => context.push(
+                                '/dashboard/orders/${o.idOrdine}',
+                              ),
+                              child: Row(
+                                children: isCompact
+                                    ? [
+                                        _cell(
+                                          Column(
+                                            mainAxisAlignment:
+                                                MainAxisAlignment.center,
+                                            crossAxisAlignment:
+                                                CrossAxisAlignment.start,
+                                            children: [
+                                              Text(
+                                                '${o.numeroOrdine ?? ''}',
+                                                style: theme
+                                                    .textTheme
+                                                    .bodyMedium
+                                                    ?.copyWith(
+                                                      fontWeight:
+                                                          FontWeight.bold,
+                                                      fontFamily: 'monospace',
+                                                    ),
+                                              ),
+                                              const SizedBox(height: 4),
+                                              Text(
+                                                o.dataOrdine != null
+                                                    ? dateFormat.format(
+                                                        DateTime.parse(
+                                                          o.dataOrdine!,
+                                                        ),
+                                                      )
+                                                    : '',
+                                                style: theme.textTheme.bodySmall
+                                                    ?.copyWith(
+                                                      color:
+                                                          cs.onSurfaceVariant,
+                                                    ),
+                                              ),
+                                            ],
+                                          ),
+                                          flex: 2,
+                                        ),
+                                        _cell(
+                                          Column(
+                                            mainAxisAlignment:
+                                                MainAxisAlignment.center,
+                                            crossAxisAlignment:
+                                                CrossAxisAlignment.start,
+                                            children: [
+                                              Text(
+                                                '${o.codCliente ?? ''} - ${o.ragioneSociale ?? ''}',
+                                                style:
+                                                    theme.textTheme.bodyMedium,
+                                                maxLines: 1,
+                                                overflow: TextOverflow.ellipsis,
+                                              ),
+                                              const SizedBox(height: 4),
+                                              Text(
+                                                '${o.filiale ?? ''}${o.indirizzo ?? ''} ${o.citta ?? ''}${o.provincia != null ? ' (${o.provincia})' : ''}',
+                                                style: theme.textTheme.bodySmall
+                                                    ?.copyWith(
+                                                      color:
+                                                          cs.onSurfaceVariant,
+                                                    ),
+                                                maxLines: 1,
+                                                overflow: TextOverflow.ellipsis,
+                                              ),
+                                            ],
+                                          ),
+                                          flex: 5,
+                                        ),
+                                        _cell(
+                                          Padding(
+                                            padding: const EdgeInsets.only(
+                                              right: 16,
+                                            ),
+                                            child: Text(
+                                              currencyFormat.format(
+                                                o.totale ?? 0,
+                                              ),
+                                              style: theme.textTheme.bodyMedium
+                                                  ?.copyWith(
+                                                    fontWeight: FontWeight.bold,
+                                                  ),
+                                              textAlign: TextAlign.right,
+                                            ),
+                                          ),
+                                          flex: 2,
+                                        ),
+                                        _cell(
+                                          _StatoPill(stato: o.stato),
+                                          flex: 1,
+                                        ),
+                                        _cell(
+                                          IconButton(
+                                            icon: Icon(
+                                              Icons.visibility,
+                                              size: 20,
+                                              color: cs.secondary,
+                                            ),
+                                            onPressed: () => context.push(
+                                              '/dashboard/orders/${o.idOrdine}',
+                                            ),
+                                            visualDensity:
+                                                VisualDensity.compact,
+                                          ),
+                                          flex: 1,
+                                        ),
+                                      ]
+                                    : [
+                                        _cell(
+                                          Text(
+                                            '${o.numeroOrdine ?? ''}',
+                                            style: theme.textTheme.bodyMedium
+                                                ?.copyWith(
+                                                  fontWeight: FontWeight.bold,
+                                                  fontFamily: 'monospace',
+                                                ),
+                                          ),
+                                          flex: 1,
+                                        ),
+                                        _cell(
+                                          Text(
+                                            o.dataOrdine != null
+                                                ? dateFormat.format(
+                                                    DateTime.parse(
+                                                      o.dataOrdine!,
+                                                    ),
+                                                  )
+                                                : '',
+                                            style: theme.textTheme.bodyMedium
+                                                ?.copyWith(
+                                                  color: cs.onSurfaceVariant,
+                                                ),
+                                          ),
+                                          flex: 2,
+                                        ),
+                                        _cell(
+                                          Text(
+                                            '${o.codCliente ?? ''} - ${o.ragioneSociale ?? ''}',
+                                            style: theme.textTheme.bodyMedium,
+                                            maxLines: 1,
+                                            overflow: TextOverflow.ellipsis,
+                                          ),
+                                          flex: 4,
+                                        ),
+                                        _cell(
+                                          Text(
+                                            '${o.filiale ?? ''}${o.indirizzo ?? ''} ${o.citta ?? ''}${o.provincia != null ? ' (${o.provincia})' : ''}',
+                                            style: theme.textTheme.bodyMedium
+                                                ?.copyWith(
+                                                  color: cs.onSurfaceVariant,
+                                                ),
+                                            maxLines: 2,
+                                            overflow: TextOverflow.ellipsis,
+                                          ),
+                                          flex: 6,
+                                        ),
+                                        _cell(
+                                          Padding(
+                                            padding: const EdgeInsets.only(
+                                              right: 16,
+                                            ),
+                                            child: Text(
+                                              currencyFormat.format(
+                                                o.totale ?? 0,
+                                              ),
+                                              style: theme.textTheme.bodyMedium
+                                                  ?.copyWith(
+                                                    fontWeight: FontWeight.bold,
+                                                  ),
+                                              textAlign: TextAlign.right,
+                                            ),
+                                          ),
+                                          flex: 1,
+                                        ),
+                                        _cell(
+                                          _StatoPill(stato: o.stato),
+                                          flex: 1,
+                                        ),
+                                        _cell(
+                                          IconButton(
+                                            icon: Icon(
+                                              Icons.visibility,
+                                              size: 20,
+                                              color: cs.secondary,
+                                            ),
+                                            onPressed: () => context.push(
+                                              '/dashboard/orders/${o.idOrdine}',
+                                            ),
+                                            visualDensity:
+                                                VisualDensity.compact,
+                                          ),
+                                          flex: 1,
+                                        ),
+                                      ],
+                              ),
+                            ),
+                          );
+                        }),
                       ],
                       ],
                     ),
                     ),
                   ),
                   ),
-                );
-              }),
-            ],
+                ),
+              ],
+            ),
           ),
           ),
-        ),
-      ),
+        );
+      },
     );
     );
   }
   }
 
 
@@ -387,7 +567,10 @@ class _StatsBar extends StatelessWidget {
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
     final theme = Theme.of(context);
     final theme = Theme.of(context);
     final cs = theme.colorScheme;
     final cs = theme.colorScheme;
-    final currencyFormat = NumberFormat.currency(symbol: '€ ', decimalDigits: 2);
+    final currencyFormat = NumberFormat.currency(
+      symbol: '€ ',
+      decimalDigits: 2,
+    );
 
 
     return Container(
     return Container(
       padding: const EdgeInsets.all(16),
       padding: const EdgeInsets.all(16),
@@ -476,14 +659,18 @@ class _StatCard extends StatelessWidget {
               children: [
               children: [
                 Text(
                 Text(
                   label,
                   label,
-                  style: theme.textTheme.labelSmall?.copyWith(color: cs.onSurfaceVariant),
+                  style: theme.textTheme.labelSmall?.copyWith(
+                    color: cs.onSurfaceVariant,
+                  ),
                   maxLines: 1,
                   maxLines: 1,
                   overflow: TextOverflow.ellipsis,
                   overflow: TextOverflow.ellipsis,
                 ),
                 ),
                 const SizedBox(height: 2),
                 const SizedBox(height: 2),
                 Text(
                 Text(
                   value,
                   value,
-                  style: theme.textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
+                  style: theme.textTheme.titleMedium?.copyWith(
+                    fontWeight: FontWeight.bold,
+                  ),
                   maxLines: 1,
                   maxLines: 1,
                   overflow: TextOverflow.ellipsis,
                   overflow: TextOverflow.ellipsis,
                 ),
                 ),

+ 194 - 0
lib/ui/pages/orders/selezione_cliente_page.dart

@@ -0,0 +1,194 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:ristoris/core/credit_score_color.dart';
+import 'package:ristoris/database/database.dart';
+import 'package:ristoris/providers/database_provider.dart';
+import '../../widgets/search_bar.dart' as sw;
+import '../../widgets/empty_state.dart';
+
+class SelezioneClientePage extends ConsumerStatefulWidget {
+  final int idAgente;
+
+  const SelezioneClientePage({super.key, required this.idAgente});
+
+  @override
+  ConsumerState<SelezioneClientePage> createState() => _SelezioneClientePageState();
+}
+
+class _SelezioneClientePageState extends ConsumerState<SelezioneClientePage> {
+  String _filter = '';
+  final _searchCtrl = TextEditingController();
+
+  @override
+  void dispose() {
+    _searchCtrl.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    final clientiAsync = ref.watch(
+      _filter.isEmpty
+          ? customerListForAgentProvider(widget.idAgente)
+          : customerSearchForAgentProvider((
+              idAgente: widget.idAgente,
+              filter: _filter,
+            )),
+    );
+
+    return Scaffold(
+      appBar: AppBar(title: const Text('Seleziona Cliente')),
+      body: SafeArea(
+        child: Column(
+          children: [
+            sw.SearchBarWidget(
+              controller: _searchCtrl,
+              hint: 'Cerca per codice, ragione sociale o partita IVA...',
+              onChanged: (v) => setState(() => _filter = v),
+              onClear: () {
+                _searchCtrl.clear();
+                setState(() => _filter = '');
+              },
+            ),
+            Expanded(
+              child: clientiAsync.when(
+                data: (clienti) {
+                  if (clienti.isEmpty) {
+                    return const EmptyState(
+                      icon: Icons.people_outline,
+                      title: 'Nessun cliente trovato',
+                    );
+                  }
+                  return ListView.builder(
+                    padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
+                    itemCount: clienti.length,
+                    itemBuilder: (_, i) => _ClienteTile(
+                      cliente: clienti[i],
+                      onTap: () => _onClienteTap(clienti[i]),
+                    ),
+                  );
+                },
+                loading: () => const Center(child: CircularProgressIndicator()),
+                error: (e, _) => Center(child: Text('Errore: $e')),
+              ),
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+
+  void _onClienteTap(Cliente cliente) {
+    if (cliente.codBlocco == '001') {
+      ScaffoldMessenger.of(context).showSnackBar(
+        const SnackBar(content: Text('Cliente bloccato: impossibile selezionare')),
+      );
+      return;
+    }
+    Navigator.pop(context, cliente);
+  }
+}
+
+class _ClienteTile extends StatelessWidget {
+  final Cliente cliente;
+  final VoidCallback onTap;
+
+  const _ClienteTile({required this.cliente, required this.onTap});
+
+  @override
+  Widget build(BuildContext context) {
+    final theme = Theme.of(context);
+    final cs = theme.colorScheme;
+    final bgColor = creditScoreBg(cliente.creditScoreColor);
+
+    return Card(
+      margin: const EdgeInsets.only(bottom: 8),
+      elevation: 0,
+      color: Colors.white,
+      shape: RoundedRectangleBorder(
+        borderRadius: BorderRadius.circular(12),
+        side: BorderSide(color: cs.outlineVariant),
+      ),
+      child: InkWell(
+        borderRadius: BorderRadius.circular(12),
+        onTap: onTap,
+        child: Padding(
+          padding: const EdgeInsets.all(12),
+          child: Row(
+            children: [
+              Expanded(
+                child: Column(
+                  crossAxisAlignment: CrossAxisAlignment.start,
+                  children: [
+                    Row(
+                      children: [
+                        if ((cliente.codCliente ?? '').isNotEmpty)
+                          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,
+                          ),
+                        ),
+                      ],
+                    ),
+                    const SizedBox(height: 4),
+                    Row(
+                      children: [
+                        if ((cliente.telefono ?? '').isNotEmpty) ...[
+                          Icon(Icons.phone, size: 14, color: cs.onSurfaceVariant),
+                          const SizedBox(width: 4),
+                          Text(cliente.telefono ?? '',
+                            style: theme.textTheme.bodySmall?.copyWith(color: cs.onSurfaceVariant)),
+                          const SizedBox(width: 12),
+                        ],
+                        if ((cliente.cellulare ?? '').isNotEmpty) ...[
+                          Icon(Icons.smartphone, size: 14, color: cs.onSurfaceVariant),
+                          const SizedBox(width: 4),
+                          Text(cliente.cellulare ?? '',
+                            style: theme.textTheme.bodySmall?.copyWith(color: cs.onSurfaceVariant)),
+                        ],
+                      ],
+                    ),
+                  ],
+                ),
+              ),
+              if (cliente.codBlocco == '001')
+                Icon(Icons.block, color: Colors.red, size: 24)
+              else if (cliente.codBlocco != null && cliente.codBlocco!.isNotEmpty)
+                Icon(Icons.warning_amber_rounded, color: Colors.amber, size: 24),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+}
+
+final customerListForAgentProvider = FutureProvider.family<List<Cliente>, int>((ref, idAgente) {
+  return ref.read(clientiDaoProvider).getActiveClients(idAgente);
+});
+
+final customerSearchForAgentProvider = FutureProvider.family<List<Cliente>, ({int idAgente, String filter})>(
+  (ref, params) {
+    return ref.read(clientiDaoProvider).getClienti(params.idAgente, params.filter);
+  },
+);

+ 13 - 11
lib/ui/pages/payments/payments_page.dart

@@ -21,17 +21,19 @@ class PaymentsPage extends ConsumerWidget {
 
 
     return Scaffold(
     return Scaffold(
       appBar: AppBar(title: const Text('Scadenze')),
       appBar: AppBar(title: const Text('Scadenze')),
-      body: paysAsync?.when(
-        data: (pays) {
-          if (pays.isEmpty) return const EmptyState(icon: Icons.account_balance_wallet_outlined, title: 'Nessuna scadenza');
-          return ListView.builder(
-            itemCount: pays.length,
-            itemBuilder: (_, i) => _ScadenzaCard(scadenza: pays[i]),
-          );
-        },
-        loading: () => const Center(child: CircularProgressIndicator()),
-        error: (e, _) => Center(child: Text('Errore: $e')),
-      ) ?? const Center(child: CircularProgressIndicator()),
+      body: SafeArea(
+        child: paysAsync?.when(
+          data: (pays) {
+            if (pays.isEmpty) return const EmptyState(icon: Icons.account_balance_wallet_outlined, title: 'Nessuna scadenza');
+            return ListView.builder(
+              itemCount: pays.length,
+              itemBuilder: (_, i) => _ScadenzaCard(scadenza: pays[i]),
+            );
+          },
+          loading: () => const Center(child: CircularProgressIndicator()),
+          error: (e, _) => Center(child: Text('Errore: $e')),
+        ) ?? const Center(child: CircularProgressIndicator()),
+      ),
     );
     );
   }
   }
 }
 }

+ 13 - 11
lib/ui/pages/promotions/promotion_list_page.dart

@@ -16,17 +16,19 @@ class PromotionListPage extends ConsumerWidget {
 
 
     return Scaffold(
     return Scaffold(
       appBar: AppBar(title: const Text('Promozioni')),
       appBar: AppBar(title: const Text('Promozioni')),
-      body: FutureBuilder(
-        future: promosAsync,
-        builder: (_, snap) {
-          if (!snap.hasData) return const Center(child: CircularProgressIndicator());
-          final promos = snap.data!;
-          if (promos.isEmpty) return const EmptyState(icon: Icons.local_offer_outlined, title: 'Nessuna promozione attiva');
-          return ListView.builder(
-            itemCount: promos.length,
-            itemBuilder: (_, i) => _PromoCard(promo: promos[i], promoDao: promoDao, theme: theme),
-          );
-        },
+      body: SafeArea(
+        child: FutureBuilder(
+          future: promosAsync,
+          builder: (_, snap) {
+            if (!snap.hasData) return const Center(child: CircularProgressIndicator());
+            final promos = snap.data!;
+            if (promos.isEmpty) return const EmptyState(icon: Icons.local_offer_outlined, title: 'Nessuna promozione attiva');
+            return ListView.builder(
+              itemCount: promos.length,
+              itemBuilder: (_, i) => _PromoCard(promo: promos[i], promoDao: promoDao, theme: theme),
+            );
+          },
+        ),
       ),
       ),
     );
     );
   }
   }

+ 8 - 6
lib/ui/pages/statistics/statistics_page.dart

@@ -42,12 +42,14 @@ class _StatisticsPageState extends ConsumerState<StatisticsPage>
           ],
           ],
         ),
         ),
       ),
       ),
-      body: TabBarView(
-        controller: _tabCtrl,
-        children: [
-          _MonthlyChart(),
-          _TopClientsChart(),
-        ],
+      body: SafeArea(
+        child: TabBarView(
+          controller: _tabCtrl,
+          children: [
+            _MonthlyChart(),
+            _TopClientsChart(),
+          ],
+        ),
       ),
       ),
     );
     );
   }
   }

+ 7 - 5
lib/ui/pages/sync/sync_page.dart

@@ -31,10 +31,11 @@ class _SyncPageState extends ConsumerState<SyncPage> {
           ),
           ),
         ],
         ],
       ),
       ),
-      body: Center(
-        child: Padding(
-          padding: const EdgeInsets.all(32),
-          child: Column(
+      body: SafeArea(
+        child: Center(
+          child: Padding(
+            padding: const EdgeInsets.all(32),
+            child: Column(
             mainAxisSize: MainAxisSize.min,
             mainAxisSize: MainAxisSize.min,
             children: [
             children: [
               Icon(
               Icon(
@@ -90,7 +91,8 @@ class _SyncPageState extends ConsumerState<SyncPage> {
                     : const Icon(Icons.sync),
                     : const Icon(Icons.sync),
                 label: Text(syncState.isSyncing ? 'In corso...' : 'Avvia Sincronizzazione'),
                 label: Text(syncState.isSyncing ? 'In corso...' : 'Avvia Sincronizzazione'),
               ),
               ),
-            ],
+              ],
+            ),
           ),
           ),
         ),
         ),
       ),
       ),

+ 7 - 5
lib/ui/pages/sync/sync_settings_page.dart

@@ -136,10 +136,11 @@ class _SyncSettingsPageState extends ConsumerState<SyncSettingsPage> {
 
 
     return Scaffold(
     return Scaffold(
       appBar: AppBar(title: const Text('Impostazioni')),
       appBar: AppBar(title: const Text('Impostazioni')),
-      body: Center(
-        child: SingleChildScrollView(
-          padding: const EdgeInsets.all(24),
-          child: ConstrainedBox(
+      body: SafeArea(
+        child: Center(
+          child: SingleChildScrollView(
+            padding: const EdgeInsets.all(24),
+            child: ConstrainedBox(
             constraints: const BoxConstraints(maxWidth: 400),
             constraints: const BoxConstraints(maxWidth: 400),
             child: Form(
             child: Form(
               key: _formKey,
               key: _formKey,
@@ -196,12 +197,13 @@ class _SyncSettingsPageState extends ConsumerState<SyncSettingsPage> {
                     const SizedBox(height: 16),
                     const SizedBox(height: 16),
                     const LinearProgressIndicator(),
                     const LinearProgressIndicator(),
                   ],
                   ],
-                ],
+                  ],
               ),
               ),
             ),
             ),
           ),
           ),
         ),
         ),
       ),
       ),
+      ),
     );
     );
   }
   }
 }
 }

+ 32 - 0
lib/ui/widgets/cod_desc_dropdown_item.dart

@@ -0,0 +1,32 @@
+import 'package:flutter/material.dart';
+
+class CodDescDropdownItem extends StatelessWidget {
+  final String? codice;
+  final String? descrizione;
+
+  const CodDescDropdownItem({
+    super.key,
+    required this.codice,
+    required this.descrizione,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    final style = DefaultTextStyle.of(context).style;
+    return RichText(
+      text: TextSpan(
+        children: [
+          TextSpan(
+            text: codice ?? '',
+            style: style.copyWith(fontWeight: FontWeight.bold),
+          ),
+          TextSpan(
+            text: '  ${descrizione ?? ''}',
+            style: style,
+          ),
+        ],
+      ),
+      overflow: TextOverflow.ellipsis,
+    );
+  }
+}

+ 120 - 121
lib/ui/widgets/customer_card.dart

@@ -1,30 +1,8 @@
 import 'package:flutter/material.dart';
 import 'package:flutter/material.dart';
 import 'package:go_router/go_router.dart';
 import 'package:go_router/go_router.dart';
+import 'package:ristoris/core/credit_score_color.dart';
 import 'package:ristoris/database/database.dart';
 import 'package:ristoris/database/database.dart';
 
 
-Color? _creditScoreBg(String? colorName) {
-  switch (colorName?.toUpperCase()) {
-    case 'VERDE':
-      return const Color(0xFF008000);
-    case 'VERDE CHIARO':
-      return const Color(0xFF90EE90);
-    case 'VERDE SCURO':
-      return const Color(0xFF006400);
-    case 'GIALLO':
-      return const Color(0xFFFFA500);
-    case 'GRIGIO':
-      return const Color(0xFF808080);
-    case 'ROSSO VIVO':
-      return const Color(0xFFA80000);
-    case 'ROSSO SCURO':
-      return const Color(0xFF8B0000);
-    case 'ROSSO':
-      return const Color(0xFFFF0000);
-    default:
-      return null;
-  }
-}
-
 class CustomerCard extends StatelessWidget {
 class CustomerCard extends StatelessWidget {
   final Cliente cliente;
   final Cliente cliente;
   const CustomerCard({super.key, required this.cliente});
   const CustomerCard({super.key, required this.cliente});
@@ -47,116 +25,134 @@ class CustomerCard extends StatelessWidget {
         child: Padding(
         child: Padding(
           padding: const EdgeInsets.all(16),
           padding: const EdgeInsets.all(16),
           child: Column(
           child: Column(
-            crossAxisAlignment: CrossAxisAlignment.start,
             children: [
             children: [
-              Row(
-                crossAxisAlignment: CrossAxisAlignment.start,
-                children: [
-                  Expanded(
-                    child: Text(
-                      cliente.ragioneSociale ?? '',
-                      style: theme.textTheme.bodyMedium?.copyWith(
-                        color: cs.primary,
-                      ),
-                      maxLines: 2,
-                      overflow: TextOverflow.ellipsis,
-                    ),
-                  ),
-                  if ((cliente.codCliente ?? '').isNotEmpty) ...[
-                    const SizedBox(width: 8),
-                    Container(
-                      padding: const EdgeInsets.symmetric(
-                        horizontal: 8,
-                        vertical: 4,
-                      ),
-                      decoration: BoxDecoration(
-                        color: _creditScoreBg(cliente.creditScoreColor) ??
-                            cs.surfaceVariant,
-                        borderRadius: BorderRadius.circular(4),
-                      ),
-                      child: Text(
-                        cliente.codCliente ?? '',
-                        style: TextStyle(
-                          fontSize: 12,
-                          height: 16 / 12,
-                          fontWeight: FontWeight.w500,
-                          color: _creditScoreBg(cliente.creditScoreColor) != null
-                              ? Colors.white
-                              : cs.onSurfaceVariant,
+              Expanded(
+                child: Column(
+                  crossAxisAlignment: CrossAxisAlignment.start,
+                  children: [
+                    Row(
+                      crossAxisAlignment: CrossAxisAlignment.start,
+                      children: [
+                        Expanded(
+                          child: Text(
+                            cliente.ragioneSociale ?? '',
+                            style: theme.textTheme.bodyMedium?.copyWith(
+                              color: cs.primary,
+                            ),
+                            maxLines: 2,
+                            overflow: TextOverflow.ellipsis,
+                          ),
                         ),
                         ),
-                      ),
+                        if ((cliente.codCliente ?? '').isNotEmpty) ...[
+                          const SizedBox(width: 8),
+                          Container(
+                            padding: const EdgeInsets.symmetric(
+                              horizontal: 8,
+                              vertical: 4,
+                            ),
+                            decoration: BoxDecoration(
+                              color:
+                                  creditScoreBg(cliente.creditScoreColor) ??
+                                  cs.surfaceVariant,
+                              borderRadius: BorderRadius.circular(4),
+                            ),
+                            child: Text(
+                              cliente.codCliente ?? '',
+                              style: TextStyle(
+                                fontSize: 12,
+                                height: 16 / 12,
+                                fontWeight: FontWeight.w500,
+                                color:
+                                    creditScoreBg(cliente.creditScoreColor) !=
+                                        null
+                                    ? Colors.white
+                                    : cs.onSurfaceVariant,
+                              ),
+                            ),
+                          ),
+                        ],
+                      ],
                     ),
                     ),
-                  ],
-                ],
-              ),
-
-              const SizedBox(height: 4),
-              Text(
-                cliente.email ?? '',
-                style: theme.textTheme.bodyMedium?.copyWith(
-                  color: cs.onSurfaceVariant,
-                ),
-                maxLines: 1,
-                overflow: TextOverflow.ellipsis,
-              ),
 
 
-              const SizedBox(height: 16),
-              Row(
-                children: [
-                  Icon(Icons.phone, size: 20, color: cs.onSurfaceVariant),
-                  const SizedBox(width: 8),
-                  Expanded(
-                    child: Text(
-                      cliente.telefono ?? '',
+                    const SizedBox(height: 4),
+                    Text(
+                      cliente.email ?? '',
                       style: theme.textTheme.bodyMedium?.copyWith(
                       style: theme.textTheme.bodyMedium?.copyWith(
                         color: cs.onSurfaceVariant,
                         color: cs.onSurfaceVariant,
                       ),
                       ),
                       maxLines: 1,
                       maxLines: 1,
                       overflow: TextOverflow.ellipsis,
                       overflow: TextOverflow.ellipsis,
                     ),
                     ),
-                  ),
-                ],
-              ),
-              Row(
-                children: [
-                  Icon(Icons.business, size: 20, color: cs.onSurfaceVariant),
-                  const SizedBox(width: 8),
-                  Expanded(
-                    child: Text(
-                      cliente.indirizzo ?? '',
-                      style: theme.textTheme.bodyMedium?.copyWith(
-                        color: cs.onSurfaceVariant,
-                      ),
-                      maxLines: 1,
-                      overflow: TextOverflow.ellipsis,
+
+                    const SizedBox(height: 16),
+                    Row(
+                      children: [
+                        Icon(Icons.phone, size: 20, color: cs.onSurfaceVariant),
+                        const SizedBox(width: 8),
+                        Expanded(
+                          child: Text(
+                            cliente.telefono ?? '',
+                            style: theme.textTheme.bodyMedium?.copyWith(
+                              color: cs.onSurfaceVariant,
+                            ),
+                            maxLines: 1,
+                            overflow: TextOverflow.ellipsis,
+                          ),
+                        ),
+                      ],
                     ),
                     ),
-                  ),
-                ],
-              ),
-              const SizedBox(height: 8),
-              Row(
-                children: [
-                  Icon(Icons.location_on, size: 20, color: cs.onSurfaceVariant),
-                  const SizedBox(width: 8),
-                  Expanded(
-                    child: Text(
-                      [
-                        if ((cliente.citta ?? '').isNotEmpty) cliente.citta,
-                        if ((cliente.provincia ?? '').isNotEmpty)
-                          cliente.provincia,
-                      ].join(', '),
-                      style: theme.textTheme.bodyMedium?.copyWith(
-                        color: cs.onSurfaceVariant,
-                      ),
-                      maxLines: 1,
-                      overflow: TextOverflow.ellipsis,
+                    const SizedBox(height: 4),
+                    Row(
+                      children: [
+                        Icon(
+                          Icons.business,
+                          size: 20,
+                          color: cs.onSurfaceVariant,
+                        ),
+                        const SizedBox(width: 8),
+                        Expanded(
+                          child: Text(
+                            cliente.indirizzo ?? '',
+                            style: theme.textTheme.bodyMedium?.copyWith(
+                              color: cs.onSurfaceVariant,
+                            ),
+                            maxLines: 1,
+                            overflow: TextOverflow.ellipsis,
+                          ),
+                        ),
+                      ],
                     ),
                     ),
-                  ),
-                ],
+                    const SizedBox(height: 8),
+                    Row(
+                      children: [
+                        Icon(
+                          Icons.location_on,
+                          size: 20,
+                          color: cs.onSurfaceVariant,
+                        ),
+                        const SizedBox(width: 8),
+                        Expanded(
+                          child: Text(
+                            [
+                              if ((cliente.citta ?? '').isNotEmpty)
+                                cliente.citta,
+                              if ((cliente.provincia ?? '').isNotEmpty)
+                                cliente.provincia,
+                            ].join(', '),
+                            style: theme.textTheme.bodyMedium?.copyWith(
+                              color: cs.onSurfaceVariant,
+                            ),
+                            maxLines: 1,
+                            overflow: TextOverflow.ellipsis,
+                          ),
+                        ),
+                      ],
+                    ),
+                  ],
+                ),
               ),
               ),
-              const SizedBox(height: 16),
               Divider(height: 1, color: cs.outlineVariant),
               Divider(height: 1, color: cs.outlineVariant),
-              const SizedBox(height: 12),
+              const SizedBox(height: 16),
               Row(
               Row(
                 children: [
                 children: [
                   Expanded(
                   Expanded(
@@ -180,8 +176,11 @@ class CustomerCard extends StatelessWidget {
                       onPressed: () => context.go(
                       onPressed: () => context.go(
                         '/dashboard/orders/new?cliente=${cliente.idCliente}',
                         '/dashboard/orders/new?cliente=${cliente.idCliente}',
                       ),
                       ),
-                      icon: const Icon(Icons.shopping_cart, size: 18),
-                      label: const Text('Nuovo ordine'),
+                      icon: const Icon(
+                        Icons.add_shopping_cart_outlined,
+                        size: 18,
+                      ),
+                      label: const Text('Ordine'),
                     ),
                     ),
                   ),
                   ),
                 ],
                 ],