import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:omni_datetime_picker/omni_datetime_picker.dart'; import 'package:provider/provider.dart'; import 'package:turquessa_app/views/venta/venta_csv.dart'; import '../../widgets/widgets_components.dart'; import '../../models/models.dart'; import '../../viewmodels/viewmodels.dart'; import 'venta_ticket.dart'; import '../../widgets/widgets.dart'; import '../../themes/themes.dart'; class VentaScreen extends StatefulWidget { @override _VentaScreenState createState() => _VentaScreenState(); } class _VentaScreenState extends State { DateTime? fechaInicialSeleccionada; DateTime? fechaFinalSeleccionada; List pedidosNoCancelados = []; List pedidosCancelados = []; List listaPropinas = []; final _busqueda = TextEditingController(text: ''); double totalDelDia = 0.0; double totalPropinas = 0.0; double totalCancelados = 0.0; double totalEfectivoDelDia = 0.0; double totalTarjetaDelDia = 0.0; double totalTransferenciaDelDia = 0.0; double cambio = 0.0; double totalSinCambio = 0.0; String formatCurrency(double amount) { final format = NumberFormat("#,##0.00", "es_MX"); return format.format(amount); } void clearSearchAndReset() { setState(() { _busqueda.clear(); fechaInicialSeleccionada = null; fechaFinalSeleccionada = null; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text( "Resumen de Pedidos por Periodo", style: TextStyle(color: AppTheme.secondary), ), actions: [ IconButton( icon: const Icon(Icons.save_alt), onPressed: () { exportCSV(fechaInicialSeleccionada, fechaFinalSeleccionada); }, tooltip: 'Exportar a CSV', ), ], iconTheme: IconThemeData(color: AppTheme.secondary)), body: Padding( padding: const EdgeInsets.all(16.0), child: Column( children: [ Row( children: [ Expanded( flex: 3, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 0.0), child: tarjeta( ListTile( title: Text( "Fecha Inicial", style: TextStyle( color: AppTheme.quaternary, fontWeight: FontWeight.bold), ), subtitle: Text( fechaInicialSeleccionada == null ? "" : DateFormat("dd/MM/yyyy") .format(fechaInicialSeleccionada!), style: TextStyle( color: AppTheme.quaternary, fontWeight: FontWeight.bold), ), trailing: Icon(Icons.calendar_month, color: AppTheme.quaternary), onTap: () async { DateTime? d = await showDatetimePicker( context, fechaInicialSeleccionada, inicia: fechaInicialSeleccionada, tipo: OmniDateTimePickerType.date, solofecha: true); if (d == null) return; setState(() { fechaInicialSeleccionada = d; }); cargarPedidos(fechaInicialSeleccionada, fechaFinalSeleccionada); }), color: AppTheme.tertiary, ), )), const SizedBox( width: 10, ), Expanded( flex: 3, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 0.0), child: tarjeta( ListTile( title: Text( "Fecha Final", style: TextStyle( color: AppTheme.quaternary, fontWeight: FontWeight.bold), ), subtitle: Text( fechaFinalSeleccionada == null ? "" : DateFormat("dd/MM/yyyy") .format(fechaFinalSeleccionada!), style: TextStyle( color: AppTheme.quaternary, fontWeight: FontWeight.bold), ), trailing: Icon(Icons.calendar_month, color: AppTheme.quaternary), onTap: () async { DateTime? d = await showDatetimePicker( context, fechaFinalSeleccionada, inicia: fechaFinalSeleccionada, tipo: OmniDateTimePickerType.date, solofecha: true); if (d == null) return; setState(() { fechaFinalSeleccionada = d; }); cargarPedidos(fechaInicialSeleccionada, fechaFinalSeleccionada); }), color: AppTheme.tertiary, ), )), const SizedBox( width: 500, ), Expanded( flex: 2, child: Padding( padding: const EdgeInsets.only(top: 0), child: ElevatedButton( onPressed: clearSearchAndReset, style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20.0), ), backgroundColor: AppTheme.tertiary, padding: const EdgeInsets.symmetric(vertical: 25), ), child: Text('Limpiar', style: TextStyle( color: AppTheme.quaternary, fontSize: 18)), ), ), ), ], ), Expanded( child: tarjeta( Padding( padding: const EdgeInsets.all(8.0), child: ListView.builder( itemCount: pedidosNoCancelados.length + pedidosCancelados.length, itemBuilder: (context, index) { if (index < pedidosNoCancelados.length) { final pedido = pedidosNoCancelados[index]; return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( "Folio: ${pedido.folio}", style: TextStyle( fontSize: 20, fontWeight: FontWeight.w500), ), Text( "Fecha/Hora: ${_formatDateTime(pedido.peticion)}", style: TextStyle( fontSize: 20, fontWeight: FontWeight.w500), ), Text( "Propina: \$${formatCurrency(_propinaPedido(pedido.id) ?? 0)}", style: TextStyle( fontSize: 20, fontWeight: FontWeight.w500), ), Text( "Total: \$${formatCurrency(pedido.totalPedido ?? 0)}", style: TextStyle( fontSize: 20, fontWeight: FontWeight.w500)), ], ); } else { final pedido = pedidosCancelados[index - pedidosNoCancelados.length]; return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( "Folio: ${pedido.folio} (Cancelado)", style: TextStyle( fontSize: 20, fontWeight: FontWeight.w500, color: Colors.red), ), Text( "Fecha/Hora: ${_formatDateTime(pedido.peticion)}", style: TextStyle( fontSize: 20, fontWeight: FontWeight.w500), ), Text( "Propina: \$${formatCurrency(_propinaPedido(pedido.id) ?? 0)}", style: TextStyle( fontSize: 20, fontWeight: FontWeight.w500), ), Text( "Total: \$${formatCurrency(pedido.totalPedido ?? 0)}", style: TextStyle( fontSize: 20, fontWeight: FontWeight.w500, color: Colors.red)), ], ); } }, ), ), )), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ ElevatedButton.icon( icon: Icon( Icons.receipt_long_outlined, color: AppTheme.quaternary, size: 30, ), onPressed: pedidosNoCancelados.isNotEmpty || pedidosCancelados.isNotEmpty ? () => imprimirResumenPedidos( pedidosNoCancelados + pedidosCancelados) : null, label: Text( "Imprimir Resumen", style: TextStyle(color: AppTheme.quaternary, fontSize: 18), ), style: ButtonStyle( backgroundColor: MaterialStatePropertyAll(AppTheme.tertiary), padding: MaterialStatePropertyAll( EdgeInsets.fromLTRB(30, 20, 30, 20))), ), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Row( children: [ Padding( padding: const EdgeInsets.all(16.0), child: Text( "Total Propina: \$${formatCurrency(totalPropinas)}", style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold), ), ), Padding( padding: const EdgeInsets.all(16.0), child: Text( "Total: \$${formatCurrency(totalDelDia)}", style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold), ), ), ], ), Row( children: [ if (totalTarjetaDelDia > 0) Padding( padding: const EdgeInsets.all(16.0), child: Text( "Total en Tarjeta: \$${formatCurrency(totalTarjetaDelDia)}", style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold), ), ), if (totalTransferenciaDelDia > 0) Padding( padding: const EdgeInsets.all(16.0), child: Text( "Total en Transferencia: \$${formatCurrency(totalTransferenciaDelDia)}", style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold), ), ), if (totalEfectivoDelDia > 0) Padding( padding: const EdgeInsets.all(16.0), child: Text( "Total en Efectivo: \$${formatCurrency(totalEfectivoDelDia)}", style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold), ), ), if (cambio > 0) Padding( padding: const EdgeInsets.all(16.0), child: Text( "Cambio Entregado: \$${formatCurrency(cambio)}", style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold), ), ), ], ), if (totalCancelados > 0) Padding( padding: const EdgeInsets.all(16.0), child: Text( "Total cancelados: \$${formatCurrency(totalCancelados)}", style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.red), ), ), ], ), ], ) ], ), ), ); } void cargarPedidos(DateTime? fechaInicial, DateTime? fechaFinal) async { if (fechaInicial != null && fechaFinal != null) { // Convertir el inicio y fin del día local a UTC final inicioDelDia = DateTime(fechaInicial.year, fechaInicial.month, fechaInicial.day) .toUtc(); // Convierte la fecha local de inicio del día a UTC final finDelDia = DateTime( fechaFinal.year, fechaFinal.month, fechaFinal.day, 23, 59, 59) .toUtc(); // Convierte la fecha local de fin del día a UTC print('Buscando pedidos desde: $inicioDelDia hasta: $finDelDia (en UTC)'); // Realizar la búsqueda en UTC final pedidos = await Provider.of(context, listen: false) .buscarPorFecha(inicioDelDia, finDelDia); print('Pedidos obtenidos: ${pedidos.length}'); pedidos.forEach((pedido) => print( 'Pedido: ${pedido.folio}, Total: ${pedido.totalPedido}, Estatus: ${pedido.estatus}, Propinas: ${pedido.propinas.length}')); final pedidosNoCancelados = pedidos.where((p) => p.estatus != "CANCELADO").toList(); final pedidosCancelados = pedidos.where((p) => p.estatus == "CANCELADO").toList(); totalDelDia = 0.0; totalPropinas = 0.0; totalCancelados = 0.0; totalEfectivoDelDia = 0.0; totalTarjetaDelDia = 0.0; totalTransferenciaDelDia = 0.0; cambio = 0.0; totalSinCambio = 0.0; for (var pedido in pedidosNoCancelados) { totalDelDia += pedido.totalPedido ?? 0.0; totalEfectivoDelDia += pedido.cantEfectivo ?? 0.0; totalTarjetaDelDia += pedido.cantTarjeta ?? 0.0; totalTransferenciaDelDia += pedido.cantTransferencia ?? 0.0; totalSinCambio = totalEfectivoDelDia + totalTarjetaDelDia + totalTransferenciaDelDia; cambio = totalSinCambio - totalDelDia; print("Propinas: ${pedido.propinas.length}"); // if (pedido.propinas.length > 0) { // for (var propina in pedido.propinas) { // totalPropinas += propina.cantidad ?? 0.0; // } // } final propinas = await Provider.of(context, listen: false) .obtenerPropinasPorPedido(pedido.id); listaPropinas = propinas; for (var propina in propinas) { totalPropinas += propina.cantidad ?? 0.0; } print("Total propinas: ${totalPropinas}"); } totalCancelados = pedidosCancelados.fold( 0.0, (sum, current) => sum + (current.totalPedido ?? 0.0)); setState(() { this.pedidosNoCancelados = pedidosNoCancelados; this.pedidosCancelados = pedidosCancelados; }); } } void exportCSV(DateTime? fechaInicial, DateTime? fechaFinal) async { final pedidosViewModel = Provider.of(context, listen: false); List pedidosConProductos = []; List propinas = []; List altPropinas = []; for (Pedido pedido in pedidosViewModel.pedidos) { Pedido? pedidoConProductos = await pedidosViewModel.fetchPedidoConProductos(pedido.id); if (pedidoConProductos != null) { pedidosConProductos.add(pedidoConProductos); } } if (pedidosConProductos.isNotEmpty) { String fileName = 'Ventas_Turquessa_POS'; if (fechaInicial != null && fechaFinal != null) { String startDateStr = DateFormat('dd-MM-yyyy').format(fechaInicial!); String endDateStr = DateFormat('dd-MM-yyyy').format(fechaFinal!); fileName += '_${startDateStr}_al_${endDateStr}'; } fileName += '.csv'; for (var pedido in pedidosConProductos) { altPropinas = await Provider.of(context, listen: false) .obtenerPropinasPorPedido(pedido.id); } for (var alt in altPropinas) { propinas.add(alt); } await exportarVentasACSV(pedidosConProductos, propinas, fileName); ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text('Archivo CSV descargado! Archivo: $fileName'))); } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('No hay pedidos para exportar.'))); } } Future imprimirResumenPedidos(List pedidos) async { if (fechaInicialSeleccionada == null) { print("No se ha seleccionado una fecha inicial."); return; } if (fechaFinalSeleccionada == null) { print("No se ha seleccionado una fecha final."); return; } await VentaTicket.imprimirResumenPedidos( pedidos, fechaInicialSeleccionada!); } String _formatDateTime(String? dateTimeString) { if (dateTimeString == null) return "Sin fecha"; DateTime parsedDate = DateTime.parse(dateTimeString); var formatter = DateFormat('dd-MM-yyyy HH:mm:ss'); return formatter.format(parsedDate.toLocal()); } double? _propinaPedido(int? idPedido) { double? propina = 0.0; for (var p in listaPropinas) { if (p.idPedido == idPedido) { propina = p.cantidad; } } return propina; } }