|
|
@ -258,14 +258,31 @@ class _NouvelleCommandePageState extends State<NouvelleCommandePage> { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void _showClientFormDialog() { |
|
|
void _showClientFormDialog() { |
|
|
Get.dialog( |
|
|
Get.dialog( |
|
|
AlertDialog( |
|
|
AlertDialog( |
|
|
title: const Text('Informations Client'), |
|
|
title: Row( |
|
|
content: SingleChildScrollView( |
|
|
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( |
|
|
child: Form( |
|
|
key: _formKey, |
|
|
key: _formKey, |
|
|
child: Column( |
|
|
child: Column( |
|
|
mainAxisSize: MainAxisSize.min, |
|
|
mainAxisSize: MainAxisSize.min, |
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start, |
|
|
children: [ |
|
|
children: [ |
|
|
_buildTextFormField( |
|
|
_buildTextFormField( |
|
|
controller: _nomController, |
|
|
controller: _nomController, |
|
|
@ -307,38 +324,35 @@ class _NouvelleCommandePageState extends State<NouvelleCommandePage> { |
|
|
), |
|
|
), |
|
|
const SizedBox(height: 12), |
|
|
const SizedBox(height: 12), |
|
|
_buildCommercialDropdown(), |
|
|
_buildCommercialDropdown(), |
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
actions: [ |
|
|
|
|
|
TextButton( |
|
|
|
|
|
onPressed: () => Get.back(), |
|
|
|
|
|
child: const Text('Annuler'), |
|
|
|
|
|
), |
|
|
|
|
|
ElevatedButton( |
|
|
|
|
|
style: ElevatedButton.styleFrom( |
|
|
|
|
|
backgroundColor: Colors.blue.shade800, |
|
|
|
|
|
foregroundColor: Colors.white, |
|
|
|
|
|
), |
|
|
|
|
|
onPressed: () { |
|
|
|
|
|
if (_formKey.currentState!.validate()) { |
|
|
|
|
|
Get.back(); |
|
|
|
|
|
Get.snackbar( |
|
|
|
|
|
'Succès', |
|
|
|
|
|
'Informations client enregistrées', |
|
|
|
|
|
snackPosition: SnackPosition.BOTTOM, |
|
|
|
|
|
backgroundColor: Colors.green, |
|
|
|
|
|
colorText: Colors.white, |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
}, |
|
|
|
|
|
child: const Text('Enregistrer'), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
), |
|
|
); |
|
|
actions: [ |
|
|
} |
|
|
TextButton( |
|
|
|
|
|
onPressed: () => Get.back(), |
|
|
|
|
|
child: const Text('Annuler'), |
|
|
|
|
|
), |
|
|
|
|
|
ElevatedButton( |
|
|
|
|
|
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(); |
|
|
|
|
|
// Au lieu d'afficher juste un message, on valide directement la commande |
|
|
|
|
|
_submitOrder(); |
|
|
|
|
|
} |
|
|
|
|
|
}, |
|
|
|
|
|
child: const Text('Valider la commande'), // Changement de texte ici |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
Widget _buildTextFormField({ |
|
|
Widget _buildTextFormField({ |
|
|
required TextEditingController controller, |
|
|
required TextEditingController controller, |
|
|
@ -464,7 +478,7 @@ class _NouvelleCommandePageState extends State<NouvelleCommandePage> { |
|
|
children: [ |
|
|
children: [ |
|
|
const SizedBox(height: 4), |
|
|
const SizedBox(height: 4), |
|
|
Text( |
|
|
Text( |
|
|
'${product.price.toStringAsFixed(2)} DA', |
|
|
'${product.price.toStringAsFixed(2)} MGA', |
|
|
style: TextStyle( |
|
|
style: TextStyle( |
|
|
color: Colors.green.shade700, |
|
|
color: Colors.green.shade700, |
|
|
fontWeight: FontWeight.w600, |
|
|
fontWeight: FontWeight.w600, |
|
|
@ -626,9 +640,9 @@ class _NouvelleCommandePageState extends State<NouvelleCommandePage> { |
|
|
child: const Icon(Icons.shopping_bag, size: 20), |
|
|
child: const Icon(Icons.shopping_bag, size: 20), |
|
|
), |
|
|
), |
|
|
title: Text(product.name), |
|
|
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( |
|
|
trailing: Text( |
|
|
'${(entry.value * product.price).toStringAsFixed(2)} DA', |
|
|
'${(entry.value * product.price).toStringAsFixed(2)} MGA', |
|
|
style: TextStyle( |
|
|
style: TextStyle( |
|
|
fontWeight: FontWeight.bold, |
|
|
fontWeight: FontWeight.bold, |
|
|
color: Colors.blue.shade800, |
|
|
color: Colors.blue.shade800, |
|
|
@ -658,7 +672,7 @@ class _NouvelleCommandePageState extends State<NouvelleCommandePage> { |
|
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), |
|
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), |
|
|
), |
|
|
), |
|
|
Text( |
|
|
Text( |
|
|
'${total.toStringAsFixed(2)} DA', |
|
|
'${total.toStringAsFixed(2)} MGA', |
|
|
style: const TextStyle( |
|
|
style: const TextStyle( |
|
|
fontSize: 18, |
|
|
fontSize: 18, |
|
|
fontWeight: FontWeight.bold, |
|
|
fontWeight: FontWeight.bold, |
|
|
@ -708,122 +722,122 @@ class _NouvelleCommandePageState extends State<NouvelleCommandePage> { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Future<void> _submitOrder() async { |
|
|
Future<void> _submitOrder() async { |
|
|
if (_nomController.text.isEmpty || |
|
|
// Vérifier d'abord si le panier est vide |
|
|
_prenomController.text.isEmpty || |
|
|
final itemsInCart = _quantites.entries.where((e) => e.value > 0).toList(); |
|
|
_emailController.text.isEmpty || |
|
|
if (itemsInCart.isEmpty) { |
|
|
_telephoneController.text.isEmpty || |
|
|
Get.snackbar( |
|
|
_adresseController.text.isEmpty) { |
|
|
'Panier vide', |
|
|
Get.back(); // Ferme le bottom sheet |
|
|
'Veuillez ajouter des produits à votre commande', |
|
|
Get.snackbar( |
|
|
snackPosition: SnackPosition.BOTTOM, |
|
|
'Informations manquantes', |
|
|
backgroundColor: Colors.red, |
|
|
'Veuillez remplir les informations client', |
|
|
colorText: Colors.white, |
|
|
snackPosition: SnackPosition.BOTTOM, |
|
|
); |
|
|
backgroundColor: Colors.red, |
|
|
_showCartBottomSheet(); // Ouvrir le panier pour montrer qu'il est vide |
|
|
colorText: Colors.white, |
|
|
return; |
|
|
); |
|
|
} |
|
|
_showClientFormDialog(); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
final itemsInCart = _quantites.entries.where((e) => e.value > 0).toList(); |
|
|
|
|
|
if (itemsInCart.isEmpty) { |
|
|
|
|
|
Get.snackbar( |
|
|
|
|
|
'Panier vide', |
|
|
|
|
|
'Veuillez ajouter des produits à votre commande', |
|
|
|
|
|
snackPosition: SnackPosition.BOTTOM, |
|
|
|
|
|
backgroundColor: Colors.red, |
|
|
|
|
|
colorText: Colors.white, |
|
|
|
|
|
); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
setState(() { |
|
|
|
|
|
_isLoading = true; |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// Créer le client |
|
|
// Ensuite vérifier les informations client |
|
|
final client = Client( |
|
|
if (_nomController.text.isEmpty || |
|
|
nom: _nomController.text, |
|
|
_prenomController.text.isEmpty || |
|
|
prenom: _prenomController.text, |
|
|
_emailController.text.isEmpty || |
|
|
email: _emailController.text, |
|
|
_telephoneController.text.isEmpty || |
|
|
telephone: _telephoneController.text, |
|
|
_adresseController.text.isEmpty) { |
|
|
adresse: _adresseController.text, |
|
|
Get.snackbar( |
|
|
dateCreation: DateTime.now(), |
|
|
'Informations manquantes', |
|
|
|
|
|
'Veuillez remplir les informations client', |
|
|
|
|
|
snackPosition: SnackPosition.BOTTOM, |
|
|
|
|
|
backgroundColor: Colors.red, |
|
|
|
|
|
colorText: Colors.white, |
|
|
); |
|
|
); |
|
|
|
|
|
_showClientFormDialog(); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// Calculer le total et préparer les détails |
|
|
setState(() { |
|
|
double total = 0; |
|
|
_isLoading = true; |
|
|
final details = <DetailCommande>[]; |
|
|
}); |
|
|
|
|
|
|
|
|
for (final entry in itemsInCart) { |
|
|
// Créer le client |
|
|
final product = _products.firstWhere((p) => p.id == entry.key); |
|
|
final client = Client( |
|
|
total += entry.value * product.price; |
|
|
nom: _nomController.text, |
|
|
|
|
|
prenom: _prenomController.text, |
|
|
details.add(DetailCommande( |
|
|
email: _emailController.text, |
|
|
commandeId: 0, |
|
|
telephone: _telephoneController.text, |
|
|
produitId: product.id!, |
|
|
adresse: _adresseController.text, |
|
|
quantite: entry.value, |
|
|
dateCreation: DateTime.now(), |
|
|
prixUnitaire: product.price, |
|
|
); |
|
|
sousTotal: entry.value * product.price, |
|
|
|
|
|
)); |
|
|
// Calculer le total et préparer les détails |
|
|
} |
|
|
double total = 0; |
|
|
|
|
|
final details = <DetailCommande>[]; |
|
|
|
|
|
|
|
|
|
|
|
for (final entry in itemsInCart) { |
|
|
|
|
|
final product = _products.firstWhere((p) => p.id == entry.key); |
|
|
|
|
|
total += entry.value * product.price; |
|
|
|
|
|
|
|
|
|
|
|
details.add(DetailCommande( |
|
|
|
|
|
commandeId: 0, |
|
|
|
|
|
produitId: product.id!, |
|
|
|
|
|
quantite: entry.value, |
|
|
|
|
|
prixUnitaire: product.price, |
|
|
|
|
|
sousTotal: entry.value * product.price, |
|
|
|
|
|
)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// Créer la commande |
|
|
// Créer la commande |
|
|
final commande = Commande( |
|
|
final commande = Commande( |
|
|
clientId: 0, |
|
|
clientId: 0, |
|
|
dateCommande: DateTime.now(), |
|
|
dateCommande: DateTime.now(), |
|
|
statut: StatutCommande.enAttente, |
|
|
statut: StatutCommande.enAttente, |
|
|
montantTotal: total, |
|
|
montantTotal: total, |
|
|
notes: 'Commande passée via l\'application', |
|
|
notes: 'Commande passée via l\'application', |
|
|
commandeurId: _selectedCommercialUser?.id, |
|
|
commandeurId: _selectedCommercialUser?.id, |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
await _appDatabase.createCommandeComplete(client, commande, details); |
|
|
|
|
|
|
|
|
|
|
|
// 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 et expédiée avec succès.'), |
|
|
|
|
|
actions: [ |
|
|
|
|
|
TextButton( |
|
|
|
|
|
onPressed: () { |
|
|
|
|
|
Navigator.pop(context); |
|
|
|
|
|
// Réinitialiser le formulaire |
|
|
|
|
|
_nomController.clear(); |
|
|
|
|
|
_prenomController.clear(); |
|
|
|
|
|
_emailController.clear(); |
|
|
|
|
|
_telephoneController.clear(); |
|
|
|
|
|
_adresseController.clear(); |
|
|
|
|
|
setState(() { |
|
|
|
|
|
_quantites.clear(); |
|
|
|
|
|
_isLoading = false; |
|
|
|
|
|
}); |
|
|
|
|
|
}, |
|
|
|
|
|
child: const Text('OK'), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
try { |
|
|
} catch (e) { |
|
|
await _appDatabase.createCommandeComplete(client, commande, details); |
|
|
setState(() { |
|
|
|
|
|
_isLoading = false; |
|
|
Get.back(); // Ferme le bottom sheet |
|
|
}); |
|
|
|
|
|
|
|
|
// Afficher le dialogue de confirmation |
|
|
Get.snackbar( |
|
|
await showDialog( |
|
|
'Erreur', |
|
|
context: context, |
|
|
'Une erreur est survenue: ${e.toString()}', |
|
|
builder: (context) => AlertDialog( |
|
|
snackPosition: SnackPosition.BOTTOM, |
|
|
title: const Text('Commande Validée'), |
|
|
backgroundColor: Colors.red, |
|
|
content: const Text('Votre commande a été enregistrée avec succès.'), |
|
|
colorText: Colors.white, |
|
|
actions: [ |
|
|
); |
|
|
TextButton( |
|
|
|
|
|
onPressed: () { |
|
|
|
|
|
Navigator.pop(context); |
|
|
|
|
|
// Réinitialiser le formulaire |
|
|
|
|
|
_nomController.clear(); |
|
|
|
|
|
_prenomController.clear(); |
|
|
|
|
|
_emailController.clear(); |
|
|
|
|
|
_telephoneController.clear(); |
|
|
|
|
|
_adresseController.clear(); |
|
|
|
|
|
setState(() { |
|
|
|
|
|
_quantites.clear(); |
|
|
|
|
|
_isLoading = false; |
|
|
|
|
|
}); |
|
|
|
|
|
}, |
|
|
|
|
|
child: const Text('OK'), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
setState(() { |
|
|
|
|
|
_isLoading = false; |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
Get.snackbar( |
|
|
|
|
|
'Erreur', |
|
|
|
|
|
'Une erreur est survenue: ${e.toString()}', |
|
|
|
|
|
snackPosition: SnackPosition.BOTTOM, |
|
|
|
|
|
backgroundColor: Colors.red, |
|
|
|
|
|
colorText: Colors.white, |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
@override |
|
|
@override |
|
|
void dispose() { |
|
|
void dispose() { |
|
|
|