venta_screen.dart 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. import 'package:flutter/material.dart';
  2. import 'package:intl/intl.dart';
  3. import 'package:omni_datetime_picker/omni_datetime_picker.dart';
  4. import 'package:provider/provider.dart';
  5. import '../../widgets/widgets_components.dart';
  6. import '../../models/models.dart';
  7. import '../../viewmodels/viewmodels.dart';
  8. import 'venta_ticket.dart';
  9. import '../../widgets/widgets.dart';
  10. import '../../themes/themes.dart';
  11. class VentaScreen extends StatefulWidget {
  12. @override
  13. _VentaScreenState createState() => _VentaScreenState();
  14. }
  15. class _VentaScreenState extends State<VentaScreen> {
  16. DateTime? fechaSeleccionada;
  17. List<Pedido> pedidosNoCancelados = [];
  18. List<Pedido> pedidosCancelados = [];
  19. final _busqueda = TextEditingController(text: '');
  20. double totalDelDia = 0.0;
  21. double totalCancelados = 0.0;
  22. double totalEfectivoDelDia = 0.0;
  23. double totalTarjetaDelDia = 0.0;
  24. double totalTransferenciaDelDia = 0.0;
  25. double cambio = 0.0;
  26. double totalSinCambio = 0.0;
  27. String formatCurrency(double amount) {
  28. final format = NumberFormat("#,##0.00", "es_MX");
  29. return format.format(amount);
  30. }
  31. void clearSearchAndReset() {
  32. setState(() {
  33. _busqueda.clear();
  34. fechaSeleccionada = null;
  35. });
  36. }
  37. @override
  38. Widget build(BuildContext context) {
  39. return Scaffold(
  40. appBar: AppBar(
  41. title: Text(
  42. "Resumen de Pedidos por Día",
  43. style: TextStyle(color: AppTheme.secondary),
  44. ),
  45. iconTheme: IconThemeData(color: AppTheme.secondary)),
  46. body: Padding(
  47. padding: const EdgeInsets.all(16.0),
  48. child: Column(
  49. children: [
  50. Row(
  51. children: [
  52. Expanded(
  53. flex: 3,
  54. child: Padding(
  55. padding: const EdgeInsets.symmetric(horizontal: 0.0),
  56. child: tarjeta(
  57. ListTile(
  58. title: Text(
  59. "Fecha",
  60. style: TextStyle(
  61. color: AppTheme.quaternary,
  62. fontWeight: FontWeight.bold),
  63. ),
  64. subtitle: Text(
  65. fechaSeleccionada == null
  66. ? ""
  67. : DateFormat("dd/MM/yyyy")
  68. .format(fechaSeleccionada!),
  69. style: TextStyle(
  70. color: AppTheme.quaternary,
  71. fontWeight: FontWeight.bold),
  72. ),
  73. trailing: Icon(Icons.calendar_month,
  74. color: AppTheme.quaternary),
  75. onTap: () async {
  76. DateTime? d = await showDatetimePicker(
  77. context, fechaSeleccionada,
  78. inicia: fechaSeleccionada,
  79. tipo: OmniDateTimePickerType.date,
  80. solofecha: true);
  81. if (d == null) return;
  82. setState(() {
  83. fechaSeleccionada = d;
  84. });
  85. cargarPedidos(fechaSeleccionada!);
  86. }),
  87. color: AppTheme.tertiary,
  88. ),
  89. )),
  90. const SizedBox(
  91. width: 500,
  92. ),
  93. Expanded(
  94. flex: 2,
  95. child: Padding(
  96. padding: const EdgeInsets.only(top: 0),
  97. child: ElevatedButton(
  98. onPressed: clearSearchAndReset,
  99. style: ElevatedButton.styleFrom(
  100. shape: RoundedRectangleBorder(
  101. borderRadius: BorderRadius.circular(20.0),
  102. ),
  103. primary: AppTheme.tertiary,
  104. padding: const EdgeInsets.symmetric(vertical: 25),
  105. ),
  106. child: Text('Limpiar',
  107. style: TextStyle(
  108. color: AppTheme.quaternary, fontSize: 18)),
  109. ),
  110. ),
  111. ),
  112. ],
  113. ),
  114. Expanded(
  115. child: tarjeta(
  116. Padding(
  117. padding: const EdgeInsets.all(8.0),
  118. child: ListView.builder(
  119. itemCount:
  120. pedidosNoCancelados.length + pedidosCancelados.length,
  121. itemBuilder: (context, index) {
  122. if (index < pedidosNoCancelados.length) {
  123. final pedido = pedidosNoCancelados[index];
  124. return Row(
  125. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  126. children: [
  127. Text(
  128. "Folio: ${pedido.folio}",
  129. style: TextStyle(
  130. fontSize: 20, fontWeight: FontWeight.w500),
  131. ),
  132. Text(
  133. "Total: \$${formatCurrency(pedido.totalPedido ?? 0)}",
  134. style: TextStyle(
  135. fontSize: 20, fontWeight: FontWeight.w500)),
  136. ],
  137. );
  138. } else {
  139. final pedido =
  140. pedidosCancelados[index - pedidosNoCancelados.length];
  141. return Row(
  142. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  143. children: [
  144. Text(
  145. "Folio: ${pedido.folio} (Cancelado)",
  146. style: TextStyle(
  147. fontSize: 20,
  148. fontWeight: FontWeight.w500,
  149. color: Colors.red),
  150. ),
  151. Text(
  152. "Total: \$${formatCurrency(pedido.totalPedido ?? 0)}",
  153. style: TextStyle(
  154. fontSize: 20,
  155. fontWeight: FontWeight.w500,
  156. color: Colors.red)),
  157. ],
  158. );
  159. }
  160. },
  161. ),
  162. ),
  163. )),
  164. Row(
  165. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  166. children: [
  167. ElevatedButton.icon(
  168. icon: Icon(
  169. Icons.receipt_long_outlined,
  170. color: AppTheme.quaternary,
  171. size: 30,
  172. ),
  173. onPressed: pedidosNoCancelados.isNotEmpty ||
  174. pedidosCancelados.isNotEmpty
  175. ? () => imprimirResumenPedidos(
  176. pedidosNoCancelados + pedidosCancelados)
  177. : null,
  178. label: Text(
  179. "Imprimir Resumen",
  180. style: TextStyle(color: AppTheme.quaternary, fontSize: 18),
  181. ),
  182. style: ButtonStyle(
  183. backgroundColor:
  184. MaterialStatePropertyAll(AppTheme.tertiary),
  185. padding: MaterialStatePropertyAll(
  186. EdgeInsets.fromLTRB(30, 20, 30, 20))),
  187. ),
  188. Column(
  189. crossAxisAlignment: CrossAxisAlignment.end,
  190. children: [
  191. Padding(
  192. padding: const EdgeInsets.all(16.0),
  193. child: Text(
  194. "Total del día: \$${formatCurrency(totalDelDia)}",
  195. style: TextStyle(
  196. fontSize: 20, fontWeight: FontWeight.bold),
  197. ),
  198. ),
  199. Row(
  200. children: [
  201. if (totalTarjetaDelDia > 0)
  202. Padding(
  203. padding: const EdgeInsets.all(16.0),
  204. child: Text(
  205. "Total en Tarjeta: \$${formatCurrency(totalTarjetaDelDia)}",
  206. style: TextStyle(
  207. fontSize: 20, fontWeight: FontWeight.bold),
  208. ),
  209. ),
  210. if (totalTransferenciaDelDia > 0)
  211. Padding(
  212. padding: const EdgeInsets.all(16.0),
  213. child: Text(
  214. "Total en Transferencia: \$${formatCurrency(totalTransferenciaDelDia)}",
  215. style: TextStyle(
  216. fontSize: 20, fontWeight: FontWeight.bold),
  217. ),
  218. ),
  219. if (totalEfectivoDelDia > 0)
  220. Padding(
  221. padding: const EdgeInsets.all(16.0),
  222. child: Text(
  223. "Total en Efectivo: \$${formatCurrency(totalEfectivoDelDia)}",
  224. style: TextStyle(
  225. fontSize: 20, fontWeight: FontWeight.bold),
  226. ),
  227. ),
  228. if (cambio > 0)
  229. Padding(
  230. padding: const EdgeInsets.all(16.0),
  231. child: Text(
  232. "Cambio Entregado: \$${formatCurrency(cambio)}",
  233. style: TextStyle(
  234. fontSize: 20, fontWeight: FontWeight.bold),
  235. ),
  236. ),
  237. ],
  238. ),
  239. if (totalCancelados > 0)
  240. Padding(
  241. padding: const EdgeInsets.all(16.0),
  242. child: Text(
  243. "Total cancelados: \$${formatCurrency(totalCancelados)}",
  244. style: TextStyle(
  245. fontSize: 20,
  246. fontWeight: FontWeight.bold,
  247. color: Colors.red),
  248. ),
  249. ),
  250. ],
  251. ),
  252. ],
  253. )
  254. ],
  255. ),
  256. ),
  257. );
  258. }
  259. void cargarPedidos(DateTime fecha) async {
  260. // Convertir el inicio y fin del día local a UTC
  261. final inicioDelDia = DateTime(fecha.year, fecha.month, fecha.day)
  262. .toUtc(); // Convierte la fecha local de inicio del día a UTC
  263. final finDelDia = DateTime(fecha.year, fecha.month, fecha.day, 23, 59, 59)
  264. .toUtc(); // Convierte la fecha local de fin del día a UTC
  265. print('Buscando pedidos desde: $inicioDelDia hasta: $finDelDia (en UTC)');
  266. // Realizar la búsqueda en UTC
  267. final pedidos = await Provider.of<PedidoViewModel>(context, listen: false)
  268. .buscarPorFecha(inicioDelDia, finDelDia);
  269. print('Pedidos obtenidos: ${pedidos.length}');
  270. pedidos.forEach((pedido) => print(
  271. 'Pedido: ${pedido.folio}, Total: ${pedido.totalPedido}, Estatus: ${pedido.estatus}'));
  272. final pedidosNoCancelados =
  273. pedidos.where((p) => p.estatus != "CANCELADO").toList();
  274. final pedidosCancelados =
  275. pedidos.where((p) => p.estatus == "CANCELADO").toList();
  276. totalDelDia = 0.0;
  277. totalCancelados = 0.0;
  278. totalEfectivoDelDia = 0.0;
  279. totalTarjetaDelDia = 0.0;
  280. totalTransferenciaDelDia = 0.0;
  281. cambio = 0.0;
  282. totalSinCambio = 0.0;
  283. for (var pedido in pedidosNoCancelados) {
  284. totalDelDia += pedido.totalPedido ?? 0.0;
  285. totalEfectivoDelDia += pedido.cantEfectivo ?? 0.0;
  286. totalTarjetaDelDia += pedido.cantTarjeta ?? 0.0;
  287. totalTransferenciaDelDia += pedido.cantTransferencia ?? 0.0;
  288. totalSinCambio =
  289. totalEfectivoDelDia + totalTarjetaDelDia + totalTransferenciaDelDia;
  290. cambio = totalSinCambio - totalDelDia;
  291. }
  292. print("Total del dia sin cambios $totalSinCambio");
  293. print("Cambio $cambio");
  294. totalCancelados = pedidosCancelados.fold(
  295. 0.0, (sum, current) => sum + (current.totalPedido ?? 0.0));
  296. setState(() {
  297. this.pedidosNoCancelados = pedidosNoCancelados;
  298. this.pedidosCancelados = pedidosCancelados;
  299. });
  300. }
  301. Future<void> imprimirResumenPedidos(List<Pedido> pedidos) async {
  302. if (fechaSeleccionada == null) {
  303. print("No se ha seleccionado una fecha.");
  304. return;
  305. }
  306. await VentaTicket.imprimirResumenPedidos(pedidos, fechaSeleccionada!);
  307. }
  308. }