import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:generp/Notifiers/HomeScreenNotifier.dart'; import 'package:generp/services/api_calling.dart'; import 'package:generp/Utils/commonServices.dart'; import 'package:provider/provider.dart'; import '../../Models/commonModels/DistrictsResponse.dart'; import '../../Models/commonModels/EditCommonAccFormDetailsResponse.dart'; import '../../Models/commonModels/SubLocationsResponse.dart'; import '../../Models/financeModels/ValidateBankAccountDetailsResponse.dart'; import '../../Models/financeModels/ValidateGstNumResponse.dart'; import '../../Models/commonModels/commonAddAccountsViewResponse.dart'; class EditCommonAccountProvider extends ChangeNotifier { // --- Text controllers used by edit form (only required ones) --- final TextEditingController nameController = TextEditingController(); final TextEditingController mobileController = TextEditingController(); final TextEditingController addressController = TextEditingController(); final TextEditingController bankNameController = TextEditingController(); final TextEditingController branchNameController = TextEditingController(); final TextEditingController bankIfscCotroller = TextEditingController(); final TextEditingController bankHolderNameController = TextEditingController(); final TextEditingController gstNumberController = TextEditingController(); final TextEditingController bankAcNumberController = TextEditingController(); final TextEditingController bankUpiController = TextEditingController(); // contact person details (kept because your form uses them) final TextEditingController contactPersonController = TextEditingController(); // final TextEditingController contectPersonDesignationController = TextEditingController(); // final TextEditingController contectPersonAltMobController = TextEditingController(); // final TextEditingController contectPersonTeleController = TextEditingController(); final TextEditingController contectPersonMailController = TextEditingController(); // small search controllers for dropdown search widgets final TextEditingController stateSearchController = TextEditingController(); final TextEditingController districtSearchController = TextEditingController(); final TextEditingController subLocSearchController = TextEditingController(); // --- simple error strings for UI --- String? accountError; String? nameError; String? mobileError; String? stateError; String? districtError; String? localityError; String? addressError; String? gstNumberError; String? banknameError; String? bankBranchError; String? bankIFSCError; String? bankHolderNameError; String? bankAcNumberError; String? upiError; String? contactPersonError; String? desigantionError; String? altMobError; String? teleError; String? mailError; String? addMoreDetailsError; // --- dropdown lists (populated from addCommonAccountView API) --- List _accountTypes = []; List _states = []; List _districts = []; List _subLocations = []; // selection holders String? _selectedAccountType; States? _selectedState; Districts? _selectedDistricts; SubLocations? _selectedSubLocations; // IDs / values (strings) used when sending API String? _selectedStateID; String? _selectedDistrictID; String? _selectedSubLocID; // responses from validation APIs ValidateGstNumResponse? gstResponse; ValidateBankAccountDetailsResponse? bankResponse; commonAddAccountsViewResponse? commonResponse; // loading & submit state bool _isLoading = false; bool _isSubmitting = false; String? updateErrorMessage; // getters bool get isLoading => _isLoading; bool get isSubmitting => _isSubmitting; List get states => _states; List get districts => _districts; List get subLocations => _subLocations; String? get selectedAccountType => _selectedAccountType; States? get selectedState => _selectedState; Districts? get selectedDistricts => _selectedDistricts; SubLocations? get selectedSubLocations => _selectedSubLocations; String? get selectedStateID => _selectedStateID; String? get selectedDistrictId => _selectedDistrictID; String? get selectedSubLocID => _selectedSubLocID; bool _submitClicked = false; bool get submitClickced => _submitClicked; set submitClickced(bool value) { _submitClicked = value; notifyListeners(); } // --- setters that clear corresponding errors and notify --- set selectedAccountType(String? v) { _selectedAccountType = v; accountError = null; notifyListeners(); } set selectedState(States? v) { _selectedState = v; _selectedStateID = v?.id; stateError = null; // clear dependent district/subLocation when state changes _districts.clear(); _selectedDistricts = null; _selectedDistrictID = null; _subLocations.clear(); _selectedSubLocations = null; _selectedSubLocID = null; notifyListeners(); } set selectedDistricts(Districts? v) { _selectedDistricts = v; _selectedDistrictID = v?.id; districtError = null; _subLocations.clear(); _selectedSubLocations = null; _selectedSubLocID = null; notifyListeners(); } set selectedSubLocations(SubLocations? v) { _selectedSubLocations = v; _selectedSubLocID = v?.id; localityError = null; notifyListeners(); } set isLoading(bool v) { _isLoading = v; notifyListeners(); } EditCommonAccFormDetailsResponse? detailsListResponse; // LOAD ACCOUNT DETAILS + PREFILL ALL FIELDS // ========================================================== Future loadAccountDetailsForEdit( BuildContext context, String accountId, ) async { try { isLoading = true; notifyListeners(); final homeProv = Provider.of(context, listen: false); final data = await ApiCalling.commonAccountDetailsListAPI( homeProv.empId, homeProv.session, accountId, ); detailsListResponse =data; if (data == null || data.error != "0") { updateErrorMessage = data?.message ?? "Failed to load account details"; isLoading = false; notifyListeners(); return false; } // Expecting at least one account in the list; take the first. if (data.accountList == null || data.accountList!.isEmpty) { updateErrorMessage = "No account data returned"; isLoading = false; notifyListeners(); return false; } final acc = data.accountList!.first; // 1) PREFILL TEXT CONTROLLERS // --------------------------- nameController.text = acc.name ?? ""; mobileController.text = acc.mob1 ?? ""; addressController.text = acc.address ?? ""; bankNameController.text = acc.bankName ?? ""; branchNameController.text = acc.bankBranchName ?? ""; bankIfscCotroller.text = acc.bankIfscCode ?? ""; bankHolderNameController.text = acc.bankAccountHolderName ?? ""; bankAcNumberController.text = acc.bankAccountNumber ?? ""; bankUpiController.text = acc.bankUpiId ?? ""; gstNumberController.text = acc.gstNumber ?? ""; // contact person (if API has contact_name) contactPersonController.text = acc.contactName ?? ""; // Other contact fields in API aren't present — keep empty or preserve existing contectPersonMailController.text = acc.email ?? ""; // --------------------------- // 2) PREFILL ACCOUNT TYPE // --------------------------- selectedAccountType = acc.type; // --------------------------- // 3) LOAD DROPDOWNS (account types, states) // --------------------------- await addCommonAccountViewAPI(context); // --------------------------- // 4) SELECT STATE (by name) // --------------------------- if (acc.state != null && acc.state!.trim().isNotEmpty) { final matchState = _states.firstWhere( (s) => (s.name ?? "").toLowerCase() == acc.state!.trim().toLowerCase(), orElse: () => States(id: null, name: null), ); if (matchState.id != null) { // use setter so it clears errors and resets dependent lists selectedState = matchState; _selectedStateID = matchState.id; // load districts for this state await getDistrictAPI(context, matchState.id); } } // --------------------------- // 5) SELECT DISTRICT (by name) // --------------------------- if (acc.district != null && acc.district!.trim().isNotEmpty && _districts.isNotEmpty) { final matchDist = _districts.firstWhere( (d) => (d.district ?? "").toLowerCase() == acc.district!.trim().toLowerCase(), orElse: () => Districts(id: null, district: null), ); if (matchDist.id != null) { selectedDistricts = matchDist; _selectedDistrictID = matchDist.id; // load sub-localities for this district await getSubLocationAPI(context, matchDist.id); } } // --------------------------- // 6) SELECT SUB-LOCALITY (by name) // --------------------------- if (acc.subLocality != null && acc.subLocality!.trim().isNotEmpty && _subLocations.isNotEmpty) { final matchSub = _subLocations.firstWhere( (s) => (s.subLocality ?? "").toLowerCase() == acc.subLocality!.trim().toLowerCase(), orElse: () => SubLocations(id: null, subLocality: null), ); if (matchSub.id != null) { selectedSubLocations = matchSub; _selectedSubLocID = matchSub.id; } } // everything loaded isLoading = false; notifyListeners(); return true; } catch (e, s) { if (kDebugMode) debugPrint("loadAccountDetailsForEdit ERROR => $e\n$s"); updateErrorMessage = e.toString(); isLoading = false; notifyListeners(); return false; } } Future getDistrictAPI(context, stateID) async { try { var homeProv = Provider.of(context, listen: false); _districts.clear(); notifyListeners(); final data = await ApiCalling.commonAddAccountViewDistrictAPI( homeProv.empId, homeProv.session, stateID, ); if (data != null) { if (data.error == "0") { _districts = data.districts ?? []; notifyListeners(); } } } catch (e) { if (kDebugMode) debugPrint('getDistrictAPI error: $e'); } } Future getSubLocationAPI(context, districtID) async { try { var homeProv = Provider.of(context, listen: false); _subLocations.clear(); notifyListeners(); final data = await ApiCalling.commonAddAccountViewSubLocationAPI( homeProv.empId, homeProv.session, districtID, ); if (data != null) { if (data.error == "0") { _subLocations = data.subLocations ?? []; notifyListeners(); } } } catch (e) { if (kDebugMode) debugPrint('getSubLocationAPI error: $e'); } } // --- API: load data needed to populate dropdowns (account types, states) --- Future addCommonAccountViewAPI(BuildContext context) async { try { isLoading = true; var homeProv = Provider.of(context, listen: false); final data = await ApiCalling.commonAddAccountViewAPI(homeProv.empId, homeProv.session); _accountTypes.clear(); _states.clear(); if (data != null && data.error == "0") { _accountTypes = data.accountTypes ?? []; _states = data.states ?? []; commonResponse = data; } } catch (e) { if (kDebugMode) debugPrint('addCommonAccountViewAPI error: $e'); } finally { isLoading = false; notifyListeners(); } } // --- GST validation: calls API and sets gstResponse; returns true if valid --- Future validateGstNumber(String empId, String sessionId, String gstNumber) async { if (gstNumber.trim().isEmpty) { gstResponse = null; gstNumberError = null; notifyListeners(); return false; } try { isLoading = true; final response = await ApiCalling.validateGstNumberApi(empId, sessionId, gstNumber.trim()); gstResponse = response; if (response == null) { gstNumberError = "Failed to validate GST number"; notifyListeners(); return false; } if (response.error == "0") { gstNumberError = null; notifyListeners(); return true; } else { gstNumberError = response.message ?? "Invalid GST number"; notifyListeners(); return false; } } catch (e) { gstNumberError = "Error validating GST: ${e.toString()}"; if (kDebugMode) debugPrint('validateGstNumber error: $e'); notifyListeners(); return false; } finally { isLoading = false; notifyListeners(); } } // --- Bank validation: requires both account number and IFSC --- Future validateBankDetails(String empId, String sessionId, String accountNumber) async { final ifsc = bankIfscCotroller.text.trim(); final accList = detailsListResponse?.accountList!.first; if (accountNumber.trim().isEmpty || ifsc.isEmpty) { bankResponse = null; bankAcNumberError = null; bankIFSCError = null; bankNameController.text = ""; branchNameController.text = ""; bankHolderNameController.text = ""; bankNameController.text = accList?.bankName ?? ""; branchNameController.text = accList?.bankBranchName ?? ""; bankHolderNameController.text = accList?.bankAccountHolderName ?? ""; notifyListeners(); return false; } if (bankAcNumberController.text.isEmpty || bankIfscCotroller.text.isEmpty) { bankNameController.text = ""; branchNameController.text = ""; bankHolderNameController.text = ""; bankNameController.text = accList?.bankName ?? ""; branchNameController.text = accList?.bankBranchName ?? ""; bankHolderNameController.text = accList?.bankAccountHolderName ?? ""; notifyListeners(); return false; } final reg = RegExp(r'^[A-Za-z]{4}0[A-Za-z0-9]{6}$'); if (!reg.hasMatch(ifsc)) { bankIFSCError = "Invalid IFSC format"; notifyListeners(); return false; } try { isLoading = true; final response = await ApiCalling.validateBankAccountDetailsApi(empId, sessionId, accountNumber.trim(), ifsc); bankResponse = response; if (response == null) { bankAcNumberError = "Failed to validate bank account"; notifyListeners(); return false; } if (response.error == "0") { bankAcNumberError = null; bankIFSCError = null; notifyListeners(); return true; } else { bankAcNumberError = response.message ?? "Invalid account details"; notifyListeners(); return false; } } catch (e) { bankAcNumberError = "Error validating account: ${e.toString()}"; if (kDebugMode) debugPrint('validateBankDetails error: $e'); notifyListeners(); return false; } finally { isLoading = false; notifyListeners(); } } // --- Combines validation and applies response (autofill) for GST --- Future checkAndApplyGst(BuildContext context, String gstNumber) async { gstNumberError = null; notifyListeners(); final trimmed = gstNumber.trim(); if (trimmed.isEmpty) { gstResponse = null; gstNumberError = null; notifyListeners(); return; } try { isLoading = true; final homeProv = Provider.of(context, listen: false); final resp = await ApiCalling.validateGstNumberApi(homeProv.empId, homeProv.session, trimmed); gstResponse = resp; if (resp == null) { gstNumberError = "Failed to validate GST number"; notifyListeners(); return; } if (resp.error == "0") { // autofill address if available final apiAddress = (resp.address ?? "").trim(); final apiName = (resp.legalNameOfBusiness ?? "").trim(); if (apiAddress.isNotEmpty) { addressController.text = apiAddress; } // compare company name and set error if mismatch final enteredName = nameController.text.trim(); if (apiName.isNotEmpty && enteredName.isNotEmpty) { if (apiName.toLowerCase() != enteredName.toLowerCase()) { nameError = "Name Does not match with GST Legal Name : ('$apiName')."; } else { nameError = null; } } gstNumberError = null; notifyListeners(); return; } else { _submitClicked = false; gstNumberError = resp.message ?? "Invalid GST number"; notifyListeners(); return; } } catch (e) { gstNumberError = "Error validating GST"; if (kDebugMode) debugPrint("checkAndApplyGst error: $e"); notifyListeners(); return; } finally { isLoading = false; notifyListeners(); } } // --- Combines validation and applies response (autofill) for Bank --- Future checkAndApplyBank(BuildContext context, String accountNumber) async { bankAcNumberError = null; bankIFSCError = null; notifyListeners(); final acc = accountNumber.trim(); final ifsc = bankIfscCotroller.text.trim(); if (acc.isEmpty && ifsc.isEmpty) { bankResponse = null; bankAcNumberError = null; bankIFSCError = null; notifyListeners(); return; } // If account entered, IFSC required if (acc.isNotEmpty && ifsc.isEmpty) { bankIFSCError = "IFSC is required when account number is entered"; notifyListeners(); return; } // validate IFSC format final ifscReg = RegExp(r'^[A-Za-z]{4}0[A-Za-z0-9]{6}$'); if (ifsc.isNotEmpty && !ifscReg.hasMatch(ifsc)) { bankIFSCError = "Invalid IFSC format"; notifyListeners(); return; } if (acc.isNotEmpty && ifsc.isNotEmpty) { try { isLoading = true; final homeProv = Provider.of(context, listen: false); final resp = await ApiCalling.validateBankAccountDetailsApi(homeProv.empId, homeProv.session, acc, ifsc); bankResponse = resp; if (resp == null) { bankAcNumberError = "Failed to validate bank details"; notifyListeners(); return; } if (resp.error == "0") { // autofill bank fields from response bankNameController.text = resp.bankName ?? bankNameController.text; branchNameController.text = resp.branch ?? branchNameController.text; bankHolderNameController.text = resp.nameAtBank ?? bankHolderNameController.text; bankAcNumberError = null; bankIFSCError = null; banknameError = null; bankBranchError = null; bankHolderNameError = null; notifyListeners(); return; } else { bankAcNumberError = resp.message ?? "Invalid account details"; notifyListeners(); return; } } catch (e) { bankAcNumberError = "Error validating bank: ${e.toString()}"; if (kDebugMode) debugPrint("checkAndApplyBank error: $e"); notifyListeners(); return; } finally { isLoading = false; notifyListeners(); } } } // --- Re-compare company name with GST (UI calls this on name change) --- void recheckNameWithGst() { if (gstResponse == null) return; final apiName = (gstResponse?.legalNameOfBusiness ?? "").trim(); final enteredName = nameController.text.trim(); if (apiName.isNotEmpty && enteredName.isNotEmpty) { if (apiName.toLowerCase() != enteredName.toLowerCase()) { nameError = "Name Does not match with GST Legal Name : ('$apiName')."; } else { nameError = null; } } notifyListeners(); } Future checkInputsAPI(context, type, value) async { try { var homeProv = Provider.of(context, listen: false); final data = await ApiCalling.commonAddAccountCheckInputsAPI( homeProv.empId, homeProv.session, type, value, ); commonResponse =data; if (data != null) { if (data.error == "0") { nameError = null; mobileError = null; notifyListeners(); } else if (data.error == "1") { if (data.message?.contains("name already exists") ?? false) { nameError = data.message ?? ""; } else { mobileError = data.message ?? ""; } notifyListeners(); } } } catch (e) { if (kDebugMode) debugPrint('checkInputsAPI error: $e'); } } // --- Submit (update) API function (calls your existing commonUpdateAccountDetailsAPI) --- Future updateAccountDetailsAPIFunction( BuildContext context, { required String accId, required String name, required String mob1, String? mob2, String? tel, String? email, String? designation, String? address, String? state, String? district, String? subLocality, String? bankName, String? branchName, String? bankIfscCode, String? accHolderName, String? bankAccNumber, String? bankUpiId, }) async { try { _isSubmitting = true; updateErrorMessage = null; notifyListeners(); var prov = Provider.of(context, listen: false); final data = await ApiCalling.commonUpdateAccountDetailsAPI( prov.empId, prov.session, accId, name, mob1, mob2 ?? '', tel ?? '', email ?? '', designation ?? '', address ?? '', state ?? '', district ?? '', subLocality ?? '', bankName ?? '', branchName ?? '', bankIfscCode ?? '', accHolderName ?? '', bankAccNumber ?? '', bankUpiId ?? '', ); if (data == null) { updateErrorMessage = "No response from server"; _isSubmitting = false; notifyListeners(); return false; } if (data.error == "0" || data.error == 0) { toast(context, data.message ?? "Updated successfully"); _isSubmitting = false; notifyListeners(); return true; } else { updateErrorMessage = data.message ?? "Failed to update account"; _isSubmitting = false; notifyListeners(); return false; } } catch (e, s) { if (kDebugMode) debugPrint("updateAccountDetailsAPIFunction error: $e\n$s"); updateErrorMessage = e.toString(); _isSubmitting = false; notifyListeners(); return false; } } bool _isGstValidFormat(String gst) { gst = gst.trim().toUpperCase(); final reg = RegExp(r'^[0-3][0-9][A-Z]{5}[0-9]{4}[A-Z][1-9A-Z]Z[0-9A-Z]$'); return reg.hasMatch(gst); } // --- Simple validation (keeps same logic as your UI expects) --- bool validateStep1(BuildContext context) { accountError = null; nameError = null; mobileError = null; gstNumberError = null; contactPersonError = null; bool isValid = true; if (_selectedAccountType == null || _selectedAccountType!.isEmpty) { accountError = "Please select an Account"; isValid = false; } if (nameController.text.trim().isEmpty) { nameError = "Please Enter a Name"; isValid = false; } if(gstNumberController.text.trim().isNotEmpty){ final gst = gstNumberController.text.trim(); if (!_isGstValidFormat(gst)) { gstNumberError = "Invalid GST format";notifyListeners(); isValid = false; } } if(gstNumberController.text.isEmpty){ final accList = detailsListResponse?.accountList!.first; final gst = gstNumberController.text.trim(); addressController.text = accList?.address ?? ""; } if (nameError != null && nameError!.isNotEmpty) { isValid = false; } if (mobileController.text.trim().isNotEmpty && mobileController.text.length < 10) { mobileError = "Mobile Number should be 10 digits"; isValid = false; } if (mobileController.text.trim().isEmpty) { mobileError = "Please Enter Mobile Number"; isValid = false; } if (contactPersonController.text.trim().isEmpty) { contactPersonError = "Please Enter Contact Person Name"; isValid = false; } // GST vs name check if gstResponse present if (gstResponse != null) { final apiName = (gstResponse?.legalNameOfBusiness ?? "").trim(); final enteredName = nameController.text.trim(); if (apiName.isNotEmpty && enteredName.isNotEmpty) { if (apiName.toLowerCase() != enteredName.toLowerCase()) { nameError = "Company name does not match GST record ('$apiName')"; isValid = false; } else { nameError = null; } } } notifyListeners(); return isValid; } bool validateStep() { final accList = detailsListResponse?.accountList!.first; if (gstNumberController.text.isEmpty) { final gst = gstNumberController.text.trim(); addressController.text = accList?.address ?? ""; } notifyListeners(); return false; } bool validateStep3() { final accList = detailsListResponse?.accountList!.first; if (bankAcNumberController.text.isEmpty || bankIfscCotroller.text.isEmpty) { bankNameController.text = ""; branchNameController.text = ""; bankHolderNameController.text = ""; bankNameController.text = accList?.bankName ?? ""; branchNameController.text = accList?.bankBranchName ?? ""; bankHolderNameController.text = accList?.bankAccountHolderName ?? ""; notifyListeners(); return false; } bool isValid = true; // optional step — you commented it optional. Keep commented validations deactivated. _submitClicked = false; notifyListeners(); return isValid; } // Full form final validation before submit bool validatereceiptForm(BuildContext context) { // reset error holders accountError = null; nameError = null; mobileError = null; stateError = null; districtError = null; localityError = null; addressError = null; banknameError = null; gstNumberError = null; bankBranchError = null; bankIFSCError = null; bankHolderNameError = null; bankAcNumberError = null; upiError = null; contactPersonError = null; desigantionError = null; altMobError = null; teleError = null; mailError = null; bool isValid = true; if (_selectedAccountType == null || _selectedAccountType!.isEmpty) { accountError = "Please select an Account"; isValid = false; } if (nameController.text.trim().isEmpty) { nameError = "Please Enter a Name"; isValid = false; } if (mobileController.text.trim().isEmpty) { mobileError = "Please Enter Mobile Number"; isValid = false; } if (contactPersonController.text.trim().isEmpty) { contactPersonError = "Please Enter Contact Person Name"; isValid = false; } // GST check final apiName = (gstResponse?.legalNameOfBusiness ?? "").trim(); final enteredName = nameController.text.trim(); if (apiName.isNotEmpty && enteredName.isNotEmpty) { if (apiName.toLowerCase() != enteredName.toLowerCase()) { isValid = false; nameError = "Company name does not match GST record ('$apiName')"; } } notifyListeners(); return isValid; } // --- update helper setters to clear errors on edit --- void updateName(String value) { nameError = null; notifyListeners(); } void updateMobile(String value) { mobileError = null; notifyListeners(); } void updateAddress(String value) { addressError = null; notifyListeners(); } void updateBankName(String value) { banknameError = null; notifyListeners(); } void updateGSTNumber(String value) { gstNumberError = null; notifyListeners(); } void updateBankBranch(String value) { bankBranchError = null; notifyListeners(); } void updateIFSC(String value) { bankIFSCError = null; notifyListeners(); } void updateHolder(String value) { bankHolderNameError = null; notifyListeners(); } void updateNumber(String value) { bankAcNumberError = null; notifyListeners(); } void updateUPI(String value) { upiError = null; notifyListeners(); } void updateContactPerson(String value) { contactPersonError = null; notifyListeners(); } void updateDesignation(String value) { desigantionError = null; notifyListeners(); } void updateAltMobile(String value) { altMobError = null; notifyListeners(); } void updateTeleMobile(String value) { teleError = null; notifyListeners(); } void updateMail(String value) { mailError = null; notifyListeners(); } // --- Reset values used by Edit form (clears controllers + errors + selections) --- void resetValues() { _selectedAccountType = null; _selectedState = null; _selectedDistricts = null; _selectedSubLocations = null; _selectedStateID = null; _selectedDistrictID = null; _selectedSubLocID = null; gstResponse = null; bankResponse = null; commonResponse = null; updateErrorMessage = null; _isLoading = false; _isSubmitting = false; stateSearchController.clear(); districtSearchController.clear(); subLocSearchController.clear(); nameController.clear(); mobileController.clear(); addressController.clear(); bankNameController.clear(); branchNameController.clear(); bankIfscCotroller.clear(); bankHolderNameController.clear(); bankAcNumberController.clear(); bankUpiController.clear(); contactPersonController.clear(); contectPersonMailController.clear(); accountError = null; nameError = null; mobileError = null; stateError = null; districtError = null; localityError = null; addressError = null; banknameError = null; gstNumberError = null; bankBranchError = null; bankIFSCError = null; bankHolderNameError = null; bankAcNumberError = null; upiError = null; contactPersonError = null; desigantionError = null; altMobError = null; teleError = null; mailError = null; addMoreDetailsError = null; notifyListeners(); } // dispose controllers when provider is disposed (optional) @override void dispose() { nameController.dispose(); mobileController.dispose(); addressController.dispose(); bankNameController.dispose(); branchNameController.dispose(); bankIfscCotroller.dispose(); bankHolderNameController.dispose(); gstNumberController.dispose(); bankAcNumberController.dispose(); bankUpiController.dispose(); contactPersonController.dispose(); contectPersonMailController.dispose(); stateSearchController.dispose(); districtSearchController.dispose(); subLocSearchController.dispose(); super.dispose(); } }