pedido_detalle_screen.dart 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. import 'package:intl/intl.dart';
  2. import 'package:flutter/material.dart';
  3. import '../../models/models.dart';
  4. import '../../themes/themes.dart';
  5. import '../pedido/pedido_ticket.dart';
  6. class PedidoDetalleScreen extends StatelessWidget {
  7. final Pedido pedido;
  8. const PedidoDetalleScreen({Key? key, required this.pedido}) : super(key: key);
  9. String formatCurrency(double amount) {
  10. final format = NumberFormat("#,##0.00", "es_MX");
  11. return format.format(amount);
  12. }
  13. @override
  14. Widget build(BuildContext context) {
  15. double totalSinDescuento =
  16. pedido.productos.fold(0, (previousValue, element) {
  17. double productTotal =
  18. element.cantidad! * (element.producto?.precio ?? 0.0);
  19. double toppingsTotal = element.toppings.fold(0, (toppingTotal, topping) {
  20. return toppingTotal +
  21. (topping.topping?.precio ?? 0.0) * element.cantidad!;
  22. });
  23. return previousValue + productTotal + toppingsTotal;
  24. });
  25. double descuento = pedido.descuento?.toDouble() ?? 0.0;
  26. double precioDescuento = totalSinDescuento * (descuento / 100);
  27. double totalConDescuento = totalSinDescuento - precioDescuento;
  28. return Scaffold(
  29. appBar: AppBar(
  30. title: Text(
  31. 'Detalle del Pedido ${pedido.folio}',
  32. style: TextStyle(fontWeight: FontWeight.w500),
  33. ),
  34. ),
  35. body: SingleChildScrollView(
  36. padding: const EdgeInsets.all(12.0),
  37. child: Column(
  38. children: [
  39. Card(
  40. elevation: 4,
  41. color: Colors.white,
  42. child: Column(
  43. children: [
  44. ListTile(
  45. title: Text(
  46. 'Cliente: ${pedido.nombreCliente}',
  47. style:
  48. TextStyle(fontWeight: FontWeight.bold, fontSize: 22),
  49. ),
  50. subtitle: Text(
  51. 'Comentarios: ${pedido.comentarios}',
  52. style:
  53. TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
  54. ),
  55. ),
  56. ListTile(
  57. title: Text(
  58. 'Estado del Pedido: ${pedido.estatus}',
  59. style: TextStyle(
  60. fontSize: 22,
  61. fontWeight: FontWeight.bold,
  62. ),
  63. ),
  64. )
  65. ],
  66. ),
  67. ),
  68. SizedBox(height: 10),
  69. Card(
  70. elevation: 4,
  71. color: Colors.white,
  72. child: Padding(
  73. padding: const EdgeInsets.all(8.0),
  74. child: Column(
  75. crossAxisAlignment: CrossAxisAlignment.start,
  76. children: [
  77. Text('Productos',
  78. style: TextStyle(
  79. fontSize: 22, fontWeight: FontWeight.bold)),
  80. const SizedBox(height: 15),
  81. ListView.builder(
  82. shrinkWrap: true,
  83. physics: NeverScrollableScrollPhysics(),
  84. itemCount: pedido.productos.length,
  85. itemBuilder: (context, index) {
  86. final producto = pedido.productos[index];
  87. return Padding(
  88. padding: const EdgeInsets.symmetric(vertical: 4.0),
  89. child: Column(
  90. crossAxisAlignment: CrossAxisAlignment.start,
  91. children: [
  92. Row(
  93. children: [
  94. Expanded(
  95. flex: 6,
  96. child: Text(
  97. producto.producto?.nombre ??
  98. "Producto no especificado",
  99. style: TextStyle(
  100. fontWeight: FontWeight.bold,
  101. fontSize: 17),
  102. overflow: TextOverflow.ellipsis,
  103. ),
  104. ),
  105. Expanded(
  106. flex: 1,
  107. child: Text(
  108. 'x${producto.cantidad}',
  109. style: TextStyle(
  110. fontWeight: FontWeight.w500,
  111. fontSize: 17),
  112. textAlign: TextAlign.center,
  113. ),
  114. ),
  115. Expanded(
  116. flex: 2,
  117. child: Text(
  118. '\$${formatCurrency(producto.producto?.precio ?? 0.0)}',
  119. style: TextStyle(
  120. fontWeight: FontWeight.w500,
  121. fontSize: 17),
  122. textAlign: TextAlign.right,
  123. ),
  124. ),
  125. ],
  126. ),
  127. if (producto.toppings.isNotEmpty)
  128. Padding(
  129. padding: const EdgeInsets.only(top: 4.0),
  130. child: Column(
  131. crossAxisAlignment:
  132. CrossAxisAlignment.start,
  133. children: producto.toppings.map((topping) {
  134. return Padding(
  135. padding: const EdgeInsets.symmetric(
  136. vertical: 2.0),
  137. child: Row(
  138. children: [
  139. Text(
  140. '- ${topping.topping?.nombre ?? "Topping no especificado"}',
  141. style: TextStyle(
  142. fontSize: 15,
  143. color: Colors.grey[600]),
  144. ),
  145. Spacer(),
  146. Text(
  147. '\$${formatCurrency(topping.topping?.precio ?? 0.0)}',
  148. style: TextStyle(
  149. fontSize: 15,
  150. color: Colors.grey[600]),
  151. ),
  152. ],
  153. ),
  154. );
  155. }).toList(),
  156. ),
  157. ),
  158. ],
  159. ),
  160. );
  161. },
  162. ),
  163. Divider(),
  164. Padding(
  165. padding: const EdgeInsets.symmetric(vertical: 8.0),
  166. child: Column(
  167. crossAxisAlignment: CrossAxisAlignment.end,
  168. children: [
  169. Row(
  170. mainAxisAlignment: MainAxisAlignment.end,
  171. children: [
  172. const Text('Subtotal:',
  173. style: TextStyle(
  174. fontSize: 16,
  175. fontWeight: FontWeight.bold)),
  176. const SizedBox(width: 5),
  177. Text('\$${formatCurrency(totalSinDescuento)}',
  178. style: const TextStyle(
  179. fontSize: 16,
  180. fontWeight: FontWeight.bold)),
  181. ],
  182. ),
  183. if (descuento > 0) ...[
  184. Row(
  185. mainAxisAlignment: MainAxisAlignment.end,
  186. children: [
  187. Text(
  188. 'Descuento (${descuento.toStringAsFixed(0)}%):',
  189. style: const TextStyle(
  190. fontSize: 16,
  191. fontWeight: FontWeight.bold)),
  192. const SizedBox(width: 8),
  193. Text('-\$${formatCurrency(precioDescuento)}',
  194. style: const TextStyle(
  195. fontSize: 16,
  196. fontWeight: FontWeight.bold)),
  197. ],
  198. ),
  199. ],
  200. Row(
  201. mainAxisAlignment: MainAxisAlignment.end,
  202. children: [
  203. const Text('Total:',
  204. style: TextStyle(
  205. fontSize: 16,
  206. fontWeight: FontWeight.bold)),
  207. const SizedBox(width: 5),
  208. Text('\$${formatCurrency(totalConDescuento)}',
  209. style: const TextStyle(
  210. fontSize: 16,
  211. fontWeight: FontWeight.bold)),
  212. ],
  213. ),
  214. ],
  215. ),
  216. ),
  217. ],
  218. ),
  219. ),
  220. ),
  221. const SizedBox(height: 10),
  222. Card(
  223. elevation: 4,
  224. color: Colors.white,
  225. child: Padding(
  226. padding: const EdgeInsets.all(8.0),
  227. child: Column(
  228. crossAxisAlignment: CrossAxisAlignment.start,
  229. children: [
  230. Text('Pago',
  231. style: TextStyle(
  232. fontSize: 22, fontWeight: FontWeight.bold)),
  233. const SizedBox(height: 10),
  234. _buildPaymentDetails(),
  235. ],
  236. ),
  237. ),
  238. ),
  239. const SizedBox(height: 20),
  240. Align(
  241. alignment: Alignment.centerLeft,
  242. child: ElevatedButton.icon(
  243. icon: Icon(
  244. Icons.receipt_long_outlined,
  245. color: AppTheme.quaternary,
  246. size: 30,
  247. ),
  248. onPressed: () => imprimirTicketsJuntos(context, pedido),
  249. label: Text(
  250. 'Imprimir Ticket',
  251. style: TextStyle(
  252. fontWeight: FontWeight.w500,
  253. fontSize: 18,
  254. color: AppTheme.quaternary),
  255. ),
  256. style: ElevatedButton.styleFrom(
  257. padding: const EdgeInsets.fromLTRB(50, 20, 50, 20),
  258. backgroundColor: AppTheme.tertiary,
  259. ),
  260. ),
  261. )
  262. ],
  263. ),
  264. ),
  265. );
  266. }
  267. Widget _buildPaymentDetails() {
  268. List<Widget> paymentDetails = [];
  269. if (pedido.cantEfectivo != null && pedido.cantEfectivo! > 0) {
  270. paymentDetails.add(_buildPaymentRow("Efectivo", pedido.cantEfectivo!));
  271. }
  272. if (pedido.cantTarjeta != null && pedido.cantTarjeta! > 0) {
  273. paymentDetails.add(_buildPaymentRow("Tarjeta", pedido.cantTarjeta!));
  274. }
  275. if (pedido.cantTransferencia != null && pedido.cantTransferencia! > 0) {
  276. paymentDetails
  277. .add(_buildPaymentRow("Transferencia", pedido.cantTransferencia!));
  278. }
  279. if (paymentDetails.isEmpty) {
  280. paymentDetails.add(Text("No se especificaron métodos de pago.",
  281. style: TextStyle(fontSize: 16, color: Colors.grey[600])));
  282. }
  283. return Column(
  284. crossAxisAlignment: CrossAxisAlignment.start,
  285. children: paymentDetails,
  286. );
  287. }
  288. Widget _buildPaymentRow(String paymentType, double amount) {
  289. return Row(
  290. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  291. children: [
  292. Text(
  293. paymentType,
  294. style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
  295. ),
  296. Text(
  297. '\$${formatCurrency(amount)}',
  298. style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
  299. ),
  300. ],
  301. );
  302. }
  303. }