venta_screen.dart 13 KB

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