From 001953fbd7c21145c111faff8985a502ca90f985 Mon Sep 17 00:00:00 2001 From: "sanjeev.p" Date: Mon, 16 Mar 2026 18:53:22 +0530 Subject: [PATCH] Fix_partner added in endorsement --- lib/core/services/api_service.dart | 2 - .../create_endorsement_dialog.dart | 216 +++++++++++++++++- .../endorsomentUpdateValidation.dart | 200 ++++++++++++++-- .../policy_claims_endros/endrosment.dart | 6 +- 4 files changed, 388 insertions(+), 36 deletions(-) diff --git a/lib/core/services/api_service.dart b/lib/core/services/api_service.dart index 8b7d3d4..f660c48 100644 --- a/lib/core/services/api_service.dart +++ b/lib/core/services/api_service.dart @@ -2088,8 +2088,6 @@ class ApiService { final url = Uri.parse( '${Env.apiUrl}reports/endorsement-excel?manager_id=$managerId', ); - - print('getPdfDownload endorsement-excel - $url'); await _initializeToken(); diff --git a/lib/presentation/screens/Enquiry/policy_claims_endros/create_endorsement_dialog.dart b/lib/presentation/screens/Enquiry/policy_claims_endros/create_endorsement_dialog.dart index 9a906d5..b1d4e06 100644 --- a/lib/presentation/screens/Enquiry/policy_claims_endros/create_endorsement_dialog.dart +++ b/lib/presentation/screens/Enquiry/policy_claims_endros/create_endorsement_dialog.dart @@ -91,6 +91,7 @@ class _CreateEndorsementDialogState bool isStartDateFocused = false; bool isEndDateFocused = false; bool isPaymentModeFocused = false; + bool isPartnerFocused = false; String policyFrom = "Internal"; String financialOrNonFinancial = "Yes"; @@ -131,6 +132,7 @@ class _CreateEndorsementDialogState String? selectedBroker; String? selectedEndorsementNo; // String? selectedInsuredName; + String? selectedPartner; String financialType = "Yes"; // 🔹 LISTS @@ -139,6 +141,10 @@ class _CreateEndorsementDialogState List> endorsementNoList = []; List> insuredNameList = []; + // Partner / Agent lists + List> getAgentData = []; + List> filteredAgentData = []; + PlatformFile? docUploadedEndorsFile; List> getEndrosmentType = []; @@ -180,6 +186,11 @@ class _CreateEndorsementDialogState "verification_status": verificationStatus, }; + // Add agent_id only when a Partner has been selected + if (selectedPartner != null && selectedPartner!.toString().isNotEmpty) { + data["agent_id"] = selectedPartner; + } + if (isInternal) { data.addAll({ "endorsement_no": endorsementNoController.text, @@ -239,28 +250,43 @@ class _CreateEndorsementDialogState 'endDate': TextEditingController(), }; + // ✅ FIX — move it inside Future.microtask, after providers are read Future.microtask(() async { managerId = ref.read(managerIdProvider); roleId = ref.read(userRoleProvider); userId = ref.read(userIdProvider); + // ✅ FIX: fallback to widget.managerId if provider returns null + final effectiveManagerId = managerId ?? widget.managerId; + + print("MID CED - $managerId | widget.managerId - ${widget.managerId} | effective - $effectiveManagerId"); + + // Set Internal/External flags AFTER state is confirmed + if (mounted) { + setState(() { + isInternal = selectedEndrosementPolicyFrom == 'Internal'; + isExternal = selectedEndrosementPolicyFrom == 'External'; + }); + } + if (userId != null) { - await getStaffList(managerId, userId, roleId); + await getStaffList(effectiveManagerId, userId, roleId); + } + + // ✅ FIX: always call getAgentList using effectiveManagerId, no null check skip + if (effectiveManagerId != null) { + await getAgentList(effectiveManagerId); + } else { + print("❌ getAgentList NOT called — both managerId and widget.managerId are null"); } }); - if(selectedEndrosementPolicyFrom == 'Internal'){ - - isInternal = true; - - } - - _initializeToken(); getEnroementType(); getBroker(); getPaymentMode(); getInsurerDetails(); + // getAgent(managerId); } @override @@ -406,11 +432,55 @@ class _CreateEndorsementDialogState print('Error: $e'); } finally { setState(() { - isLoading = true; + isLoading = false; }); } } + Future getAgentList(id) async { + print('getAgentList in create_endorsement_dialog.dart called with manager ID: $id'); + if (!mounted) return; + setState(() { + isLoading = true; + }); + + try { + final response = await apiService.fetchAgentNameDropDown(id); + print('getAgentList response: $response'); + + if (mounted && response['status'] == 'success' && response['data'] != null) { + setState(() { + getAgentData = List>.from(response['data']); + print('getAgentList successful. Data received for dropdown: $getAgentData'); + filteredAgentData = List.from(getAgentData); + }); + } else { + print('getAgentList failed or returned no data. Status: ${response['status']}'); + if (mounted) { + setState(() { + getAgentData = []; + filteredAgentData = []; + }); + } + } + } catch (e) { + print('Exception occurred in getAgentList: $e'); + if (mounted) { + setState(() { + getAgentData = []; + filteredAgentData = []; + }); + } + } finally { + if (mounted) { + setState(() { + isLoading = false; + }); + } + } + } + + Future getPolicyListSearchData(String val) async { setState(() { isLoading = true; @@ -523,7 +593,8 @@ class _CreateEndorsementDialogState isLoading = true; }); - final id = int.parse(managerId); + // ❌ DELETE THIS LINE ENTIRELY + // final id = int.parse(managerId); // FORCE BOTH VALUES TO STRING final String managerIdStr = managerId?.toString() ?? ''; final String roleStr = role?.toString() ?? ''; @@ -998,7 +1069,8 @@ class _CreateEndorsementDialogState children: [ Expanded(child: buildContactPersonField(context)), const SizedBox(width: 20), - Spacer(), + Expanded(child: buildPartnerDropdown(context)), + // Spacer(), // Expanded(child: buildPendingDaysField(context)), ], ), @@ -1831,6 +1903,18 @@ class _CreateEndorsementDialogState ); } + Widget buildPartnerField(context) { + return buildCommonTextField( + label: "Partner", + controller: contactPersonController, + isRequired: false, + isFocused: isContactPersonFocused, + onFocusChanged: (val) { + setState(() => isContactPersonFocused = val); + }, + ); + } + // Widget buildPendingDaysField(context) { // return buildCommonTextField( // label: "Pending Days", @@ -2327,7 +2411,7 @@ class _CreateEndorsementDialogState selectedItem: selectedItem, items: (f, i) => items, itemAsString: itemAsString, - compareFn: (item, s) => item['id'].toString() == s['id'].toString(), + compareFn: (item, s) => item['id']?.toString() == s['id']?.toString(), onChanged: onChanged, validator: (value) { @@ -2536,6 +2620,7 @@ class _CreateEndorsementDialogState } Widget buildBrokerDropdown(context) { + print("******"); Map? selectedItem = brokerList .where( @@ -2607,6 +2692,113 @@ class _CreateEndorsementDialogState ); } + Widget buildPartnerDropdown(BuildContext context) { + // ✅ FIX: find selected item by id match + Map? selectedItem = filteredAgentData.isEmpty + ? null + : filteredAgentData + .where( + (item) => item['id']?.toString() == selectedPartner?.toString(), + ) + .isNotEmpty + ? filteredAgentData.firstWhere( + (item) => + item['id']?.toString() == selectedPartner?.toString(), + ) + : null; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + "Partner", + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w500, + color: Color(0xFF374151), + ), + ), + const SizedBox(height: 8), + Container( + decoration: BoxDecoration(borderRadius: BorderRadius.circular(14)), + child: DropdownSearch>( + selectedItem: selectedItem, + items: (f, i) => filteredAgentData, + + // ✅ FIX: compare by id string — safe null guard + compareFn: (item, s) => + item['id']?.toString() == s['id']?.toString(), + + // ✅ FIX: use agent_name, fallback to name + itemAsString: (val) { + final code = val['agent_code']?.toString() ?? ''; + final name = val['agent_name']?.toString() ?? + val['name']?.toString() ?? + ''; + return code.isNotEmpty ? '$code - $name' : name; + }, + + onChanged: (val) { + if (val != null) { + setState(() { + selectedPartner = val['id']?.toString(); + }); + print('Partner selected: id=${val['id']}, name=${val['agent_name'] ?? val['name']}'); + } + }, + + onBeforePopupOpening: (val) async { + setState(() => isPartnerFocused = true); + return true; + }, + + popupProps: PopupProps.menu( + onDismissed: () => setState(() => isPartnerFocused = false), + showSearchBox: true, + ), + + decoratorProps: DropDownDecoratorProps( + decoration: InputDecoration( + filled: true, + fillColor: const Color(0xFFF9FAFB), + isDense: true, + contentPadding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 13, + ), + helperText: " ", + helperStyle: const TextStyle(height: 0.8), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide( + color: Color(0xFFE5E7EB), + width: 1.5, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide( + color: Color(0xFF0F766E), + width: 1.5, + ), + ), + errorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide(color: Colors.red, width: 1.5), + ), + focusedErrorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide(color: Colors.red, width: 1.5), + ), + errorStyle: const TextStyle(fontSize: 11, height: 1.3), + ), + ), + ), + ), + ], + ); + } + // ------------------- STyle --------------------------------- static final TextStyle _textStyle = TextStyle( diff --git a/lib/presentation/screens/Enquiry/policy_claims_endros/endorsomentUpdateValidation.dart b/lib/presentation/screens/Enquiry/policy_claims_endros/endorsomentUpdateValidation.dart index ddd3cb2..7c9c4a8 100644 --- a/lib/presentation/screens/Enquiry/policy_claims_endros/endorsomentUpdateValidation.dart +++ b/lib/presentation/screens/Enquiry/policy_claims_endros/endorsomentUpdateValidation.dart @@ -100,10 +100,13 @@ class _endorsomentValidationState extends ConsumerState { bool isStartDateFocused = false; bool isEndDateFocused = false; bool isPaymentModeFocused = false; + bool isPartnerFocused = false; String policyFrom = ""; String financialOrNonFinancial = ""; + String? selectedPartner; + bool isPolicyNumberReadOnly = true; PlatformFile? uploadedFile; @@ -151,6 +154,10 @@ class _endorsomentValidationState extends ConsumerState { List> endorsementNoList = []; List> insuredNameList = []; + // Partner / Agent lists + List> getAgentData = []; + List> filteredAgentData = []; + PlatformFile? docUploadedFile; PlatformFile? docUploadedEndorsFile; @@ -195,6 +202,11 @@ class _endorsomentValidationState extends ConsumerState { "status": lifecycleStatus, }; + // Add agent_id only when a Partner has been selected + if (selectedPartner != null && selectedPartner!.toString().isNotEmpty) { + data["agent_id"] = selectedPartner; + } + if (isInternal) { data.addAll({ "endorsement_no": endorsementNoController.text, @@ -268,8 +280,14 @@ class _endorsomentValidationState extends ConsumerState { roleId = ref.read(userRoleProvider); userId = ref.read(userIdProvider); + final effectiveManagerId = managerId ?? widget.managerId; + if (userId != null) { - await getStaffList(managerId, userId, roleId); + await getStaffList(effectiveManagerId, userId, roleId); + } + + if (effectiveManagerId != null) { + await getAgentList(effectiveManagerId); // ✅ wait for list to load } }); @@ -329,6 +347,7 @@ class _endorsomentValidationState extends ConsumerState { selectedEndorsement = item['endorsement_type']?.toString(); selectedEndrosementPolicyFrom = item['policy_from']; lifecycleStatus = item['status']; + selectedPartner = item['agent_id']?.toString(); financialType = item['financia_or_non_financial'] ?? "Yes"; @@ -369,32 +388,24 @@ class _endorsomentValidationState extends ConsumerState { } Future getPaymentMode() async { - print('getPaymentMode called'); - try { final response = await apiService.fetchMasterDropDown('PaymentMode'); - if (response['status'] == 200) { - print('getPaymentModeData - ${response['data']}'); setState(() { - getPaymentModeData = List>.from( - response['data'], - ); - print('API Data - $getPaymentModeData'); - + getPaymentModeData = List>.from(response['data']); filteredPaymentModeData = List.from(getPaymentModeData); - print('originalData - $filteredPaymentModeData'); + + // ✅ Re-apply selectedPaymentModeId AFTER list is loaded + final savedId = widget.item?['payment_mode_id']?.toString(); + if (savedId != null) { + selectedPaymentModeId = savedId; + } }); - } else { - getPaymentModeData = []; - filteredPaymentModeData = []; } } catch (e) { print('Exception occurred: $e'); } finally { - setState(() { - isLoading = false; - }); + setState(() => isLoading = false); } } @@ -455,6 +466,49 @@ class _endorsomentValidationState extends ConsumerState { } } + Future getAgentList(id) async { + print('getAgentList in endorsomentUpdateValidation.dart called with manager ID: $id'); + if (!mounted) return; + setState(() { + isLoading = true; + }); + + try { + final response = await apiService.fetchAgentNameDropDown(id); + print('getAgentList response: $response'); + + if (mounted && response['status'] == 'success' && response['data'] != null) { + setState(() { + getAgentData = List>.from(response['data']); + print('getAgentList successful. Data received for dropdown: $getAgentData'); + filteredAgentData = List.from(getAgentData); + }); + } else { + print('getAgentList failed or returned no data. Status: ${response['status']}'); + if (mounted) { + setState(() { + getAgentData = []; + filteredAgentData = []; + }); + } + } + } catch (e) { + print('Exception occurred in getAgentList: $e'); + if (mounted) { + setState(() { + getAgentData = []; + filteredAgentData = []; + }); + } + } finally { + if (mounted) { + setState(() { + isLoading = false; + }); + } + } + } + Future getPolicyListSearchData(String val) async { try { final response = await apiService.fetchPolicySearch(val); @@ -530,7 +584,7 @@ class _endorsomentValidationState extends ConsumerState { isLoading = true; }); - final id = int.parse(managerId); + // final id = int.parse(managerId); // FORCE BOTH VALUES TO STRING final String managerIdStr = managerId?.toString() ?? ''; final String roleStr = role?.toString() ?? ''; @@ -1225,7 +1279,8 @@ class _endorsomentValidationState extends ConsumerState { ), ), const SizedBox(width: 20), - Spacer(), + Expanded(child: buildPartnerDropdown(context)), + // Spacer(), // Expanded(child: buildPendingDaysField(context)), ], ), @@ -3209,6 +3264,113 @@ class _endorsomentValidationState extends ConsumerState { }, ); } + + Widget buildPartnerDropdown(BuildContext context) { + // ✅ FIX: find selected item by id match + Map? selectedItem = filteredAgentData.isEmpty + ? null + : filteredAgentData + .where( + (item) => item['id']?.toString() == selectedPartner?.toString(), + ) + .isNotEmpty + ? filteredAgentData.firstWhere( + (item) => + item['id']?.toString() == selectedPartner?.toString(), + ) + : null; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + "Partner", + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w500, + color: Color(0xFF374151), + ), + ), + const SizedBox(height: 8), + Container( + decoration: BoxDecoration(borderRadius: BorderRadius.circular(14)), + child: DropdownSearch>( + selectedItem: selectedItem, + items: (f, i) => filteredAgentData, + + // ✅ FIX: compare by id string — safe null guard + compareFn: (item, s) => + item['id']?.toString() == s['id']?.toString(), + + // ✅ FIX: use agent_name, fallback to name + itemAsString: (val) { + final code = val['agent_code']?.toString() ?? ''; + final name = val['name']?.toString() ?? + val['name']?.toString() ?? + ''; + return code.isNotEmpty ? '$code - $name' : name; + }, + + onChanged: (val) { + if (val != null) { + setState(() { + selectedPartner = val['id']?.toString(); + }); + print('Partner selected: id=${val['id']}, name=${val['agent_name'] ?? val['name']}'); + } + }, + + onBeforePopupOpening: (val) async { + setState(() => isPartnerFocused = true); + return true; + }, + + popupProps: PopupProps.menu( + onDismissed: () => setState(() => isPartnerFocused = false), + showSearchBox: true, + ), + + decoratorProps: DropDownDecoratorProps( + decoration: InputDecoration( + filled: true, + fillColor: const Color(0xFFF9FAFB), + isDense: true, + contentPadding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 13, + ), + helperText: " ", + helperStyle: const TextStyle(height: 0.8), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide( + color: Color(0xFFE5E7EB), + width: 1.5, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide( + color: Color(0xFF0F766E), + width: 1.5, + ), + ), + errorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide(color: Colors.red, width: 1.5), + ), + focusedErrorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide(color: Colors.red, width: 1.5), + ), + errorStyle: const TextStyle(fontSize: 11, height: 1.3), + ), + ), + ), + ), + ], + ); + } // ------------------- STyle --------------------------------- static final TextStyle _textStyle = TextStyle( diff --git a/lib/presentation/screens/Enquiry/policy_claims_endros/endrosment.dart b/lib/presentation/screens/Enquiry/policy_claims_endros/endrosment.dart index ff4e28c..9d84196 100644 --- a/lib/presentation/screens/Enquiry/policy_claims_endros/endrosment.dart +++ b/lib/presentation/screens/Enquiry/policy_claims_endros/endrosment.dart @@ -2210,7 +2210,7 @@ class endosementState extends ConsumerState { crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ - Text('Upload Revised Endorsement Document (PDF)', style: _dataBold), + Text('Upload Endorsement Document (PDF)', style: _dataBold), const SizedBox(height: 10), _buildEndorsementUploadField(item), ], @@ -2233,12 +2233,12 @@ class endosementState extends ConsumerState { mainAxisSize: MainAxisSize.min, children: [ // ── UPLOAD LABEL ────────────────────────────── - Text('Upload Revised Document', style: GoogleFonts.poppins(fontSize: 11, fontWeight: FontWeight.w500)), + Text('Upload Document', style: GoogleFonts.poppins(fontSize: 11, fontWeight: FontWeight.w500)), const SizedBox(height: 6), // ── UPLOAD FIELD ────────────────────────────── ThemedUploadField( - hintText: selectedFileNames ?? "Upload Revised Document", + hintText: selectedFileNames ?? "Upload Document", padHorizontal: 4, padVertical: 5, fontSZ: 11,