|
@@ -1,19 +1,39 @@
|
|
|
|
+import 'package:collection/collection.dart';
|
|
import 'package:intl/intl.dart';
|
|
import 'package:intl/intl.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/material.dart';
|
|
|
|
+import 'package:provider/provider.dart';
|
|
import '../../models/models.dart';
|
|
import '../../models/models.dart';
|
|
|
|
+import '../../services/services.dart';
|
|
import '../../themes/themes.dart';
|
|
import '../../themes/themes.dart';
|
|
|
|
+import '../../viewmodels/viewmodels.dart';
|
|
|
|
+import '../../widgets/widgets.dart';
|
|
import '../pedido/pedido_ticket.dart';
|
|
import '../pedido/pedido_ticket.dart';
|
|
|
|
|
|
-class PedidoDetalleScreen extends StatelessWidget {
|
|
|
|
|
|
+class PedidoDetalleScreen extends StatefulWidget {
|
|
final Pedido pedido;
|
|
final Pedido pedido;
|
|
|
|
|
|
- const PedidoDetalleScreen({Key? key, required this.pedido}) : super(key: key);
|
|
|
|
|
|
+ PedidoDetalleScreen({Key? key, required this.pedido}) : super(key: key);
|
|
|
|
+
|
|
|
|
+ @override
|
|
|
|
+ _PedidoDetalleScreenState createState() => _PedidoDetalleScreenState();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+class _PedidoDetalleScreenState extends State<PedidoDetalleScreen> {
|
|
|
|
+ late Pedido pedido;
|
|
|
|
+
|
|
|
|
+ @override
|
|
|
|
+ void initState() {
|
|
|
|
+ super.initState();
|
|
|
|
+ pedido = widget.pedido;
|
|
|
|
+ }
|
|
|
|
|
|
String formatCurrency(double amount) {
|
|
String formatCurrency(double amount) {
|
|
final format = NumberFormat("#,##0.00", "es_MX");
|
|
final format = NumberFormat("#,##0.00", "es_MX");
|
|
return format.format(amount);
|
|
return format.format(amount);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ final List<String> tiposDePago = ['Efectivo', 'Tarjeta', 'Transferencia'];
|
|
|
|
+
|
|
@override
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
Widget build(BuildContext context) {
|
|
double totalSinDescuento =
|
|
double totalSinDescuento =
|
|
@@ -33,6 +53,14 @@ class PedidoDetalleScreen extends StatelessWidget {
|
|
double precioDescuento = totalSinDescuento * (descuento / 100);
|
|
double precioDescuento = totalSinDescuento * (descuento / 100);
|
|
double totalConDescuento = totalSinDescuento - precioDescuento;
|
|
double totalConDescuento = totalSinDescuento - precioDescuento;
|
|
|
|
|
|
|
|
+ double totalPropina = 0.0;
|
|
|
|
+ if (pedido.propinas.isNotEmpty) {
|
|
|
|
+ totalPropina = pedido.propinas.fold(
|
|
|
|
+ 0.0,
|
|
|
|
+ (previousValue, propina) => previousValue + (propina.cantidad ?? 0.0),
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
return Scaffold(
|
|
return Scaffold(
|
|
appBar: AppBar(
|
|
appBar: AppBar(
|
|
title: Text(
|
|
title: Text(
|
|
@@ -145,6 +173,12 @@ class PedidoDetalleScreen extends StatelessWidget {
|
|
),
|
|
),
|
|
],
|
|
],
|
|
),
|
|
),
|
|
|
|
+ if (producto.comentario!.isNotEmpty)
|
|
|
|
+ Text(
|
|
|
|
+ 'Comentarios: ${producto.comentario!}',
|
|
|
|
+ style: TextStyle(
|
|
|
|
+ fontSize: 15, color: AppTheme.tertiary),
|
|
|
|
+ ),
|
|
if (producto.toppings.isNotEmpty)
|
|
if (producto.toppings.isNotEmpty)
|
|
Padding(
|
|
Padding(
|
|
padding: const EdgeInsets.only(top: 4.0),
|
|
padding: const EdgeInsets.only(top: 4.0),
|
|
@@ -232,6 +266,27 @@ class PedidoDetalleScreen extends StatelessWidget {
|
|
fontWeight: FontWeight.bold)),
|
|
fontWeight: FontWeight.bold)),
|
|
],
|
|
],
|
|
),
|
|
),
|
|
|
|
+ if (pedido.propinas.isNotEmpty) ...[
|
|
|
|
+ const Divider(),
|
|
|
|
+ Row(
|
|
|
|
+ mainAxisAlignment: MainAxisAlignment.end,
|
|
|
|
+ children: [
|
|
|
|
+ const Text(
|
|
|
|
+ 'Propina:',
|
|
|
|
+ style: TextStyle(
|
|
|
|
+ fontSize: 16,
|
|
|
|
+ fontWeight: FontWeight.bold),
|
|
|
|
+ ),
|
|
|
|
+ const SizedBox(width: 5),
|
|
|
|
+ Text(
|
|
|
|
+ '\$${formatCurrency(totalPropina)}',
|
|
|
|
+ style: const TextStyle(
|
|
|
|
+ fontSize: 16,
|
|
|
|
+ fontWeight: FontWeight.bold),
|
|
|
|
+ ),
|
|
|
|
+ ],
|
|
|
|
+ ),
|
|
|
|
+ ],
|
|
],
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
@@ -245,15 +300,47 @@ class PedidoDetalleScreen extends StatelessWidget {
|
|
color: Colors.white,
|
|
color: Colors.white,
|
|
child: Padding(
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
padding: const EdgeInsets.all(8.0),
|
|
- child: Column(
|
|
|
|
- crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
- children: [
|
|
|
|
- Text('Pago',
|
|
|
|
- style: TextStyle(
|
|
|
|
- fontSize: 22, fontWeight: FontWeight.bold)),
|
|
|
|
- const SizedBox(height: 10),
|
|
|
|
- _buildPaymentDetails(),
|
|
|
|
- ],
|
|
|
|
|
|
+ child: Consumer<PedidoViewModel>(
|
|
|
|
+ builder: (context, viewModel, _) {
|
|
|
|
+ return Column(
|
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
+ children: [
|
|
|
|
+ Row(
|
|
|
|
+ children: [
|
|
|
|
+ Text('Pago',
|
|
|
|
+ style: TextStyle(
|
|
|
|
+ fontSize: 22, fontWeight: FontWeight.bold)),
|
|
|
|
+ Spacer(),
|
|
|
|
+ ElevatedButton(
|
|
|
|
+ onPressed: () {
|
|
|
|
+ _mostrarModalCambiarMetodoPago(context);
|
|
|
|
+ },
|
|
|
|
+ child: Text('Cambiar Método Pago',
|
|
|
|
+ style: TextStyle(
|
|
|
|
+ color: AppTheme.quaternary,
|
|
|
|
+ fontWeight: FontWeight.w500,
|
|
|
|
+ fontSize: 16)),
|
|
|
|
+ style: ElevatedButton.styleFrom(
|
|
|
|
+ backgroundColor: AppTheme.tertiary,
|
|
|
|
+ padding:
|
|
|
|
+ const EdgeInsets.fromLTRB(20, 10, 20, 10),
|
|
|
|
+ ),
|
|
|
|
+ ),
|
|
|
|
+ ],
|
|
|
|
+ ),
|
|
|
|
+ const SizedBox(height: 10),
|
|
|
|
+ if ((pedido.cantEfectivo ?? 0) > 0)
|
|
|
|
+ _buildReadOnlyPaymentRow(
|
|
|
|
+ "Efectivo", pedido.cantEfectivo ?? 0.0),
|
|
|
|
+ if ((pedido.cantTarjeta ?? 0) > 0)
|
|
|
|
+ _buildReadOnlyPaymentRow(
|
|
|
|
+ "Tarjeta", pedido.cantTarjeta ?? 0.0),
|
|
|
|
+ if ((pedido.cantTransferencia ?? 0) > 0)
|
|
|
|
+ _buildReadOnlyPaymentRow(
|
|
|
|
+ "Transferencia", pedido.cantTransferencia ?? 0.0),
|
|
|
|
+ ],
|
|
|
|
+ );
|
|
|
|
+ },
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
@@ -276,7 +363,7 @@ class PedidoDetalleScreen extends StatelessWidget {
|
|
),
|
|
),
|
|
style: ElevatedButton.styleFrom(
|
|
style: ElevatedButton.styleFrom(
|
|
padding: const EdgeInsets.fromLTRB(50, 20, 50, 20),
|
|
padding: const EdgeInsets.fromLTRB(50, 20, 50, 20),
|
|
- primary: AppTheme.tertiary,
|
|
|
|
|
|
+ backgroundColor: AppTheme.tertiary,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
)
|
|
)
|
|
@@ -286,41 +373,409 @@ class PedidoDetalleScreen extends StatelessWidget {
|
|
);
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
- Widget _buildPaymentDetails() {
|
|
|
|
- List<Widget> paymentDetails = [];
|
|
|
|
|
|
+ Widget _buildReadOnlyPaymentRow(String paymentType, double amount) {
|
|
|
|
+ return Padding(
|
|
|
|
+ padding: const EdgeInsets.symmetric(vertical: 6.0),
|
|
|
|
+ child: Row(
|
|
|
|
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
|
+ children: [
|
|
|
|
+ Text(paymentType,
|
|
|
|
+ style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
|
|
|
+ Text('\$${formatCurrency(amount)}',
|
|
|
|
+ style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
|
|
|
+ ],
|
|
|
|
+ ),
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Future<void> _mostrarModalCambiarMetodoPago(BuildContext context) async {
|
|
|
|
+ double totalPedido = pedido.totalPedido ?? 0.0;
|
|
|
|
+ TextEditingController efectivoController = TextEditingController(
|
|
|
|
+ text: (pedido.cantEfectivo ?? 0) > 0
|
|
|
|
+ ? pedido.cantEfectivo!.toStringAsFixed(2)
|
|
|
|
+ : '');
|
|
|
|
+ TextEditingController tarjetaController = TextEditingController(
|
|
|
|
+ text: (pedido.cantTarjeta ?? 0) > 0
|
|
|
|
+ ? pedido.cantTarjeta!.toStringAsFixed(2)
|
|
|
|
+ : '');
|
|
|
|
+ TextEditingController transferenciaController = TextEditingController(
|
|
|
|
+ text: (pedido.cantTransferencia ?? 0) > 0
|
|
|
|
+ ? pedido.cantTransferencia!.toStringAsFixed(2)
|
|
|
|
+ : '');
|
|
|
|
|
|
- if (pedido.cantEfectivo != null && pedido.cantEfectivo! > 0) {
|
|
|
|
- paymentDetails.add(_buildPaymentRow("Efectivo", pedido.cantEfectivo!));
|
|
|
|
- }
|
|
|
|
- if (pedido.cantTarjeta != null && pedido.cantTarjeta! > 0) {
|
|
|
|
- paymentDetails.add(_buildPaymentRow("Tarjeta", pedido.cantTarjeta!));
|
|
|
|
- }
|
|
|
|
- if (pedido.cantTransferencia != null && pedido.cantTransferencia! > 0) {
|
|
|
|
- paymentDetails
|
|
|
|
- .add(_buildPaymentRow("Transferencia", pedido.cantTransferencia!));
|
|
|
|
- }
|
|
|
|
- if (paymentDetails.isEmpty) {
|
|
|
|
- paymentDetails.add(Text("No se especificaron métodos de pago.",
|
|
|
|
- style: TextStyle(fontSize: 16, color: Colors.grey[600])));
|
|
|
|
|
|
+ bool efectivoSeleccionado = (pedido.cantEfectivo ?? 0) > 0;
|
|
|
|
+ bool tarjetaSeleccionada = (pedido.cantTarjeta ?? 0) > 0;
|
|
|
|
+ bool transferenciaSeleccionada = (pedido.cantTransferencia ?? 0) > 0;
|
|
|
|
+
|
|
|
|
+ bool efectivoCompleto = false;
|
|
|
|
+ bool tarjetaCompleto = false;
|
|
|
|
+ bool transferenciaCompleto = false;
|
|
|
|
+
|
|
|
|
+ double cambio = 0.0;
|
|
|
|
+ double faltante = totalPedido;
|
|
|
|
+ bool totalCompletado = false;
|
|
|
|
+
|
|
|
|
+ void _calcularCambio(StateSetter setState) {
|
|
|
|
+ double totalPagado = (double.tryParse(efectivoController.text) ?? 0) +
|
|
|
|
+ (double.tryParse(tarjetaController.text) ?? 0) +
|
|
|
|
+ (double.tryParse(transferenciaController.text) ?? 0);
|
|
|
|
+
|
|
|
|
+ setState(() {
|
|
|
|
+ cambio = totalPagado - totalPedido;
|
|
|
|
+ faltante = cambio < 0 ? totalPedido - totalPagado : 0;
|
|
|
|
+ totalCompletado = cambio >= 0;
|
|
|
|
+ });
|
|
}
|
|
}
|
|
|
|
|
|
- return Column(
|
|
|
|
- crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
- children: paymentDetails,
|
|
|
|
|
|
+ bool? shouldSave = await showDialog<bool>(
|
|
|
|
+ context: context,
|
|
|
|
+ builder: (BuildContext context) {
|
|
|
|
+ return StatefulBuilder(
|
|
|
|
+ builder: (context, setState) {
|
|
|
|
+ return AlertDialog(
|
|
|
|
+ actionsPadding: EdgeInsets.fromLTRB(50, 10, 50, 30),
|
|
|
|
+ title: const Text(
|
|
|
|
+ 'Cambiar Método de Pago',
|
|
|
|
+ style: TextStyle(fontSize: 22, fontWeight: FontWeight.w500),
|
|
|
|
+ ),
|
|
|
|
+ content: SingleChildScrollView(
|
|
|
|
+ child: AnimatedSize(
|
|
|
|
+ duration: const Duration(milliseconds: 300),
|
|
|
|
+ curve: Curves.easeInOut,
|
|
|
|
+ child: Column(
|
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
|
|
+ children: [
|
|
|
|
+ Align(
|
|
|
|
+ alignment: Alignment.center,
|
|
|
|
+ child: Text(
|
|
|
|
+ 'Métodos de pago',
|
|
|
|
+ style: TextStyle(
|
|
|
|
+ fontWeight: FontWeight.bold, fontSize: 20),
|
|
|
|
+ ),
|
|
|
|
+ ),
|
|
|
|
+ const SizedBox(height: 10),
|
|
|
|
+ _buildPaymentMethodRow(
|
|
|
|
+ setState,
|
|
|
|
+ totalPedido,
|
|
|
|
+ label: 'Efectivo',
|
|
|
|
+ selected: efectivoSeleccionado,
|
|
|
|
+ exactSelected: efectivoCompleto,
|
|
|
|
+ controller: efectivoController,
|
|
|
|
+ onSelected: (value) {
|
|
|
|
+ setState(() {
|
|
|
|
+ efectivoSeleccionado = value;
|
|
|
|
+ if (!efectivoSeleccionado) {
|
|
|
|
+ efectivoCompleto = false;
|
|
|
|
+ efectivoController.clear();
|
|
|
|
+ }
|
|
|
|
+ _calcularCambio(setState);
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ onExactSelected: (value) {
|
|
|
|
+ setState(() {
|
|
|
|
+ efectivoCompleto = value;
|
|
|
|
+ if (efectivoCompleto) {
|
|
|
|
+ efectivoController.text =
|
|
|
|
+ totalPedido.toStringAsFixed(2);
|
|
|
|
+ efectivoSeleccionado = true;
|
|
|
|
+ tarjetaSeleccionada = false;
|
|
|
|
+ transferenciaSeleccionada = false;
|
|
|
|
+ tarjetaController.clear();
|
|
|
|
+ transferenciaController.clear();
|
|
|
|
+ } else {
|
|
|
|
+ efectivoController.clear();
|
|
|
|
+ }
|
|
|
|
+ _calcularCambio(setState);
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ disableOtherMethods:
|
|
|
|
+ tarjetaCompleto || transferenciaCompleto,
|
|
|
|
+ onChangedMonto: () => _calcularCambio(setState),
|
|
|
|
+ ),
|
|
|
|
+ _buildPaymentMethodRow(
|
|
|
|
+ setState,
|
|
|
|
+ totalPedido,
|
|
|
|
+ label: 'Tarjeta',
|
|
|
|
+ selected: tarjetaSeleccionada,
|
|
|
|
+ exactSelected: tarjetaCompleto,
|
|
|
|
+ controller: tarjetaController,
|
|
|
|
+ sinCambio: true,
|
|
|
|
+ onSelected: (value) {
|
|
|
|
+ setState(() {
|
|
|
|
+ tarjetaSeleccionada = value;
|
|
|
|
+ if (!tarjetaSeleccionada) {
|
|
|
|
+ tarjetaCompleto = false;
|
|
|
|
+ tarjetaController.clear();
|
|
|
|
+ }
|
|
|
|
+ _calcularCambio(setState);
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ onExactSelected: (value) {
|
|
|
|
+ setState(() {
|
|
|
|
+ tarjetaCompleto = value;
|
|
|
|
+ if (tarjetaCompleto) {
|
|
|
|
+ tarjetaController.text =
|
|
|
|
+ totalPedido.toStringAsFixed(2);
|
|
|
|
+ tarjetaSeleccionada = true;
|
|
|
|
+ efectivoSeleccionado = false;
|
|
|
|
+ transferenciaSeleccionada = false;
|
|
|
|
+ efectivoController.clear();
|
|
|
|
+ transferenciaController.clear();
|
|
|
|
+ } else {
|
|
|
|
+ tarjetaController.clear();
|
|
|
|
+ }
|
|
|
|
+ _calcularCambio(setState);
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ disableOtherMethods:
|
|
|
|
+ efectivoCompleto || transferenciaCompleto,
|
|
|
|
+ onChangedMonto: () => _calcularCambio(setState),
|
|
|
|
+ ),
|
|
|
|
+ _buildPaymentMethodRow(
|
|
|
|
+ setState,
|
|
|
|
+ totalPedido,
|
|
|
|
+ label: 'Transferencia',
|
|
|
|
+ selected: transferenciaSeleccionada,
|
|
|
|
+ exactSelected: transferenciaCompleto,
|
|
|
|
+ controller: transferenciaController,
|
|
|
|
+ sinCambio: true,
|
|
|
|
+ onSelected: (value) {
|
|
|
|
+ setState(() {
|
|
|
|
+ transferenciaSeleccionada = value;
|
|
|
|
+ if (!transferenciaSeleccionada) {
|
|
|
|
+ transferenciaCompleto = false;
|
|
|
|
+ transferenciaController.clear();
|
|
|
|
+ }
|
|
|
|
+ _calcularCambio(setState);
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ onExactSelected: (value) {
|
|
|
|
+ setState(() {
|
|
|
|
+ transferenciaCompleto = value;
|
|
|
|
+ if (transferenciaCompleto) {
|
|
|
|
+ transferenciaController.text =
|
|
|
|
+ totalPedido.toStringAsFixed(2);
|
|
|
|
+ transferenciaSeleccionada = true;
|
|
|
|
+ efectivoSeleccionado = false;
|
|
|
|
+ tarjetaSeleccionada = false;
|
|
|
|
+ efectivoController.clear();
|
|
|
|
+ tarjetaController.clear();
|
|
|
|
+ } else {
|
|
|
|
+ transferenciaController.clear();
|
|
|
|
+ }
|
|
|
|
+ _calcularCambio(setState);
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ disableOtherMethods:
|
|
|
|
+ efectivoCompleto || tarjetaCompleto,
|
|
|
|
+ onChangedMonto: () => _calcularCambio(setState),
|
|
|
|
+ ),
|
|
|
|
+ const SizedBox(height: 10),
|
|
|
|
+ Align(
|
|
|
|
+ alignment: Alignment.centerRight,
|
|
|
|
+ child: Column(
|
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.end,
|
|
|
|
+ children: [
|
|
|
|
+ Text(
|
|
|
|
+ 'Total del pedido: \$${totalPedido.toStringAsFixed(2)}',
|
|
|
|
+ style: const TextStyle(
|
|
|
|
+ fontWeight: FontWeight.bold, fontSize: 18),
|
|
|
|
+ ),
|
|
|
|
+ if (faltante > 0)
|
|
|
|
+ Text(
|
|
|
|
+ 'Faltante: \$${faltante.toStringAsFixed(2)}',
|
|
|
|
+ style: const TextStyle(
|
|
|
|
+ color: Colors.red,
|
|
|
|
+ fontSize: 18,
|
|
|
|
+ fontWeight: FontWeight.bold),
|
|
|
|
+ )
|
|
|
|
+ else if (cambio > 0)
|
|
|
|
+ Text(
|
|
|
|
+ 'Cambio: \$${cambio.toStringAsFixed(2)}',
|
|
|
|
+ style: const TextStyle(
|
|
|
|
+ color: Colors.green,
|
|
|
|
+ fontSize: 18,
|
|
|
|
+ fontWeight: FontWeight.bold),
|
|
|
|
+ ),
|
|
|
|
+ ],
|
|
|
|
+ ),
|
|
|
|
+ ),
|
|
|
|
+ ],
|
|
|
|
+ ),
|
|
|
|
+ ),
|
|
|
|
+ ),
|
|
|
|
+ actions: [
|
|
|
|
+ TextButton(
|
|
|
|
+ child: const Text('Cancelar', style: TextStyle(fontSize: 18)),
|
|
|
|
+ onPressed: () => Navigator.of(context).pop(false),
|
|
|
|
+ style: ButtonStyle(
|
|
|
|
+ padding: MaterialStateProperty.all(
|
|
|
|
+ EdgeInsets.fromLTRB(30, 20, 30, 20)),
|
|
|
|
+ backgroundColor: MaterialStateProperty.all(Colors.red),
|
|
|
|
+ foregroundColor:
|
|
|
|
+ MaterialStateProperty.all(AppTheme.secondary),
|
|
|
|
+ ),
|
|
|
|
+ ),
|
|
|
|
+ const SizedBox(width: 100),
|
|
|
|
+ TextButton(
|
|
|
|
+ child: const Text('Guardar', style: TextStyle(fontSize: 18)),
|
|
|
|
+ onPressed: totalCompletado
|
|
|
|
+ ? () => Navigator.of(context).pop(true)
|
|
|
|
+ : null,
|
|
|
|
+ style: ButtonStyle(
|
|
|
|
+ padding: MaterialStateProperty.all(
|
|
|
|
+ EdgeInsets.fromLTRB(30, 20, 30, 20)),
|
|
|
|
+ backgroundColor: MaterialStateProperty.all(
|
|
|
|
+ totalCompletado ? AppTheme.tertiary : Colors.grey),
|
|
|
|
+ foregroundColor:
|
|
|
|
+ MaterialStateProperty.all(AppTheme.quaternary),
|
|
|
|
+ ),
|
|
|
|
+ ),
|
|
|
|
+ ],
|
|
|
|
+ );
|
|
|
|
+ },
|
|
|
|
+ );
|
|
|
|
+ },
|
|
);
|
|
);
|
|
|
|
+
|
|
|
|
+ if (shouldSave ?? false) {
|
|
|
|
+ double cantEfectivo = efectivoSeleccionado
|
|
|
|
+ ? double.tryParse(efectivoController.text) ?? 0
|
|
|
|
+ : 0;
|
|
|
|
+ double cantTarjeta = tarjetaSeleccionada
|
|
|
|
+ ? double.tryParse(tarjetaController.text) ?? 0
|
|
|
|
+ : 0;
|
|
|
|
+ double cantTransferencia = transferenciaSeleccionada
|
|
|
|
+ ? double.tryParse(transferenciaController.text) ?? 0
|
|
|
|
+ : 0;
|
|
|
|
+
|
|
|
|
+ pedido.cantEfectivo = cantEfectivo;
|
|
|
|
+ pedido.cantTarjeta = cantTarjeta;
|
|
|
|
+ pedido.cantTransferencia = cantTransferencia;
|
|
|
|
+
|
|
|
|
+ List<String> nuevosMetodos = [];
|
|
|
|
+ if (cantEfectivo > 0) nuevosMetodos.add('Efectivo');
|
|
|
|
+ if (cantTarjeta > 0) nuevosMetodos.add('Tarjeta');
|
|
|
|
+ if (cantTransferencia > 0) nuevosMetodos.add('Transferencia');
|
|
|
|
+
|
|
|
|
+ pedido.tipoPago =
|
|
|
|
+ nuevosMetodos.isNotEmpty ? nuevosMetodos.join(',') : 'No Definido';
|
|
|
|
+
|
|
|
|
+ pedido.sincronizado = null;
|
|
|
|
+
|
|
|
|
+ await _guardarPedido(pedido, context);
|
|
|
|
+
|
|
|
|
+ // Recargamos el pedido desde la BD para tener sus datos actualizados
|
|
|
|
+ PedidoViewModel viewModel =
|
|
|
|
+ Provider.of<PedidoViewModel>(context, listen: false);
|
|
|
|
+ Pedido? pedidoActualizado =
|
|
|
|
+ await viewModel.fetchPedidoConProductos(pedido.id!);
|
|
|
|
+
|
|
|
|
+ if (pedidoActualizado != null) {
|
|
|
|
+ setState(() {
|
|
|
|
+ pedido = pedidoActualizado;
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- Widget _buildPaymentRow(String paymentType, double amount) {
|
|
|
|
|
|
+ Widget _buildPaymentMethodRow(
|
|
|
|
+ StateSetter setState,
|
|
|
|
+ double totalPedido, {
|
|
|
|
+ required String label,
|
|
|
|
+ required bool selected,
|
|
|
|
+ required bool exactSelected,
|
|
|
|
+ required TextEditingController controller,
|
|
|
|
+ required Function(bool) onSelected,
|
|
|
|
+ required Function(bool) onExactSelected,
|
|
|
|
+ required bool disableOtherMethods,
|
|
|
|
+ required Function() onChangedMonto,
|
|
|
|
+ bool sinCambio = false,
|
|
|
|
+ }) {
|
|
return Row(
|
|
return Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
children: [
|
|
- Text(
|
|
|
|
- paymentType,
|
|
|
|
- style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
|
|
|
|
|
+ Row(
|
|
|
|
+ children: [
|
|
|
|
+ Checkbox(
|
|
|
|
+ activeColor: AppTheme.primary,
|
|
|
|
+ value: selected,
|
|
|
|
+ onChanged: disableOtherMethods
|
|
|
|
+ ? null
|
|
|
|
+ : (value) {
|
|
|
|
+ onSelected(value ?? false);
|
|
|
|
+ },
|
|
|
|
+ ),
|
|
|
|
+ GestureDetector(
|
|
|
|
+ onTap: disableOtherMethods
|
|
|
|
+ ? null
|
|
|
|
+ : () {
|
|
|
|
+ onSelected(!selected);
|
|
|
|
+ },
|
|
|
|
+ child: Text(
|
|
|
|
+ label,
|
|
|
|
+ style:
|
|
|
|
+ const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
|
|
|
+ ),
|
|
|
|
+ ),
|
|
|
|
+ ],
|
|
),
|
|
),
|
|
- Text(
|
|
|
|
- '\$${formatCurrency(amount)}',
|
|
|
|
- style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
|
|
|
|
|
+ SizedBox(
|
|
|
|
+ width: 180,
|
|
|
|
+ child: Row(
|
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
+ children: [
|
|
|
|
+ Column(
|
|
|
|
+ children: [
|
|
|
|
+ const Text(
|
|
|
|
+ 'Exacto',
|
|
|
|
+ style: TextStyle(
|
|
|
|
+ fontSize: 18,
|
|
|
|
+ fontWeight: FontWeight.bold,
|
|
|
|
+ color: Colors.black),
|
|
|
|
+ ),
|
|
|
|
+ const SizedBox(height: 17),
|
|
|
|
+ Checkbox(
|
|
|
|
+ activeColor: AppTheme.primary,
|
|
|
|
+ value: exactSelected,
|
|
|
|
+ onChanged: !disableOtherMethods
|
|
|
|
+ ? (value) {
|
|
|
|
+ onExactSelected(value ?? false);
|
|
|
|
+ if (value == true) {
|
|
|
|
+ setState(() {
|
|
|
|
+ // nada especial, ya manejamos esto arriba
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ : null,
|
|
|
|
+ ),
|
|
|
|
+ ],
|
|
|
|
+ ),
|
|
|
|
+ const SizedBox(width: 5),
|
|
|
|
+ Expanded(
|
|
|
|
+ child: AppTextField(
|
|
|
|
+ controller: controller,
|
|
|
|
+ enabled: selected,
|
|
|
|
+ etiqueta: 'Cantidad',
|
|
|
|
+ hintText: '0.00',
|
|
|
|
+ keyboardType: TextInputType.number,
|
|
|
|
+ onChanged: (value) {
|
|
|
|
+ if (sinCambio) {
|
|
|
|
+ double? input = double.tryParse(value) ?? 0;
|
|
|
|
+ if (input > totalPedido) {
|
|
|
|
+ controller.text = totalPedido.toStringAsFixed(2);
|
|
|
|
+ controller.selection = TextSelection.fromPosition(
|
|
|
|
+ TextPosition(offset: controller.text.length),
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ onChangedMonto();
|
|
|
|
+ },
|
|
|
|
+ ),
|
|
|
|
+ ),
|
|
|
|
+ ],
|
|
|
|
+ ),
|
|
),
|
|
),
|
|
],
|
|
],
|
|
);
|
|
);
|
|
@@ -328,10 +783,75 @@ class PedidoDetalleScreen extends StatelessWidget {
|
|
|
|
|
|
String _formatDateTime(String? dateTimeString) {
|
|
String _formatDateTime(String? dateTimeString) {
|
|
if (dateTimeString == null) return "Sin fecha";
|
|
if (dateTimeString == null) return "Sin fecha";
|
|
-
|
|
|
|
DateTime parsedDate = DateTime.parse(dateTimeString);
|
|
DateTime parsedDate = DateTime.parse(dateTimeString);
|
|
-
|
|
|
|
var formatter = DateFormat('dd-MM-yyyy HH:mm:ss');
|
|
var formatter = DateFormat('dd-MM-yyyy HH:mm:ss');
|
|
return formatter.format(parsedDate.toLocal());
|
|
return formatter.format(parsedDate.toLocal());
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ Future<void> _guardarPedido(Pedido pedido, BuildContext buildContext) async {
|
|
|
|
+ RepoService<Pedido> repoPedido = RepoService<Pedido>();
|
|
|
|
+ RepoService<PedidoProducto> repoPedidoProducto =
|
|
|
|
+ RepoService<PedidoProducto>();
|
|
|
|
+ RepoService<PedidoProductoTopping> repoPedidoProductoTopping =
|
|
|
|
+ RepoService<PedidoProductoTopping>();
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ if (pedido.id != null && pedido.id! > 0) {
|
|
|
|
+ await repoPedido.guardar(pedido);
|
|
|
|
+ } else {
|
|
|
|
+ pedido.id = await repoPedido.guardarLocal(pedido);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ List<PedidoProducto> productosExistentes =
|
|
|
|
+ await repoPedidoProducto.obtenerPorIdPedido(pedido.id!);
|
|
|
|
+
|
|
|
|
+ for (var productoExistente in productosExistentes) {
|
|
|
|
+ bool sigueExistiendo = pedido.productos.any(
|
|
|
|
+ (producto) => producto.idProducto == productoExistente.idProducto);
|
|
|
|
+
|
|
|
|
+ if (!sigueExistiendo) {
|
|
|
|
+ productoExistente.eliminado = DateTime.now().toUtc();
|
|
|
|
+ await repoPedidoProducto.guardar(productoExistente);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (var producto in pedido.productos) {
|
|
|
|
+ PedidoProducto pedidoProducto = PedidoProducto(
|
|
|
|
+ idPedido: pedido.id,
|
|
|
|
+ idProducto: producto.idProducto,
|
|
|
|
+ cantidad: producto.cantidad,
|
|
|
|
+ costoUnitario: producto.costoUnitario,
|
|
|
|
+ comentario: producto.comentario,
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ PedidoProducto? productoExistente = productosExistentes
|
|
|
|
+ .firstWhereOrNull((p) => p.idProducto == pedidoProducto.idProducto);
|
|
|
|
+
|
|
|
|
+ if (productoExistente != null) {
|
|
|
|
+ pedidoProducto.id = productoExistente.id;
|
|
|
|
+ await repoPedidoProducto.guardar(pedidoProducto);
|
|
|
|
+ } else {
|
|
|
|
+ int idPedidoProducto =
|
|
|
|
+ await repoPedidoProducto.guardarLocal(pedidoProducto);
|
|
|
|
+ for (var topping in producto.toppings) {
|
|
|
|
+ PedidoProductoTopping pedidoProductoTopping = PedidoProductoTopping(
|
|
|
|
+ idPedidoProducto: idPedidoProducto,
|
|
|
|
+ idTopping: topping.idTopping,
|
|
|
|
+ idCategoria: topping.idCategoria,
|
|
|
|
+ );
|
|
|
|
+ await repoPedidoProductoTopping.guardarLocal(pedidoProductoTopping);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ScaffoldMessenger.of(buildContext).showSnackBar(
|
|
|
|
+ const SnackBar(content: Text("Pedido actualizado correctamente.")),
|
|
|
|
+ );
|
|
|
|
+ } catch (e) {
|
|
|
|
+ print("Error al guardar el pedido: $e");
|
|
|
|
+ ScaffoldMessenger.of(buildContext).showSnackBar(
|
|
|
|
+ const SnackBar(content: Text("Error al actualizar el pedido.")),
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|