pedido_detalle_screen.dart 13 KB

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