Pārlūkot izejas kodu

Pedidos ahora llevan corte caja id y se pueden pasar de un corte de caja a otro

OscarGil03 3 mēneši atpakaļ
vecāks
revīzija
92ded34352

+ 3 - 0
lib/models/pedido_model.dart

@@ -82,6 +82,7 @@ class Pedido extends Basico {
       'sincronizado': sincronizado,
       'idWeb': idWeb,
       'uuid': uuid,
+      'idCorteCaja': idCorteCaja,
     }..addAll(super.toJson());
   }
 
@@ -104,6 +105,7 @@ class Pedido extends Basico {
       'cantTransferencia': cantTransferencia,
       'idMesa': idMesa,
       'uuid': uuid,
+      'idCorteCaja': idCorteCaja,
       'productos': productos.map((producto) => producto.toApi()).toList(),
       'propinas': propinas.map((propina) => propina.toApi()).toList(),
     };
@@ -139,6 +141,7 @@ class Pedido extends Basico {
     uuid = Basico.parseString(json['uuid']);
     idWeb = Basico.parseInt(json['idWeb']);
     sincronizado = Basico.parseString(json['sincronizado']);
+    idCorteCaja = Basico.parseString(json['idCorteCaja']);
 
     List<PedidoProducto> _productos = [];
     if (json["productos"] != null && (json["productos"] as List).isNotEmpty) {

+ 13 - 2
lib/services/repo_service.dart

@@ -937,8 +937,8 @@ class RepoService<T> {
         return Usuario.fromJson(map) as T;
       case CorteCaja:
         return CorteCaja.fromJson(map) as T;
-      // case Propinas:
-      //   return Propinas.fromJson(map) as T;
+      case Propinas:
+        return Propinas.fromJson(map) as T;
       default:
         throw Exception('Tipo no soportado');
     }
@@ -965,6 +965,17 @@ class RepoService<T> {
 
   //CORTE CAJA
 
+  Future<List<Pedido>> obtenerPedidosPorCorteCaja(String idCorteCaja) async {
+    var dbClient = await db;
+    List<Map<String, dynamic>> maps = await dbClient!.query(
+      'Pedido',
+      where: 'idCorteCaja = ? AND eliminado IS NULL AND estatus != ?',
+      whereArgs: [idCorteCaja, 'CANCELADO'],
+    );
+
+    return maps.map((map) => Pedido.fromJson(map)).toList();
+  }
+
   Future<List<Deposito>> obtenerDepositosPorIdCorteCaja(
       String idCorteCaja) async {
     var dbClient = await db;

+ 37 - 52
lib/viewmodels/corte_caja_view_model.dart

@@ -194,12 +194,8 @@ class CorteCajaViewModel extends ChangeNotifier {
     setIsLoading(true);
     var db = await RepoService().db;
 
-    // Suponiendo que tenemos un campo 'sincronizado' similar a Pedidos.
-    // Aquí obtendremos todos los corteCaja donde sincronizado IS NULL
     List<Map<String, dynamic>> result = await db!.query('CorteCaja',
-        where: 'sincronizado IS NULL',
-        orderBy: 'fechaApertura ASC' // Ordenar por fecha de apertura
-        );
+        where: 'sincronizado IS NULL', orderBy: 'fechaApertura ASC');
 
     List<CorteCaja> cortesNoSync =
         result.map((map) => CorteCaja.fromJson(map)).toList();
@@ -208,22 +204,18 @@ class CorteCajaViewModel extends ChangeNotifier {
   }
 
   Future<bool> sincronizarCorteCajas() async {
-    // Similar a sincronizarPedidos
     List<CorteCaja> cortesNoSincronizados =
         await fetchAllLocalCortesCajasNoSincronizadosOrdenadosPorFecha();
 
     if (cortesNoSincronizados.isNotEmpty) {
       CorteCaja corteNoSincronizado = cortesNoSincronizados.first;
 
-      // Cargar los detalles (depositos, retiros, gastos)
       if (corteNoSincronizado.id != null &&
           corteNoSincronizado.id!.isNotEmpty) {
         await fetchCorteCajaConDetalles(corteNoSincronizado.id!);
-        // Obtenemos el corte con la misma ID desde la lista de cortes
         corteNoSincronizado =
             _cortes.firstWhere((c) => c.id == corteNoSincronizado.id);
 
-// Asignamos los depósitos, retiros y gastos del ViewModel al objeto corteNoSincronizado
         corteNoSincronizado.depositos = this.depositos;
         corteNoSincronizado.retiros = this.retiros;
         corteNoSincronizado.gastos = this.gastos;
@@ -248,7 +240,7 @@ class CorteCajaViewModel extends ChangeNotifier {
       } else {
         print(
             'Error en la sincronización del corte de caja: ${response.mensaje}');
-        return true; // Retornar true para que siga intentando
+        return true;
       }
     } else {
       print('No se encontraron cortes de caja no sincronizados.');
@@ -357,50 +349,42 @@ class CorteCajaViewModel extends ChangeNotifier {
     notifyListeners();
   }
 
-  Future<void> cargarVentasDesdeFechaApertura(DateTime fechaApertura) async {
+  Future<void> cargarVentasPorCorteId(String idCorteCaja) async {
     setIsLoading(true);
-    RepoService<Pedido> repoPedido = RepoService<Pedido>();
-
-    DateTime fechaFin = _selectedCorte?.fechaCorte ?? DateTime.now().toUtc();
-
-    List<Pedido> pedidos =
-        (await repoPedido.buscarPorFecha(fechaApertura, fechaFin))
-            .where((pedido) =>
-                pedido.estatus == 'NUEVO' || pedido.estatus == 'TERMINADO')
-            .toList();
-
-    // Calcula los totales
-    double totalEfectivo = 0;
-    double totalTarjeta = 0;
-    double totalTransferencia = 0;
-    double totalDia = 0.0;
-    double cambio = 0.0;
-    double efeSinCambio = 0.0;
-    double totalSinCambio = 0.0;
-
-    for (var pedido in pedidos) {
-      totalEfectivo += pedido.cantEfectivo ?? 0;
-      totalTarjeta += pedido.cantTarjeta ?? 0;
-      totalTransferencia += pedido.cantTransferencia ?? 0;
-      totalSinCambio += pedido.totalPedido ?? 0;
-    }
-
-    totalDia = totalEfectivo + totalTarjeta + totalTransferencia;
-    cambio = totalDia - totalSinCambio;
-    efeSinCambio = totalEfectivo - cambio;
-
-    _ventaEfeController.text = formatoMiles(efeSinCambio);
-    _ventaTarjController.text = formatoMiles(totalTarjeta);
-    _ventaTransfController.text = formatoMiles(totalTransferencia);
-    _totalVentaController.text =
-        formatoMiles(efeSinCambio + totalTarjeta + totalTransferencia);
-
-    print(
-        'Total efectivo: $totalEfectivo, Total tarjeta: $totalTarjeta, Total transferencia: $totalTransferencia');
-    print('Pedidos encontrados: ${pedidos.length}');
+    try {
+      RepoService<Pedido> repoPedido = RepoService<Pedido>();
+      List<Pedido> pedidos =
+          await repoPedido.obtenerPedidosPorCorteCaja(idCorteCaja);
+
+      pedidos = pedidos.where((p) => p.estatus == 'TERMINADO').toList();
+
+      double totalEfectivo = 0;
+      double totalTarjeta = 0;
+      double totalTransferencia = 0;
+      double totalSinCambio = 0;
+
+      for (var pedido in pedidos) {
+        totalEfectivo += pedido.cantEfectivo ?? 0;
+        totalTarjeta += pedido.cantTarjeta ?? 0;
+        totalTransferencia += pedido.cantTransferencia ?? 0;
+        totalSinCambio += pedido.totalPedido ?? 0;
+      }
 
-    setIsLoading(false);
-    notifyListeners();
+      double totalDia = totalEfectivo + totalTarjeta + totalTransferencia;
+      double cambio = totalDia - totalSinCambio;
+      double efectivoSinCambio = totalEfectivo - cambio;
+
+      _ventaEfeController.text = formatoMiles(efectivoSinCambio);
+      _ventaTarjController.text = formatoMiles(totalTarjeta);
+      _ventaTransfController.text = formatoMiles(totalTransferencia);
+      _totalVentaController.text =
+          formatoMiles(efectivoSinCambio + totalTarjeta + totalTransferencia);
+    } catch (e) {
+      print("Error al cargar pedidos por idCorteCaja: $e");
+    } finally {
+      setIsLoading(false);
+      notifyListeners();
+    }
   }
 
   bool hasOpenCorteCaja() {
@@ -485,6 +469,7 @@ class CorteCajaViewModel extends ChangeNotifier {
     if (corteCajaId != null) {
       await fetchDepositosAndRetiros(corteCajaId);
       _selectedCorte = _cortes.firstWhere((corte) => corte.id == corteCajaId);
+      await cargarVentasPorCorteId(corteCajaId);
     }
 
     if (_selectedCorte == null) {

+ 41 - 12
lib/viewmodels/pedido_view_model.dart

@@ -265,9 +265,9 @@ class PedidoViewModel extends ChangeNotifier {
         }
 
         producto.toppings = toppings;
-        // List<Propinas> propinas = await repoPropina.obtenerTodos<Propinas>(
-        //     where: 'idPedido = ?', whereArgs: [idPedido]);
-        // pedido.propinas = propinas;
+        List<Propinas> propinas = await repoPropina.obtenerTodos<Propinas>(
+            where: 'idPedido = ?', whereArgs: [idPedido]);
+        pedido.propinas = propinas;
       }
 
       pedido.productos = productos;
@@ -395,19 +395,48 @@ class PedidoViewModel extends ChangeNotifier {
     setIsLoading(false);
     return allPedidos;
   }
-}
 
-Future<Map<String, dynamic>> prepararPedidoParaApi(Pedido pedido) async {
-  String? claveSucursal =
-      await RepoService().obtenerClaveSucursalSeleccionada();
+  Future<List<Pedido>> fetchPedidosNuevosByCorteId(String idCorteCaja) async {
+    var db = await RepoService().db;
+
+    List<Map<String, dynamic>> maps = await db!.query(
+      'Pedido',
+      where: 'estatus = ? AND idCorteCaja = ? AND eliminado IS NULL',
+      whereArgs: ['NUEVO', idCorteCaja],
+    );
 
-  Map<String, dynamic> apiMap = pedido.toApi();
+    if (maps.isNotEmpty) {
+      return maps.map((map) => Pedido.fromJson(map)).toList();
+    }
+    return [];
+  }
 
-  apiMap['claveSucursal'] = claveSucursal;
+  Future<void> actualizarCorteCajaEnPedidos(
+      List<int> idsPedidos, String nuevoIdCorte) async {
+    var db = await RepoService().db;
 
-  if (pedido.idWeb != null && pedido.idWeb! > 0) {
-    apiMap['idWeb'] = pedido.idWeb;
+    for (int idPedido in idsPedidos) {
+      await db!.update(
+        'Pedido',
+        {'idCorteCaja': nuevoIdCorte, 'sincronizado': null},
+        where: 'id = ?',
+        whereArgs: [idPedido],
+      );
+    }
   }
 
-  return apiMap;
+  Future<Map<String, dynamic>> prepararPedidoParaApi(Pedido pedido) async {
+    String? claveSucursal =
+        await RepoService().obtenerClaveSucursalSeleccionada();
+
+    Map<String, dynamic> apiMap = pedido.toApi();
+
+    apiMap['claveSucursal'] = claveSucursal;
+
+    if (pedido.idWeb != null && pedido.idWeb! > 0) {
+      apiMap['idWeb'] = pedido.idWeb;
+    }
+
+    return apiMap;
+  }
 }

+ 294 - 58
lib/views/corte_caja/corte_caja_form.dart

@@ -1,14 +1,18 @@
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:provider/provider.dart';
+import '../../models/models.dart';
 import '../../themes/themes.dart';
 import 'package:intl/intl.dart';
 import '../../models/corte_caja_model.dart';
 import '../../viewmodels/corte_caja_view_model.dart';
+import '../../viewmodels/viewmodels.dart';
 import '../../widgets/app_textfield.dart';
 import '../../widgets/widgets.dart';
 import 'dart:async';
 
+import '../pedido/pedido_screen.dart';
+
 class CorteCajaForm extends StatefulWidget {
   final String? corteCajaId;
 
@@ -72,11 +76,9 @@ class _CorteCajaFormState extends State<CorteCajaForm> {
                   ? formatNumber(viewModel.selectedCorte!.fondoDiaSig!)
                   : '';
 
-          if (fechaApertura != null) {
-            viewModel.cargarVentasDesdeFechaApertura(fechaApertura!).then((_) {
-              viewModel.calcularCorteFinal();
-            });
-          }
+          viewModel.cargarVentasPorCorteId(corte.id!).then((_) {
+            viewModel.calcularCorteFinal();
+          });
         });
       });
     }
@@ -109,6 +111,163 @@ class _CorteCajaFormState extends State<CorteCajaForm> {
     });
   }
 
+  void _mostrarDialogoPedidosNuevos(
+    BuildContext context,
+    List<Pedido> pedidos, {
+    required Function(List<Pedido>) onAbrirNuevaCaja,
+  }) {
+    showDialog(
+      context: context,
+      builder: (ctx) {
+        return AlertDialog(
+          title: Text(
+            'Atención: Aún cuentas con pedidos sin terminar.',
+            style: TextStyle(fontWeight: FontWeight.bold),
+          ),
+          content: SingleChildScrollView(
+            child: Column(
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: [
+                Text(
+                  '¿Deseas terminar los pedidos o abrir una nueva caja con ellos?',
+                  style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
+                ),
+                SizedBox(height: 10),
+                Text(
+                  'Pedidos pendientes:',
+                  style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
+                ),
+                SizedBox(height: 5),
+                Column(
+                  children: pedidos.map((p) {
+                    return Row(
+                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                      children: [
+                        Text(
+                          'Folio: ${p.folio}',
+                          style: TextStyle(
+                              fontSize: 16, fontWeight: FontWeight.w600),
+                        ),
+                        Text(
+                          '\$${p.totalPedido?.toStringAsFixed(2) ?? '0.00'}',
+                          style: TextStyle(
+                              fontSize: 16, fontWeight: FontWeight.w600),
+                        ),
+                      ],
+                    );
+                  }).toList(),
+                ),
+              ],
+            ),
+          ),
+          actions: [
+            TextButton(
+              style: ButtonStyle(
+                backgroundColor: WidgetStatePropertyAll(AppTheme.rojo),
+                foregroundColor: WidgetStatePropertyAll(AppTheme.quaternary),
+              ),
+              child: Text(
+                'Terminar mis pedidos primero',
+                style: TextStyle(fontSize: 16),
+              ),
+              onPressed: () {
+                Navigator.of(ctx).pop();
+                Navigator.push(
+                  context,
+                  MaterialPageRoute(
+                    builder: (context) => PedidoScreen(),
+                  ),
+                );
+              },
+            ),
+            TextButton(
+              style: ButtonStyle(
+                  backgroundColor: WidgetStatePropertyAll(AppTheme.verde),
+                  foregroundColor: WidgetStatePropertyAll(AppTheme.quaternary)),
+              child: Text(
+                'Abrir una caja nueva con esos pedidos',
+                style: TextStyle(fontSize: 16),
+              ),
+              onPressed: () {
+                Navigator.of(ctx).pop();
+                onAbrirNuevaCaja(pedidos);
+              },
+            ),
+          ],
+        );
+      },
+    );
+  }
+
+  void _mostrarDialogoDespuesDe6pm(
+    BuildContext context,
+    List<Pedido> pedidos,
+  ) {
+    showDialog(
+      context: context,
+      builder: (ctx) {
+        return AlertDialog(
+          title: Text(
+            'Pedidos sin terminar',
+            style: TextStyle(fontWeight: FontWeight.bold),
+          ),
+          content: SingleChildScrollView(
+            child: Column(
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: [
+                Text(
+                  'Debes terminar estos pedidos para poder realizar el corte:',
+                  style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
+                ),
+                SizedBox(height: 10),
+                Column(
+                  children: pedidos.map((p) {
+                    return Row(
+                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                      children: [
+                        Text(
+                          'Folio: ${p.folio}',
+                          style: TextStyle(
+                              fontSize: 16, fontWeight: FontWeight.w600),
+                        ),
+                        Text(
+                          '\$${p.totalPedido?.toStringAsFixed(2) ?? '0.00'}',
+                          style: TextStyle(
+                              fontSize: 16, fontWeight: FontWeight.w600),
+                        ),
+                      ],
+                    );
+                  }).toList(),
+                ),
+              ],
+            ),
+          ),
+          actions: [
+            TextButton(
+              style: ButtonStyle(
+                backgroundColor: WidgetStatePropertyAll(AppTheme.rojo),
+                foregroundColor: WidgetStatePropertyAll(AppTheme.quaternary),
+              ),
+              child: Text(
+                'Terminar mis pedidos',
+                style: TextStyle(fontSize: 16),
+              ),
+              onPressed: () {
+                Navigator.of(ctx).pop();
+                Navigator.push(
+                  context,
+                  MaterialPageRoute(
+                    builder: (context) => PedidoScreen(),
+                  ),
+                );
+              },
+            ),
+          ],
+        );
+      },
+    );
+  }
+
   @override
   Widget build(BuildContext context) {
     final viewModel = Provider.of<CorteCajaViewModel>(context);
@@ -317,13 +476,19 @@ class _CorteCajaFormState extends State<CorteCajaForm> {
                             trailing: IconButton(
                               icon: Icon(Icons.remove_circle_outline,
                                   color: Colors.red),
-                              onPressed: () {
-                                cuadroConfirmacion(
-                                  context,
-                                  etiqueta:
-                                      "¿Estás seguro de eliminar el depósito?",
-                                  onConfirm: () {
-                                    viewModel.eliminarDeposito(deposito.id!);
+                              onPressed: () async {
+                                showDialog(
+                                  context: context,
+                                  builder: (context) {
+                                    return TotpCuadroConfirmacion(
+                                      title: "Eliminar Deposito",
+                                      content:
+                                          "Por favor, ingresa el código de autenticación para continuar.",
+                                      onSuccess: () {
+                                        viewModel
+                                            .eliminarDeposito(deposito.id!);
+                                      },
+                                    );
                                   },
                                 );
                               },
@@ -406,13 +571,18 @@ class _CorteCajaFormState extends State<CorteCajaForm> {
                             trailing: IconButton(
                               icon: Icon(Icons.remove_circle_outline,
                                   color: Colors.red),
-                              onPressed: () {
-                                cuadroConfirmacion(
-                                  context,
-                                  etiqueta:
-                                      "¿Estás seguro de eliminar el retiro?",
-                                  onConfirm: () {
-                                    viewModel.eliminarRetiro(retiro.id!);
+                              onPressed: () async {
+                                showDialog(
+                                  context: context,
+                                  builder: (context) {
+                                    return TotpCuadroConfirmacion(
+                                      title: "Eliminar Retiro",
+                                      content:
+                                          "Por favor, ingresa el código de autenticación para continuar.",
+                                      onSuccess: () {
+                                        viewModel.eliminarRetiro(retiro.id!);
+                                      },
+                                    );
                                   },
                                 );
                               },
@@ -494,13 +664,18 @@ class _CorteCajaFormState extends State<CorteCajaForm> {
                             trailing: IconButton(
                               icon: Icon(Icons.remove_circle_outline,
                                   color: Colors.red),
-                              onPressed: () {
-                                cuadroConfirmacion(
-                                  context,
-                                  etiqueta:
-                                      "¿Estás seguro de eliminar el gasto?",
-                                  onConfirm: () {
-                                    viewModel.eliminarGasto(gasto.id!);
+                              onPressed: () async {
+                                showDialog(
+                                  context: context,
+                                  builder: (context) {
+                                    return TotpCuadroConfirmacion(
+                                      title: "Eliminar Gasto",
+                                      content:
+                                          "Por favor, ingresa el código de autenticación para continuar.",
+                                      onSuccess: () {
+                                        viewModel.eliminarGasto(gasto.id!);
+                                      },
+                                    );
                                   },
                                 );
                               },
@@ -584,15 +759,61 @@ class _CorteCajaFormState extends State<CorteCajaForm> {
                     const SizedBox(width: 15),
                     if (viewModel.selectedCorte?.modificado != null)
                       boton('Realizar Corte', () async {
-                        cuadroConfirmacion(
-                          context,
-                          etiqueta: "¿Estás seguro realizar el corte?",
-                          onConfirm: () async {
-                            await viewModel.guardarCorte(esCorte: true);
-                            Navigator.pop(context);
-                            await viewModel.imprimirCorteCajaTicket();
-                          },
-                        );
+                        // 1) Verificar si hay pedidos con estatus NUEVO de este corte
+                        final pedidosViewModel = Provider.of<PedidoViewModel>(
+                            context,
+                            listen: false);
+                        List<Pedido> pedidosNuevos =
+                            await pedidosViewModel.fetchPedidosNuevosByCorteId(
+                                viewModel.selectedCorte!.id!);
+
+                        // 2) Si no hay pedidos con estatus NUEVO se continúa flujo normal
+                        if (pedidosNuevos.isEmpty) {
+                          cuadroConfirmacion(
+                            context,
+                            etiqueta: "¿Estás seguro de realizar el corte?",
+                            onConfirm: () async {
+                              await viewModel.guardarCorte(esCorte: true);
+                              Navigator.pop(context);
+                              await viewModel.imprimirCorteCajaTicket();
+                            },
+                          );
+                          return;
+                        }
+
+                        // 3) Hay pedidos con estatus NUEVO se va a revisar hora local
+                        DateTime now = DateTime.now().toLocal();
+                        print(DateFormat('dd/MM/yyyy HH:mm:ss').format(now));
+                        if (now.hour < 18) {
+                          // Si son antes de las 6pm mostramos el diálogo para pasar los pedidos al siguiente corte
+                          _mostrarDialogoPedidosNuevos(
+                            context,
+                            pedidosNuevos,
+                            onAbrirNuevaCaja: (nuevosPedidos) async {
+                              final oldCorteId = viewModel.selectedCorte!.id!;
+
+                              await viewModel.guardarCorte(esCorte: true);
+
+                              String? nuevaCajaId =
+                                  await viewModel.createCorteCaja();
+                              if (nuevaCajaId == null) return;
+
+                              List<int> ids =
+                                  nuevosPedidos.map((p) => p.id!).toList();
+                              await pedidosViewModel
+                                  .actualizarCorteCajaEnPedidos(
+                                      ids, nuevaCajaId);
+
+                              Navigator.pop(context);
+
+                              await viewModel.imprimirCorteCajaTicket(
+                                  corteCajaId: oldCorteId);
+                            },
+                          );
+                        } else {
+                          // Si son de las 6pm mostramos el diálogo que forza el terminar esos pedidos
+                          _mostrarDialogoDespuesDe6pm(context, pedidosNuevos);
+                        }
                       }, height: 60, width: 250),
                   ],
                 ),
@@ -640,7 +861,6 @@ class _CorteCajaFormState extends State<CorteCajaForm> {
                   controller: _personaDepositoController,
                 ),
                 SizedBox(height: 20),
-                // Lista de depósitos
                 Text(
                   "Lista de Depósitos",
                   style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
@@ -663,14 +883,19 @@ class _CorteCajaFormState extends State<CorteCajaForm> {
                                 trailing: IconButton(
                                   icon: Icon(Icons.remove_circle_outline,
                                       color: Colors.red),
-                                  onPressed: () {
-                                    cuadroConfirmacion(
-                                      context,
-                                      etiqueta:
-                                          "¿Estás seguro de eliminar el depósito?",
-                                      onConfirm: () {
-                                        viewModel
-                                            .eliminarDeposito(deposito.id!);
+                                  onPressed: () async {
+                                    showDialog(
+                                      context: context,
+                                      builder: (context) {
+                                        return TotpCuadroConfirmacion(
+                                          title: "Eliminar Deposito",
+                                          content:
+                                              "Por favor, ingresa el código de autenticación para continuar.",
+                                          onSuccess: () {
+                                            viewModel
+                                                .eliminarDeposito(deposito.id!);
+                                          },
+                                        );
                                       },
                                     );
                                   },
@@ -832,13 +1057,19 @@ class _CorteCajaFormState extends State<CorteCajaForm> {
                                 trailing: IconButton(
                                   icon: Icon(Icons.remove_circle_outline,
                                       color: Colors.red),
-                                  onPressed: () {
-                                    cuadroConfirmacion(
-                                      context,
-                                      etiqueta:
-                                          "¿Estás seguro de eliminar el retiro?",
-                                      onConfirm: () {
-                                        viewModel.eliminarRetiro(retiro.id!);
+                                  onPressed: () async {
+                                    showDialog(
+                                      context: context,
+                                      builder: (context) {
+                                        return TotpCuadroConfirmacion(
+                                          title: "Eliminar Retiro",
+                                          content:
+                                              "Por favor, ingresa el código de autenticación para continuar.",
+                                          onSuccess: () {
+                                            viewModel
+                                                .eliminarRetiro(retiro.id!);
+                                          },
+                                        );
                                       },
                                     );
                                   },
@@ -999,13 +1230,18 @@ class _CorteCajaFormState extends State<CorteCajaForm> {
                                 trailing: IconButton(
                                   icon: Icon(Icons.remove_circle_outline,
                                       color: Colors.red),
-                                  onPressed: () {
-                                    cuadroConfirmacion(
-                                      context,
-                                      etiqueta:
-                                          "¿Estás seguro de eliminar el gasto?",
-                                      onConfirm: () {
-                                        viewModel.eliminarGasto(gasto.id!);
+                                  onPressed: () async {
+                                    showDialog(
+                                      context: context,
+                                      builder: (context) {
+                                        return TotpCuadroConfirmacion(
+                                          title: "Eliminar Gasto",
+                                          content:
+                                              "Por favor, ingresa el código de autenticación para continuar.",
+                                          onSuccess: () {
+                                            viewModel.eliminarGasto(gasto.id!);
+                                          },
+                                        );
                                       },
                                     );
                                   },

+ 12 - 12
lib/views/corte_caja/corte_caja_screen.dart

@@ -252,18 +252,18 @@ class _CorteCajaScreenState extends State<CorteCajaScreen> {
                         child: Text('Anterior'),
                         style: ButtonStyle(
                           backgroundColor:
-                              MaterialStateProperty.resolveWith<Color?>(
-                            (Set<MaterialState> states) {
-                              if (states.contains(MaterialState.disabled)) {
+                              WidgetStateProperty.resolveWith<Color?>(
+                            (Set<WidgetState> states) {
+                              if (states.contains(WidgetState.disabled)) {
                                 return Colors.grey;
                               }
                               return AppTheme.primary;
                             },
                           ),
                           foregroundColor:
-                              MaterialStateProperty.resolveWith<Color?>(
-                            (Set<MaterialState> states) {
-                              if (states.contains(MaterialState.disabled)) {
+                              WidgetStateProperty.resolveWith<Color?>(
+                            (Set<WidgetState> states) {
+                              if (states.contains(WidgetState.disabled)) {
                                 return Colors.black;
                               }
                               return Colors.white;
@@ -281,18 +281,18 @@ class _CorteCajaScreenState extends State<CorteCajaScreen> {
                         child: Text('Siguiente'),
                         style: ButtonStyle(
                           backgroundColor:
-                              MaterialStateProperty.resolveWith<Color?>(
-                            (Set<MaterialState> states) {
-                              if (states.contains(MaterialState.disabled)) {
+                              WidgetStateProperty.resolveWith<Color?>(
+                            (Set<WidgetState> states) {
+                              if (states.contains(WidgetState.disabled)) {
                                 return Colors.grey;
                               }
                               return AppTheme.primary;
                             },
                           ),
                           foregroundColor:
-                              MaterialStateProperty.resolveWith<Color?>(
-                            (Set<MaterialState> states) {
-                              if (states.contains(MaterialState.disabled)) {
+                              WidgetStateProperty.resolveWith<Color?>(
+                            (Set<WidgetState> states) {
+                              if (states.contains(WidgetState.disabled)) {
                                 return Colors.black;
                               }
                               return Colors.white;

+ 29 - 0
lib/views/pedido/pedido_detalle_screen.dart

@@ -53,6 +53,14 @@ class _PedidoDetalleScreenState extends State<PedidoDetalleScreen> {
     double precioDescuento = totalSinDescuento * (descuento / 100);
     double totalConDescuento = totalSinDescuento - precioDescuento;
 
+    double totalPropina = 0.0;
+    if (pedido.propinas.isNotEmpty) {
+      totalPropina = pedido.propinas.fold(
+        0.0,
+        (previousValue, propina) => previousValue + (propina.cantidad ?? 0.0),
+      );
+    }
+
     return Scaffold(
       appBar: AppBar(
         title: Text(
@@ -258,6 +266,27 @@ class _PedidoDetalleScreenState extends State<PedidoDetalleScreen> {
                                       fontWeight: FontWeight.bold)),
                             ],
                           ),
+                          if (pedido.propinas.isNotEmpty) ...[
+                            const Divider(),
+                            Row(
+                              mainAxisAlignment: MainAxisAlignment.end,
+                              children: [
+                                const Text(
+                                  'Propina:',
+                                  style: TextStyle(
+                                      fontSize: 16,
+                                      fontWeight: FontWeight.bold),
+                                ),
+                                const SizedBox(width: 5),
+                                Text(
+                                  '\$${formatCurrency(totalPropina)}',
+                                  style: const TextStyle(
+                                      fontSize: 16,
+                                      fontWeight: FontWeight.bold),
+                                ),
+                              ],
+                            ),
+                          ],
                         ],
                       ),
                     ),

+ 39 - 23
lib/views/pedido/pedido_form.dart

@@ -2,7 +2,6 @@ import 'dart:async';
 import 'dart:io';
 import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
-import 'package:flutter/services.dart';
 import 'package:intl/intl.dart';
 import 'package:otp/otp.dart';
 import 'package:provider/provider.dart';
@@ -213,12 +212,12 @@ class _PedidoFormState extends State<PedidoForm> {
                       onPressed: () => Navigator.of(context).pop(),
                       child: const Text('Aceptar'),
                       style: ButtonStyle(
-                          padding: MaterialStatePropertyAll(
+                          padding: WidgetStatePropertyAll(
                               EdgeInsets.fromLTRB(20, 10, 20, 10)),
                           backgroundColor:
-                              MaterialStatePropertyAll(AppTheme.tertiary),
+                              WidgetStatePropertyAll(AppTheme.tertiary),
                           foregroundColor:
-                              MaterialStatePropertyAll(AppTheme.quaternary))),
+                              WidgetStatePropertyAll(AppTheme.quaternary))),
                 ],
               );
             },
@@ -359,11 +358,11 @@ class _PedidoFormState extends State<PedidoForm> {
               onPressed: () => Navigator.of(context).pop(false),
               child: const Text('Cancelar'),
               style: ButtonStyle(
-                padding: MaterialStatePropertyAll(
+                padding: WidgetStatePropertyAll(
                   EdgeInsets.fromLTRB(20, 10, 20, 10),
                 ),
-                backgroundColor: MaterialStatePropertyAll(Colors.red),
-                foregroundColor: MaterialStatePropertyAll(AppTheme.secondary),
+                backgroundColor: WidgetStatePropertyAll(Colors.red),
+                foregroundColor: WidgetStatePropertyAll(AppTheme.secondary),
               ),
             ),
             const SizedBox(width: 10),
@@ -381,11 +380,11 @@ class _PedidoFormState extends State<PedidoForm> {
               },
               child: const Text('Guardar'),
               style: ButtonStyle(
-                padding: MaterialStatePropertyAll(
+                padding: WidgetStatePropertyAll(
                   EdgeInsets.fromLTRB(20, 10, 20, 10),
                 ),
-                backgroundColor: MaterialStatePropertyAll(Colors.black),
-                foregroundColor: MaterialStatePropertyAll(AppTheme.quaternary),
+                backgroundColor: WidgetStatePropertyAll(Colors.black),
+                foregroundColor: WidgetStatePropertyAll(AppTheme.quaternary),
               ),
             ),
           ],
@@ -423,6 +422,15 @@ class _PedidoFormState extends State<PedidoForm> {
         }).toList(),
       );
 
+      final corteViewModel =
+          Provider.of<CorteCajaViewModel>(context, listen: false);
+      CorteCaja? corteActivo = corteViewModel.cortes.firstWhereOrNull(
+        (corte) => corte.fechaCorte == null,
+      );
+      if (corteActivo != null) {
+        nuevoPedido.idCorteCaja = corteActivo.id;
+      }
+
       bool result = await Provider.of<PedidoViewModel>(context, listen: false)
           .guardarPedidoLocal(pedido: nuevoPedido);
 
@@ -735,11 +743,10 @@ class _PedidoFormState extends State<PedidoForm> {
                   child: const Text('Cancelar', style: TextStyle(fontSize: 18)),
                   onPressed: () => Navigator.of(context).pop(false),
                   style: ButtonStyle(
-                    padding: MaterialStateProperty.all(
+                    padding: WidgetStatePropertyAll(
                         EdgeInsets.fromLTRB(30, 20, 30, 20)),
-                    backgroundColor: MaterialStateProperty.all(Colors.red),
-                    foregroundColor:
-                        MaterialStateProperty.all(AppTheme.secondary),
+                    backgroundColor: WidgetStatePropertyAll(Colors.red),
+                    foregroundColor: WidgetStatePropertyAll(AppTheme.secondary),
                   ),
                 ),
                 const SizedBox(width: 100),
@@ -749,12 +756,12 @@ class _PedidoFormState extends State<PedidoForm> {
                       ? () => Navigator.of(context).pop(true)
                       : null,
                   style: ButtonStyle(
-                    padding: MaterialStateProperty.all(
+                    padding: WidgetStatePropertyAll(
                         EdgeInsets.fromLTRB(30, 20, 30, 20)),
-                    backgroundColor: MaterialStateProperty.all(
+                    backgroundColor: WidgetStatePropertyAll(
                         totalCompletado ? AppTheme.tertiary : Colors.grey),
                     foregroundColor:
-                        MaterialStateProperty.all(AppTheme.quaternary),
+                        WidgetStatePropertyAll(AppTheme.quaternary),
                   ),
                 ),
               ],
@@ -945,6 +952,15 @@ class _PedidoFormState extends State<PedidoForm> {
       uuid: Uuid().v4(),
     );
 
+    final corteViewModel =
+        Provider.of<CorteCajaViewModel>(context, listen: false);
+    CorteCaja? corteActivo = corteViewModel.cortes.firstWhereOrNull(
+      (corte) => corte.fechaCorte == null,
+    );
+    if (corteActivo != null) {
+      nuevoPedido.idCorteCaja = corteActivo.id;
+    }
+
     List<PedidoProducto> listaPedidoProducto = carrito.map((item) {
       List<PedidoProductoTopping> selectedToppings = [];
 
@@ -1861,11 +1877,11 @@ class _PedidoFormState extends State<PedidoForm> {
                           style: TextStyle(
                               fontSize: 18, color: AppTheme.secondary)),
                       style: ButtonStyle(
-                          padding: MaterialStatePropertyAll(
+                          padding: WidgetStatePropertyAll(
                               EdgeInsets.fromLTRB(20, 10, 20, 10)),
-                          backgroundColor: MaterialStatePropertyAll(Colors.red),
+                          backgroundColor: WidgetStatePropertyAll(Colors.red),
                           foregroundColor:
-                              MaterialStatePropertyAll(AppTheme.secondary)),
+                              WidgetStatePropertyAll(AppTheme.secondary)),
                     ),
                     TextButton(
                       onPressed: () {
@@ -1910,12 +1926,12 @@ class _PedidoFormState extends State<PedidoForm> {
                           style: TextStyle(
                               fontSize: 18, color: AppTheme.quaternary)),
                       style: ButtonStyle(
-                          padding: MaterialStatePropertyAll(
+                          padding: WidgetStatePropertyAll(
                               EdgeInsets.fromLTRB(20, 10, 20, 10)),
                           backgroundColor:
-                              MaterialStatePropertyAll(AppTheme.secondary),
+                              WidgetStatePropertyAll(AppTheme.secondary),
                           foregroundColor:
-                              MaterialStatePropertyAll(AppTheme.secondary)),
+                              WidgetStatePropertyAll(AppTheme.secondary)),
                     ),
                   ],
                 )

+ 3 - 3
lib/views/pedido/pedido_sync.dart

@@ -21,9 +21,9 @@ class PedidoSync {
       // Primero sincronizamos pedidos
       bool hasMorePedidosToSync = await pedidoViewModel.sincronizarPedidos();
 
-      // Luego sincronizamos corte de caja
-      bool hasMoreCortesToSync =
-          await corteCajaViewModel.sincronizarCorteCajas();
+      // // Luego sincronizamos corte de caja
+      // bool hasMoreCortesToSync =
+      //     await corteCajaViewModel.sincronizarCorteCajas();
 
       // Opcionalmente, podrías detener el timer si ya no hay nada más que sincronizar.
       // if (!hasMorePedidosToSync && !hasMoreCortesToSync) {

+ 13 - 13
lib/widgets/app_drawer.dart

@@ -104,6 +104,18 @@ class AppDrawer extends StatelessWidget {
                   },
                 ),
                 ListTile(
+                  leading: circulo(const Icon(Icons.point_of_sale)),
+                  title: const Text('Corte de caja'),
+                  onTap: () => {
+                    Navigator.pop(context),
+                    Navigator.of(context).push(
+                      MaterialPageRoute(
+                        builder: (context) => CorteCajaScreen(),
+                      ),
+                    ),
+                  },
+                ),
+                ListTile(
                   leading: circulo(const Icon(Icons.menu_book_rounded)),
                   title: const Text('Productos'),
                   onTap: () => {
@@ -147,18 +159,6 @@ class AppDrawer extends StatelessWidget {
                     title: const Text('Administración'),
                     children: [
                       ListTile(
-                        leading: circulo(const Icon(Icons.point_of_sale)),
-                        title: const Text('Corte de caja'),
-                        onTap: () => {
-                          Navigator.pop(context),
-                          Navigator.of(context).push(
-                            MaterialPageRoute(
-                              builder: (context) => CorteCajaScreen(),
-                            ),
-                          ),
-                        },
-                      ),
-                      ListTile(
                         leading: circulo(const Icon(Icons.discount)),
                         title: const Text('Descuentos'),
                         onTap: () => {
@@ -342,7 +342,7 @@ class AppDrawer extends StatelessWidget {
             child: Align(
               alignment: Alignment.bottomCenter,
               child: Text(
-                '$prefijoVersion.1.24.12.12',
+                '$prefijoVersion.1.24.12.27',
                 style: const TextStyle(fontWeight: FontWeight.w300),
               ),
             ),