|
|
@ -4,22 +4,21 @@ import 'package:youmazgestion/Models/client.dart'; |
|
|
|
|
|
|
|
|
import '../Services/stock_managementDatabase.dart'; |
|
|
import '../Services/stock_managementDatabase.dart'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ClientFormController extends GetxController { |
|
|
class ClientFormController extends GetxController { |
|
|
final _formKey = GlobalKey<FormState>(); |
|
|
final _formKey = GlobalKey<FormState>(); |
|
|
|
|
|
|
|
|
// Controllers pour les champs |
|
|
// Controllers pour les champs |
|
|
final _nomController = TextEditingController(); |
|
|
final _nomController = TextEditingController(); |
|
|
final _prenomController = TextEditingController(); |
|
|
final _prenomController = TextEditingController(); |
|
|
final _emailController = TextEditingController(); |
|
|
final _emailController = TextEditingController(); |
|
|
final _telephoneController = TextEditingController(); |
|
|
final _telephoneController = TextEditingController(); |
|
|
final _adresseController = TextEditingController(); |
|
|
final _adresseController = TextEditingController(); |
|
|
|
|
|
|
|
|
// Variables observables pour la recherche |
|
|
// Variables observables pour la recherche |
|
|
var suggestedClients = <Client>[].obs; |
|
|
var suggestedClients = <Client>[].obs; |
|
|
var isSearching = false.obs; |
|
|
var isSearching = false.obs; |
|
|
var selectedClient = Rxn<Client>(); |
|
|
var selectedClient = Rxn<Client>(); |
|
|
|
|
|
|
|
|
@override |
|
|
@override |
|
|
void onClose() { |
|
|
void onClose() { |
|
|
_nomController.dispose(); |
|
|
_nomController.dispose(); |
|
|
@ -29,14 +28,14 @@ class ClientFormController extends GetxController { |
|
|
_adresseController.dispose(); |
|
|
_adresseController.dispose(); |
|
|
super.onClose(); |
|
|
super.onClose(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Méthode pour rechercher les clients existants |
|
|
// Méthode pour rechercher les clients existants |
|
|
Future<void> searchClients(String query) async { |
|
|
Future<void> searchClients(String query) async { |
|
|
if (query.length < 2) { |
|
|
if (query.length < 2) { |
|
|
suggestedClients.clear(); |
|
|
suggestedClients.clear(); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
isSearching.value = true; |
|
|
isSearching.value = true; |
|
|
try { |
|
|
try { |
|
|
final clients = await AppDatabase.instance.suggestClients(query); |
|
|
final clients = await AppDatabase.instance.suggestClients(query); |
|
|
@ -48,7 +47,7 @@ class ClientFormController extends GetxController { |
|
|
isSearching.value = false; |
|
|
isSearching.value = false; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Méthode pour remplir automatiquement le formulaire |
|
|
// Méthode pour remplir automatiquement le formulaire |
|
|
void fillFormWithClient(Client client) { |
|
|
void fillFormWithClient(Client client) { |
|
|
selectedClient.value = client; |
|
|
selectedClient.value = client; |
|
|
@ -59,7 +58,7 @@ class ClientFormController extends GetxController { |
|
|
_adresseController.text = client.adresse ?? ''; |
|
|
_adresseController.text = client.adresse ?? ''; |
|
|
suggestedClients.clear(); |
|
|
suggestedClients.clear(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Méthode pour vider le formulaire |
|
|
// Méthode pour vider le formulaire |
|
|
void clearForm() { |
|
|
void clearForm() { |
|
|
selectedClient.value = null; |
|
|
selectedClient.value = null; |
|
|
@ -70,14 +69,14 @@ class ClientFormController extends GetxController { |
|
|
_adresseController.clear(); |
|
|
_adresseController.clear(); |
|
|
suggestedClients.clear(); |
|
|
suggestedClients.clear(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Méthode pour valider et soumettre |
|
|
// Méthode pour valider et soumettre |
|
|
Future<void> submitForm() async { |
|
|
Future<void> submitForm() async { |
|
|
if (!_formKey.currentState!.validate()) return; |
|
|
if (!_formKey.currentState!.validate()) return; |
|
|
|
|
|
|
|
|
try { |
|
|
try { |
|
|
Client clientToUse; |
|
|
Client clientToUse; |
|
|
|
|
|
|
|
|
if (selectedClient.value != null) { |
|
|
if (selectedClient.value != null) { |
|
|
// Utiliser le client existant |
|
|
// Utiliser le client existant |
|
|
clientToUse = selectedClient.value!; |
|
|
clientToUse = selectedClient.value!; |
|
|
@ -88,17 +87,18 @@ class ClientFormController extends GetxController { |
|
|
prenom: _prenomController.text.trim(), |
|
|
prenom: _prenomController.text.trim(), |
|
|
email: _emailController.text.trim(), |
|
|
email: _emailController.text.trim(), |
|
|
telephone: _telephoneController.text.trim(), |
|
|
telephone: _telephoneController.text.trim(), |
|
|
adresse: _adresseController.text.trim().isEmpty ? null : _adresseController.text.trim(), |
|
|
adresse: _adresseController.text.trim().isEmpty |
|
|
|
|
|
? null |
|
|
|
|
|
: _adresseController.text.trim(), |
|
|
dateCreation: DateTime.now(), |
|
|
dateCreation: DateTime.now(), |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
clientToUse = await AppDatabase.instance.createOrGetClient(newClient); |
|
|
clientToUse = await AppDatabase.instance.createOrGetClient(newClient); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Procéder avec la commande |
|
|
// Procéder avec la commande |
|
|
Get.back(); |
|
|
Get.back(); |
|
|
_submitOrderWithClient(clientToUse); |
|
|
_submitOrderWithClient(clientToUse); |
|
|
|
|
|
|
|
|
} catch (e) { |
|
|
} catch (e) { |
|
|
Get.snackbar( |
|
|
Get.snackbar( |
|
|
'Erreur', |
|
|
'Erreur', |
|
|
@ -108,7 +108,7 @@ class ClientFormController extends GetxController { |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void _submitOrderWithClient(Client client) { |
|
|
void _submitOrderWithClient(Client client) { |
|
|
// Votre logique existante pour soumettre la commande |
|
|
// Votre logique existante pour soumettre la commande |
|
|
// avec le client fourni |
|
|
// avec le client fourni |
|
|
@ -116,9 +116,10 @@ class ClientFormController extends GetxController { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Widget pour le formulaire avec auto-completion |
|
|
// Widget pour le formulaire avec auto-completion |
|
|
|
|
|
// ignore: unused_element |
|
|
void _showClientFormDialog() { |
|
|
void _showClientFormDialog() { |
|
|
final controller = Get.put(ClientFormController()); |
|
|
final controller = Get.put(ClientFormController()); |
|
|
|
|
|
|
|
|
Get.dialog( |
|
|
Get.dialog( |
|
|
AlertDialog( |
|
|
AlertDialog( |
|
|
title: Row( |
|
|
title: Row( |
|
|
@ -155,7 +156,7 @@ void _showClientFormDialog() { |
|
|
// Section de recherche rapide |
|
|
// Section de recherche rapide |
|
|
_buildSearchSection(controller), |
|
|
_buildSearchSection(controller), |
|
|
const SizedBox(height: 16), |
|
|
const SizedBox(height: 16), |
|
|
|
|
|
|
|
|
// Indicateur client sélectionné |
|
|
// Indicateur client sélectionné |
|
|
Obx(() { |
|
|
Obx(() { |
|
|
if (controller.selectedClient.value != null) { |
|
|
if (controller.selectedClient.value != null) { |
|
|
@ -168,7 +169,8 @@ void _showClientFormDialog() { |
|
|
), |
|
|
), |
|
|
child: Row( |
|
|
child: Row( |
|
|
children: [ |
|
|
children: [ |
|
|
Icon(Icons.check_circle, color: Colors.green.shade600), |
|
|
Icon(Icons.check_circle, |
|
|
|
|
|
color: Colors.green.shade600), |
|
|
const SizedBox(width: 8), |
|
|
const SizedBox(width: 8), |
|
|
Expanded( |
|
|
Expanded( |
|
|
child: Text( |
|
|
child: Text( |
|
|
@ -186,12 +188,13 @@ void _showClientFormDialog() { |
|
|
return const SizedBox.shrink(); |
|
|
return const SizedBox.shrink(); |
|
|
}), |
|
|
}), |
|
|
const SizedBox(height: 12), |
|
|
const SizedBox(height: 12), |
|
|
|
|
|
|
|
|
// Champs du formulaire |
|
|
// Champs du formulaire |
|
|
_buildTextFormField( |
|
|
_buildTextFormField( |
|
|
controller: controller._nomController, |
|
|
controller: controller._nomController, |
|
|
label: 'Nom', |
|
|
label: 'Nom', |
|
|
validator: (value) => value?.isEmpty ?? true ? 'Veuillez entrer un nom' : null, |
|
|
validator: (value) => |
|
|
|
|
|
value?.isEmpty ?? true ? 'Veuillez entrer un nom' : null, |
|
|
onChanged: (value) { |
|
|
onChanged: (value) { |
|
|
if (controller.selectedClient.value != null) { |
|
|
if (controller.selectedClient.value != null) { |
|
|
controller.selectedClient.value = null; |
|
|
controller.selectedClient.value = null; |
|
|
@ -199,11 +202,13 @@ void _showClientFormDialog() { |
|
|
}, |
|
|
}, |
|
|
), |
|
|
), |
|
|
const SizedBox(height: 12), |
|
|
const SizedBox(height: 12), |
|
|
|
|
|
|
|
|
_buildTextFormField( |
|
|
_buildTextFormField( |
|
|
controller: controller._prenomController, |
|
|
controller: controller._prenomController, |
|
|
label: 'Prénom', |
|
|
label: 'Prénom', |
|
|
validator: (value) => value?.isEmpty ?? true ? 'Veuillez entrer un prénom' : null, |
|
|
validator: (value) => value?.isEmpty ?? true |
|
|
|
|
|
? 'Veuillez entrer un prénom' |
|
|
|
|
|
: null, |
|
|
onChanged: (value) { |
|
|
onChanged: (value) { |
|
|
if (controller.selectedClient.value != null) { |
|
|
if (controller.selectedClient.value != null) { |
|
|
controller.selectedClient.value = null; |
|
|
controller.selectedClient.value = null; |
|
|
@ -211,14 +216,16 @@ void _showClientFormDialog() { |
|
|
}, |
|
|
}, |
|
|
), |
|
|
), |
|
|
const SizedBox(height: 12), |
|
|
const SizedBox(height: 12), |
|
|
|
|
|
|
|
|
_buildTextFormField( |
|
|
_buildTextFormField( |
|
|
controller: controller._emailController, |
|
|
controller: controller._emailController, |
|
|
label: 'Email', |
|
|
label: 'Email', |
|
|
keyboardType: TextInputType.emailAddress, |
|
|
keyboardType: TextInputType.emailAddress, |
|
|
validator: (value) { |
|
|
validator: (value) { |
|
|
if (value?.isEmpty ?? true) return 'Veuillez entrer un email'; |
|
|
// if (value?.isEmpty ?? true) return 'Veuillez entrer un email'; |
|
|
if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value!)) { |
|
|
if (value?.isEmpty ?? true) return null; |
|
|
|
|
|
if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$') |
|
|
|
|
|
.hasMatch(value!)) { |
|
|
return 'Email invalide'; |
|
|
return 'Email invalide'; |
|
|
} |
|
|
} |
|
|
return null; |
|
|
return null; |
|
|
@ -232,12 +239,14 @@ void _showClientFormDialog() { |
|
|
}, |
|
|
}, |
|
|
), |
|
|
), |
|
|
const SizedBox(height: 12), |
|
|
const SizedBox(height: 12), |
|
|
|
|
|
|
|
|
_buildTextFormField( |
|
|
_buildTextFormField( |
|
|
controller: controller._telephoneController, |
|
|
controller: controller._telephoneController, |
|
|
label: 'Téléphone', |
|
|
label: 'Téléphone', |
|
|
keyboardType: TextInputType.phone, |
|
|
keyboardType: TextInputType.phone, |
|
|
validator: (value) => value?.isEmpty ?? true ? 'Veuillez entrer un téléphone' : null, |
|
|
validator: (value) => value?.isEmpty ?? true |
|
|
|
|
|
? 'Veuillez entrer un téléphone' |
|
|
|
|
|
: null, |
|
|
onChanged: (value) { |
|
|
onChanged: (value) { |
|
|
if (controller.selectedClient.value != null) { |
|
|
if (controller.selectedClient.value != null) { |
|
|
controller.selectedClient.value = null; |
|
|
controller.selectedClient.value = null; |
|
|
@ -247,12 +256,14 @@ void _showClientFormDialog() { |
|
|
}, |
|
|
}, |
|
|
), |
|
|
), |
|
|
const SizedBox(height: 12), |
|
|
const SizedBox(height: 12), |
|
|
|
|
|
|
|
|
_buildTextFormField( |
|
|
_buildTextFormField( |
|
|
controller: controller._adresseController, |
|
|
controller: controller._adresseController, |
|
|
label: 'Adresse', |
|
|
label: 'Adresse', |
|
|
maxLines: 2, |
|
|
maxLines: 2, |
|
|
validator: (value) => value?.isEmpty ?? true ? 'Veuillez entrer une adresse' : null, |
|
|
validator: (value) => value?.isEmpty ?? true |
|
|
|
|
|
? 'Veuillez entrer une adresse' |
|
|
|
|
|
: null, |
|
|
onChanged: (value) { |
|
|
onChanged: (value) { |
|
|
if (controller.selectedClient.value != null) { |
|
|
if (controller.selectedClient.value != null) { |
|
|
controller.selectedClient.value = null; |
|
|
controller.selectedClient.value = null; |
|
|
@ -260,9 +271,9 @@ void _showClientFormDialog() { |
|
|
}, |
|
|
}, |
|
|
), |
|
|
), |
|
|
const SizedBox(height: 12), |
|
|
const SizedBox(height: 12), |
|
|
|
|
|
|
|
|
_buildCommercialDropdown(), |
|
|
_buildCommercialDropdown(), |
|
|
|
|
|
|
|
|
// Liste des suggestions |
|
|
// Liste des suggestions |
|
|
Obx(() { |
|
|
Obx(() { |
|
|
if (controller.isSearching.value) { |
|
|
if (controller.isSearching.value) { |
|
|
@ -271,11 +282,11 @@ void _showClientFormDialog() { |
|
|
child: Center(child: CircularProgressIndicator()), |
|
|
child: Center(child: CircularProgressIndicator()), |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (controller.suggestedClients.isEmpty) { |
|
|
if (controller.suggestedClients.isEmpty) { |
|
|
return const SizedBox.shrink(); |
|
|
return const SizedBox.shrink(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return Column( |
|
|
return Column( |
|
|
crossAxisAlignment: CrossAxisAlignment.start, |
|
|
crossAxisAlignment: CrossAxisAlignment.start, |
|
|
children: [ |
|
|
children: [ |
|
|
@ -288,8 +299,9 @@ void _showClientFormDialog() { |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
const SizedBox(height: 8), |
|
|
const SizedBox(height: 8), |
|
|
...controller.suggestedClients.map((client) => |
|
|
...controller.suggestedClients.map( |
|
|
_buildClientSuggestionTile(client, controller), |
|
|
(client) => |
|
|
|
|
|
_buildClientSuggestionTile(client, controller), |
|
|
), |
|
|
), |
|
|
], |
|
|
], |
|
|
); |
|
|
); |
|
|
@ -349,7 +361,8 @@ Widget _buildSearchSection(ClientFormController controller) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Widget pour afficher une suggestion de client |
|
|
// Widget pour afficher une suggestion de client |
|
|
Widget _buildClientSuggestionTile(Client client, ClientFormController controller) { |
|
|
Widget _buildClientSuggestionTile( |
|
|
|
|
|
Client client, ClientFormController controller) { |
|
|
return Card( |
|
|
return Card( |
|
|
margin: const EdgeInsets.only(bottom: 8), |
|
|
margin: const EdgeInsets.only(bottom: 8), |
|
|
child: ListTile( |
|
|
child: ListTile( |
|
|
@ -414,4 +427,4 @@ Widget _buildTextFormField({ |
|
|
Widget _buildCommercialDropdown() { |
|
|
Widget _buildCommercialDropdown() { |
|
|
// Votre implémentation existante |
|
|
// Votre implémentation existante |
|
|
return Container(); // Remplacez par votre code existant |
|
|
return Container(); // Remplacez par votre code existant |
|
|
} |
|
|
} |
|
|
|