pedido_detalle_screen.dart 14 KB

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