venta_screen.dart 11 KB

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