commit fonctionnalite impec
This commit is contained in:
parent
2bef06a2fe
commit
9eafda610f
BIN
assets/Orange_money.png
Normal file
BIN
assets/Orange_money.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
BIN
assets/airtel_money.png
Normal file
BIN
assets/airtel_money.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
BIN
assets/mvola.jpg
Normal file
BIN
assets/mvola.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.5 KiB |
7
lib/Components/paymentType.dart
Normal file
7
lib/Components/paymentType.dart
Normal file
@ -0,0 +1,7 @@
|
||||
enum PaymentType {
|
||||
cash,
|
||||
card,
|
||||
mvola,
|
||||
orange,
|
||||
airtel
|
||||
}
|
||||
@ -1563,7 +1563,12 @@ class _CommandeActions extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
enum PaymentType { cash, card }
|
||||
enum PaymentType { cash, card ,
|
||||
|
||||
mvola,
|
||||
orange,
|
||||
airtel
|
||||
}
|
||||
|
||||
class PaymentMethod {
|
||||
final PaymentType type;
|
||||
@ -1584,7 +1589,28 @@ class PaymentMethodDialog extends StatefulWidget {
|
||||
class _PaymentMethodDialogState extends State<PaymentMethodDialog> {
|
||||
PaymentType _selectedPayment = PaymentType.cash;
|
||||
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
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -1598,52 +1624,91 @@ class _PaymentMethodDialogState extends State<PaymentMethodDialog> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget build(BuildContext context) {
|
||||
final amount = double.tryParse(_amountController.text) ?? 0;
|
||||
final change = amount - widget.commande.montantTotal;
|
||||
|
||||
return AlertDialog(
|
||||
title: const Text('Méthode de paiement'),
|
||||
content: Column(
|
||||
title: const Text('Méthode de paiement', style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
RadioListTile<PaymentType>(
|
||||
title: const Text('Paiement en liquide'),
|
||||
value: PaymentType.cash,
|
||||
groupValue: _selectedPayment,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_selectedPayment = value!;
|
||||
});
|
||||
},
|
||||
// Section Paiement mobile
|
||||
const Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text('Mobile Money', style: TextStyle(fontWeight: FontWeight.w500)),
|
||||
),
|
||||
if (_selectedPayment == PaymentType.cash)
|
||||
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,
|
||||
),
|
||||
if (_selectedPayment == PaymentType.cash) ...[
|
||||
const SizedBox(height: 12),
|
||||
TextField(
|
||||
controller: _amountController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Montant donné',
|
||||
prefixText: 'MGA ',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
keyboardType: TextInputType.number,
|
||||
onChanged: (value) {
|
||||
setState(() {}); // Rafraîchir l'UI pour calculer la monnaie
|
||||
},
|
||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||
onChanged: (value) => setState(() {}),
|
||||
),
|
||||
RadioListTile<PaymentType>(
|
||||
title: const Text('Carte bancaire'),
|
||||
value: PaymentType.card,
|
||||
groupValue: _selectedPayment,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_selectedPayment = value!;
|
||||
});
|
||||
},
|
||||
),
|
||||
if (_selectedPayment == PaymentType.cash)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: Text(
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Monnaie à rendre: ${change.toStringAsFixed(2)} MGA',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
@ -1651,41 +1716,97 @@ class _PaymentMethodDialogState extends State<PaymentMethodDialog> {
|
||||
color: change >= 0 ? Colors.green : Colors.red,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: const Text('Annuler'),
|
||||
child: const Text('Annuler', style: TextStyle(color: Colors.grey)),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
final amount = _selectedPayment == PaymentType.cash
|
||||
? double.tryParse(_amountController.text) ?? 0
|
||||
: widget.commande.montantTotal;
|
||||
|
||||
if (_selectedPayment == PaymentType.cash && amount < widget.commande.montantTotal) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Le montant donné est insuffisant'),
|
||||
backgroundColor: Colors.red,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.blue.shade800,
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
Navigator.pop(
|
||||
context,
|
||||
PaymentMethod(
|
||||
type: _selectedPayment,
|
||||
amountGiven: amount,
|
||||
),
|
||||
);
|
||||
},
|
||||
onPressed: _validatePayment,
|
||||
child: const Text('Confirmer'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildMobileMoneyTile({
|
||||
required String title,
|
||||
required String imagePath,
|
||||
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: 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),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
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),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -260,12 +260,29 @@ class _NouvelleCommandePageState extends State<NouvelleCommandePage> {
|
||||
void _showClientFormDialog() {
|
||||
Get.dialog(
|
||||
AlertDialog(
|
||||
title: const Text('Informations Client'),
|
||||
content: SingleChildScrollView(
|
||||
title: Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue.shade100,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Icon(Icons.person_add, color: Colors.blue.shade700),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
const Text('Informations Client'),
|
||||
],
|
||||
),
|
||||
content: Container(
|
||||
width: 600,
|
||||
constraints: const BoxConstraints(maxHeight: 600),
|
||||
child: SingleChildScrollView(
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildTextFormField(
|
||||
controller: _nomController,
|
||||
@ -311,6 +328,7 @@ class _NouvelleCommandePageState extends State<NouvelleCommandePage> {
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Get.back(),
|
||||
@ -320,25 +338,21 @@ class _NouvelleCommandePageState extends State<NouvelleCommandePage> {
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.blue.shade800,
|
||||
foregroundColor: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
),
|
||||
onPressed: () {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
Get.back();
|
||||
Get.snackbar(
|
||||
'Succès',
|
||||
'Informations client enregistrées',
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
backgroundColor: Colors.green,
|
||||
colorText: Colors.white,
|
||||
);
|
||||
// Au lieu d'afficher juste un message, on valide directement la commande
|
||||
_submitOrder();
|
||||
}
|
||||
},
|
||||
child: const Text('Enregistrer'),
|
||||
child: const Text('Valider la commande'), // Changement de texte ici
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildTextFormField({
|
||||
required TextEditingController controller,
|
||||
@ -464,7 +478,7 @@ class _NouvelleCommandePageState extends State<NouvelleCommandePage> {
|
||||
children: [
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'${product.price.toStringAsFixed(2)} DA',
|
||||
'${product.price.toStringAsFixed(2)} MGA',
|
||||
style: TextStyle(
|
||||
color: Colors.green.shade700,
|
||||
fontWeight: FontWeight.w600,
|
||||
@ -626,9 +640,9 @@ class _NouvelleCommandePageState extends State<NouvelleCommandePage> {
|
||||
child: const Icon(Icons.shopping_bag, size: 20),
|
||||
),
|
||||
title: Text(product.name),
|
||||
subtitle: Text('${entry.value} x ${product.price.toStringAsFixed(2)} DA'),
|
||||
subtitle: Text('${entry.value} x ${product.price.toStringAsFixed(2)} MGA'),
|
||||
trailing: Text(
|
||||
'${(entry.value * product.price).toStringAsFixed(2)} DA',
|
||||
'${(entry.value * product.price).toStringAsFixed(2)} MGA',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.blue.shade800,
|
||||
@ -658,7 +672,7 @@ class _NouvelleCommandePageState extends State<NouvelleCommandePage> {
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
Text(
|
||||
'${total.toStringAsFixed(2)} DA',
|
||||
'${total.toStringAsFixed(2)} MGA',
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
@ -708,23 +722,7 @@ class _NouvelleCommandePageState extends State<NouvelleCommandePage> {
|
||||
}
|
||||
|
||||
Future<void> _submitOrder() async {
|
||||
if (_nomController.text.isEmpty ||
|
||||
_prenomController.text.isEmpty ||
|
||||
_emailController.text.isEmpty ||
|
||||
_telephoneController.text.isEmpty ||
|
||||
_adresseController.text.isEmpty) {
|
||||
Get.back(); // Ferme le bottom sheet
|
||||
Get.snackbar(
|
||||
'Informations manquantes',
|
||||
'Veuillez remplir les informations client',
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
backgroundColor: Colors.red,
|
||||
colorText: Colors.white,
|
||||
);
|
||||
_showClientFormDialog();
|
||||
return;
|
||||
}
|
||||
|
||||
// Vérifier d'abord si le panier est vide
|
||||
final itemsInCart = _quantites.entries.where((e) => e.value > 0).toList();
|
||||
if (itemsInCart.isEmpty) {
|
||||
Get.snackbar(
|
||||
@ -734,6 +732,24 @@ class _NouvelleCommandePageState extends State<NouvelleCommandePage> {
|
||||
backgroundColor: Colors.red,
|
||||
colorText: Colors.white,
|
||||
);
|
||||
_showCartBottomSheet(); // Ouvrir le panier pour montrer qu'il est vide
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensuite vérifier les informations client
|
||||
if (_nomController.text.isEmpty ||
|
||||
_prenomController.text.isEmpty ||
|
||||
_emailController.text.isEmpty ||
|
||||
_telephoneController.text.isEmpty ||
|
||||
_adresseController.text.isEmpty) {
|
||||
Get.snackbar(
|
||||
'Informations manquantes',
|
||||
'Veuillez remplir les informations client',
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
backgroundColor: Colors.red,
|
||||
colorText: Colors.white,
|
||||
);
|
||||
_showClientFormDialog();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -781,14 +797,12 @@ class _NouvelleCommandePageState extends State<NouvelleCommandePage> {
|
||||
try {
|
||||
await _appDatabase.createCommandeComplete(client, commande, details);
|
||||
|
||||
Get.back(); // Ferme le bottom sheet
|
||||
|
||||
// Afficher le dialogue de confirmation
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Commande Validée'),
|
||||
content: const Text('Votre commande a été enregistrée avec succès.'),
|
||||
content: const Text('Votre commande a été enregistrée et expédiée avec succès.'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
@ -823,7 +837,7 @@ class _NouvelleCommandePageState extends State<NouvelleCommandePage> {
|
||||
colorText: Colors.white,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
|
||||
@ -102,6 +102,9 @@ flutter:
|
||||
- assets/database/usersdb.db
|
||||
- assets/database/work.db
|
||||
- assets/database/roles.db
|
||||
- assets/airtel_money.png
|
||||
- assets/mvola.jpg
|
||||
- assets/Orange_money.png
|
||||
|
||||
# An image asset can refer to one or more resolution-specific "variants", see
|
||||
# https://flutter.dev/assets-and-images/#resolution-aware
|
||||
|
||||
Loading…
Reference in New Issue
Block a user