|
|
@ -1563,7 +1563,12 @@ class _CommandeActions extends StatelessWidget { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
enum PaymentType { cash, card } |
|
|
enum PaymentType { cash, card , |
|
|
|
|
|
|
|
|
|
|
|
mvola, |
|
|
|
|
|
orange, |
|
|
|
|
|
airtel |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
class PaymentMethod { |
|
|
class PaymentMethod { |
|
|
final PaymentType type; |
|
|
final PaymentType type; |
|
|
@ -1584,7 +1589,28 @@ class PaymentMethodDialog extends StatefulWidget { |
|
|
class _PaymentMethodDialogState extends State<PaymentMethodDialog> { |
|
|
class _PaymentMethodDialogState extends State<PaymentMethodDialog> { |
|
|
PaymentType _selectedPayment = PaymentType.cash; |
|
|
PaymentType _selectedPayment = PaymentType.cash; |
|
|
final _amountController = TextEditingController(); |
|
|
final _amountController = TextEditingController(); |
|
|
|
|
|
void _validatePayment() { |
|
|
|
|
|
if (_selectedPayment == PaymentType.cash) { |
|
|
|
|
|
final amountGiven = double.tryParse(_amountController.text) ?? 0; |
|
|
|
|
|
if (amountGiven < widget.commande.montantTotal) { |
|
|
|
|
|
Get.snackbar( |
|
|
|
|
|
'Erreur', |
|
|
|
|
|
'Le montant donné est insuffisant', |
|
|
|
|
|
snackPosition: SnackPosition.BOTTOM, |
|
|
|
|
|
backgroundColor: Colors.red, |
|
|
|
|
|
colorText: Colors.white, |
|
|
|
|
|
); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Navigator.pop(context, PaymentMethod( |
|
|
|
|
|
type: _selectedPayment, |
|
|
|
|
|
amountGiven: _selectedPayment == PaymentType.cash |
|
|
|
|
|
? double.parse(_amountController.text) |
|
|
|
|
|
: widget.commande.montantTotal, |
|
|
|
|
|
)); |
|
|
|
|
|
} |
|
|
@override |
|
|
@override |
|
|
void initState() { |
|
|
void initState() { |
|
|
super.initState(); |
|
|
super.initState(); |
|
|
@ -1598,52 +1624,91 @@ class _PaymentMethodDialogState extends State<PaymentMethodDialog> { |
|
|
super.dispose(); |
|
|
super.dispose(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@override |
|
|
@override |
|
|
Widget build(BuildContext context) { |
|
|
Widget build(BuildContext context) { |
|
|
final amount = double.tryParse(_amountController.text) ?? 0; |
|
|
final amount = double.tryParse(_amountController.text) ?? 0; |
|
|
final change = amount - widget.commande.montantTotal; |
|
|
final change = amount - widget.commande.montantTotal; |
|
|
|
|
|
|
|
|
return AlertDialog( |
|
|
return AlertDialog( |
|
|
title: const Text('Méthode de paiement'), |
|
|
title: const Text('Méthode de paiement', style: TextStyle(fontWeight: FontWeight.bold)), |
|
|
content: Column( |
|
|
content: SingleChildScrollView( |
|
|
|
|
|
child: Column( |
|
|
mainAxisSize: MainAxisSize.min, |
|
|
mainAxisSize: MainAxisSize.min, |
|
|
children: [ |
|
|
children: [ |
|
|
RadioListTile<PaymentType>( |
|
|
// Section Paiement mobile |
|
|
title: const Text('Paiement en liquide'), |
|
|
const Align( |
|
|
|
|
|
alignment: Alignment.centerLeft, |
|
|
|
|
|
child: Text('Mobile Money', style: TextStyle(fontWeight: FontWeight.w500)), |
|
|
|
|
|
), |
|
|
|
|
|
const SizedBox(height: 8), |
|
|
|
|
|
Row( |
|
|
|
|
|
children: [ |
|
|
|
|
|
Expanded( |
|
|
|
|
|
child: _buildMobileMoneyTile( |
|
|
|
|
|
title: 'Mvola', |
|
|
|
|
|
imagePath: 'assets/mvola.jpg', |
|
|
|
|
|
value: PaymentType.mvola, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
const SizedBox(width: 8), |
|
|
|
|
|
Expanded( |
|
|
|
|
|
child: _buildMobileMoneyTile( |
|
|
|
|
|
title: 'Orange Money', |
|
|
|
|
|
imagePath: 'assets/Orange_money.png', |
|
|
|
|
|
value: PaymentType.orange, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
const SizedBox(width: 8), |
|
|
|
|
|
Expanded( |
|
|
|
|
|
child: _buildMobileMoneyTile( |
|
|
|
|
|
title: 'Airtel Money', |
|
|
|
|
|
imagePath: 'assets/airtel_money.png', |
|
|
|
|
|
value: PaymentType.airtel, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
const SizedBox(height: 16), |
|
|
|
|
|
|
|
|
|
|
|
// Section Carte bancaire |
|
|
|
|
|
const Align( |
|
|
|
|
|
alignment: Alignment.centerLeft, |
|
|
|
|
|
child: Text('Carte Bancaire', style: TextStyle(fontWeight: FontWeight.w500)), |
|
|
|
|
|
), |
|
|
|
|
|
const SizedBox(height: 8), |
|
|
|
|
|
_buildPaymentMethodTile( |
|
|
|
|
|
title: 'Carte bancaire', |
|
|
|
|
|
icon: Icons.credit_card, |
|
|
|
|
|
value: PaymentType.card, |
|
|
|
|
|
), |
|
|
|
|
|
const SizedBox(height: 16), |
|
|
|
|
|
|
|
|
|
|
|
// Section Paiement en liquide |
|
|
|
|
|
const Align( |
|
|
|
|
|
alignment: Alignment.centerLeft, |
|
|
|
|
|
child: Text('Espèces', style: TextStyle(fontWeight: FontWeight.w500)), |
|
|
|
|
|
), |
|
|
|
|
|
const SizedBox(height: 8), |
|
|
|
|
|
_buildPaymentMethodTile( |
|
|
|
|
|
title: 'Paiement en liquide', |
|
|
|
|
|
icon: Icons.money, |
|
|
value: PaymentType.cash, |
|
|
value: PaymentType.cash, |
|
|
groupValue: _selectedPayment, |
|
|
|
|
|
onChanged: (value) { |
|
|
|
|
|
setState(() { |
|
|
|
|
|
_selectedPayment = value!; |
|
|
|
|
|
}); |
|
|
|
|
|
}, |
|
|
|
|
|
), |
|
|
), |
|
|
if (_selectedPayment == PaymentType.cash) |
|
|
if (_selectedPayment == PaymentType.cash) ...[ |
|
|
|
|
|
const SizedBox(height: 12), |
|
|
TextField( |
|
|
TextField( |
|
|
controller: _amountController, |
|
|
controller: _amountController, |
|
|
decoration: const InputDecoration( |
|
|
decoration: const InputDecoration( |
|
|
labelText: 'Montant donné', |
|
|
labelText: 'Montant donné', |
|
|
prefixText: 'MGA ', |
|
|
prefixText: 'MGA ', |
|
|
|
|
|
border: OutlineInputBorder(), |
|
|
), |
|
|
), |
|
|
keyboardType: TextInputType.number, |
|
|
keyboardType: TextInputType.numberWithOptions(decimal: true), |
|
|
onChanged: (value) { |
|
|
onChanged: (value) => setState(() {}), |
|
|
setState(() {}); // Rafraîchir l'UI pour calculer la monnaie |
|
|
|
|
|
}, |
|
|
|
|
|
), |
|
|
|
|
|
RadioListTile<PaymentType>( |
|
|
|
|
|
title: const Text('Carte bancaire'), |
|
|
|
|
|
value: PaymentType.card, |
|
|
|
|
|
groupValue: _selectedPayment, |
|
|
|
|
|
onChanged: (value) { |
|
|
|
|
|
setState(() { |
|
|
|
|
|
_selectedPayment = value!; |
|
|
|
|
|
}); |
|
|
|
|
|
}, |
|
|
|
|
|
), |
|
|
), |
|
|
if (_selectedPayment == PaymentType.cash) |
|
|
const SizedBox(height: 8), |
|
|
Padding( |
|
|
Text( |
|
|
padding: const EdgeInsets.only(top: 8.0), |
|
|
|
|
|
child: Text( |
|
|
|
|
|
'Monnaie à rendre: ${change.toStringAsFixed(2)} MGA', |
|
|
'Monnaie à rendre: ${change.toStringAsFixed(2)} MGA', |
|
|
style: TextStyle( |
|
|
style: TextStyle( |
|
|
fontSize: 16, |
|
|
fontSize: 16, |
|
|
@ -1651,41 +1716,97 @@ class _PaymentMethodDialogState extends State<PaymentMethodDialog> { |
|
|
color: change >= 0 ? Colors.green : Colors.red, |
|
|
color: change >= 0 ? Colors.green : Colors.red, |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
|
|
|
], |
|
|
], |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
), |
|
|
), |
|
|
actions: [ |
|
|
actions: [ |
|
|
TextButton( |
|
|
TextButton( |
|
|
onPressed: () => Navigator.pop(context), |
|
|
onPressed: () => Navigator.pop(context), |
|
|
child: const Text('Annuler'), |
|
|
child: const Text('Annuler', style: TextStyle(color: Colors.grey)), |
|
|
), |
|
|
), |
|
|
ElevatedButton( |
|
|
ElevatedButton( |
|
|
onPressed: () { |
|
|
style: ElevatedButton.styleFrom( |
|
|
final amount = _selectedPayment == PaymentType.cash |
|
|
backgroundColor: Colors.blue.shade800, |
|
|
? double.tryParse(_amountController.text) ?? 0 |
|
|
foregroundColor: Colors.white, |
|
|
: widget.commande.montantTotal; |
|
|
), |
|
|
|
|
|
onPressed: _validatePayment, |
|
|
if (_selectedPayment == PaymentType.cash && amount < widget.commande.montantTotal) { |
|
|
child: const Text('Confirmer'), |
|
|
ScaffoldMessenger.of(context).showSnackBar( |
|
|
|
|
|
const SnackBar( |
|
|
|
|
|
content: Text('Le montant donné est insuffisant'), |
|
|
|
|
|
backgroundColor: Colors.red, |
|
|
|
|
|
), |
|
|
), |
|
|
|
|
|
], |
|
|
); |
|
|
); |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Navigator.pop( |
|
|
Widget _buildMobileMoneyTile({ |
|
|
context, |
|
|
required String title, |
|
|
PaymentMethod( |
|
|
required String imagePath, |
|
|
type: _selectedPayment, |
|
|
required PaymentType value, |
|
|
amountGiven: amount, |
|
|
}) { |
|
|
|
|
|
return Card( |
|
|
|
|
|
elevation: 2, |
|
|
|
|
|
shape: RoundedRectangleBorder( |
|
|
|
|
|
borderRadius: BorderRadius.circular(8), |
|
|
|
|
|
side: BorderSide( |
|
|
|
|
|
color: _selectedPayment == value ? Colors.blue : Colors.grey.withOpacity(0.2), |
|
|
|
|
|
width: 2, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
child: InkWell( |
|
|
|
|
|
borderRadius: BorderRadius.circular(8), |
|
|
|
|
|
onTap: () => setState(() => _selectedPayment = value), |
|
|
|
|
|
child: Padding( |
|
|
|
|
|
padding: const EdgeInsets.all(12), |
|
|
|
|
|
child: Column( |
|
|
|
|
|
children: [ |
|
|
|
|
|
Image.asset( |
|
|
|
|
|
imagePath, |
|
|
|
|
|
height: 30, |
|
|
|
|
|
width: 30, |
|
|
|
|
|
fit: BoxFit.contain, |
|
|
|
|
|
errorBuilder: (context, error, stackTrace) => |
|
|
|
|
|
const Icon(Icons.mobile_friendly, size: 30), |
|
|
|
|
|
), |
|
|
|
|
|
const SizedBox(height: 8), |
|
|
|
|
|
Text( |
|
|
|
|
|
title, |
|
|
|
|
|
textAlign: TextAlign.center, |
|
|
|
|
|
style: const TextStyle(fontSize: 12), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
), |
|
|
), |
|
|
); |
|
|
); |
|
|
}, |
|
|
} |
|
|
child: const Text('Confirmer'), |
|
|
|
|
|
|
|
|
Widget _buildPaymentMethodTile({ |
|
|
|
|
|
required String title, |
|
|
|
|
|
required IconData icon, |
|
|
|
|
|
required PaymentType value, |
|
|
|
|
|
}) { |
|
|
|
|
|
return Card( |
|
|
|
|
|
elevation: 2, |
|
|
|
|
|
shape: RoundedRectangleBorder( |
|
|
|
|
|
borderRadius: BorderRadius.circular(8), |
|
|
|
|
|
side: BorderSide( |
|
|
|
|
|
color: _selectedPayment == value ? Colors.blue : Colors.grey.withOpacity(0.2), |
|
|
|
|
|
width: 2, |
|
|
|
|
|
), |
|
|
), |
|
|
), |
|
|
|
|
|
child: InkWell( |
|
|
|
|
|
borderRadius: BorderRadius.circular(8), |
|
|
|
|
|
onTap: () => setState(() => _selectedPayment = value), |
|
|
|
|
|
child: Padding( |
|
|
|
|
|
padding: const EdgeInsets.all(12), |
|
|
|
|
|
child: Row( |
|
|
|
|
|
children: [ |
|
|
|
|
|
Icon(icon, size: 24), |
|
|
|
|
|
const SizedBox(width: 12), |
|
|
|
|
|
Text(title), |
|
|
], |
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|