Fix_partner added in endorsement

This commit is contained in:
sanjeev.p 2026-03-16 18:53:22 +05:30
parent ae1abb3243
commit 001953fbd7
4 changed files with 388 additions and 36 deletions

View File

@ -2088,8 +2088,6 @@ class ApiService {
final url = Uri.parse( final url = Uri.parse(
'${Env.apiUrl}reports/endorsement-excel?manager_id=$managerId', '${Env.apiUrl}reports/endorsement-excel?manager_id=$managerId',
); );
print('getPdfDownload endorsement-excel - $url'); print('getPdfDownload endorsement-excel - $url');
await _initializeToken(); await _initializeToken();

View File

@ -91,6 +91,7 @@ class _CreateEndorsementDialogState
bool isStartDateFocused = false; bool isStartDateFocused = false;
bool isEndDateFocused = false; bool isEndDateFocused = false;
bool isPaymentModeFocused = false; bool isPaymentModeFocused = false;
bool isPartnerFocused = false;
String policyFrom = "Internal"; String policyFrom = "Internal";
String financialOrNonFinancial = "Yes"; String financialOrNonFinancial = "Yes";
@ -131,6 +132,7 @@ class _CreateEndorsementDialogState
String? selectedBroker; String? selectedBroker;
String? selectedEndorsementNo; String? selectedEndorsementNo;
// String? selectedInsuredName; // String? selectedInsuredName;
String? selectedPartner;
String financialType = "Yes"; String financialType = "Yes";
// 🔹 LISTS // 🔹 LISTS
@ -139,6 +141,10 @@ class _CreateEndorsementDialogState
List<Map<String, dynamic>> endorsementNoList = []; List<Map<String, dynamic>> endorsementNoList = [];
List<Map<String, dynamic>> insuredNameList = []; List<Map<String, dynamic>> insuredNameList = [];
// Partner / Agent lists
List<Map<String, dynamic>> getAgentData = [];
List<Map<String, dynamic>> filteredAgentData = [];
PlatformFile? docUploadedEndorsFile; PlatformFile? docUploadedEndorsFile;
List<Map<String, dynamic>> getEndrosmentType = []; List<Map<String, dynamic>> getEndrosmentType = [];
@ -180,6 +186,11 @@ class _CreateEndorsementDialogState
"verification_status": verificationStatus, "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) { if (isInternal) {
data.addAll({ data.addAll({
"endorsement_no": endorsementNoController.text, "endorsement_no": endorsementNoController.text,
@ -239,28 +250,43 @@ class _CreateEndorsementDialogState
'endDate': TextEditingController(), 'endDate': TextEditingController(),
}; };
// FIX move it inside Future.microtask, after providers are read
Future.microtask(() async { Future.microtask(() async {
managerId = ref.read(managerIdProvider); managerId = ref.read(managerIdProvider);
roleId = ref.read(userRoleProvider); roleId = ref.read(userRoleProvider);
userId = ref.read(userIdProvider); 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) { 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(); _initializeToken();
getEnroementType(); getEnroementType();
getBroker(); getBroker();
getPaymentMode(); getPaymentMode();
getInsurerDetails(); getInsurerDetails();
// getAgent(managerId);
} }
@override @override
@ -406,11 +432,55 @@ class _CreateEndorsementDialogState
print('Error: $e'); print('Error: $e');
} finally { } finally {
setState(() { setState(() {
isLoading = true; isLoading = false;
}); });
} }
} }
Future<void> 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<Map<String, dynamic>>.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<void> getPolicyListSearchData(String val) async { Future<void> getPolicyListSearchData(String val) async {
setState(() { setState(() {
isLoading = true; isLoading = true;
@ -523,7 +593,8 @@ class _CreateEndorsementDialogState
isLoading = true; isLoading = true;
}); });
final id = int.parse(managerId); // DELETE THIS LINE ENTIRELY
// final id = int.parse(managerId);
// FORCE BOTH VALUES TO STRING // FORCE BOTH VALUES TO STRING
final String managerIdStr = managerId?.toString() ?? ''; final String managerIdStr = managerId?.toString() ?? '';
final String roleStr = role?.toString() ?? ''; final String roleStr = role?.toString() ?? '';
@ -998,7 +1069,8 @@ class _CreateEndorsementDialogState
children: [ children: [
Expanded(child: buildContactPersonField(context)), Expanded(child: buildContactPersonField(context)),
const SizedBox(width: 20), const SizedBox(width: 20),
Spacer(), Expanded(child: buildPartnerDropdown(context)),
// Spacer(),
// Expanded(child: buildPendingDaysField(context)), // 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) { // Widget buildPendingDaysField(context) {
// return buildCommonTextField( // return buildCommonTextField(
// label: "Pending Days", // label: "Pending Days",
@ -2327,7 +2411,7 @@ class _CreateEndorsementDialogState
selectedItem: selectedItem, selectedItem: selectedItem,
items: (f, i) => items, items: (f, i) => items,
itemAsString: itemAsString, itemAsString: itemAsString,
compareFn: (item, s) => item['id'].toString() == s['id'].toString(), compareFn: (item, s) => item['id']?.toString() == s['id']?.toString(),
onChanged: onChanged, onChanged: onChanged,
validator: (value) { validator: (value) {
@ -2536,6 +2620,7 @@ class _CreateEndorsementDialogState
} }
Widget buildBrokerDropdown(context) { Widget buildBrokerDropdown(context) {
print("******");
Map<String, dynamic>? selectedItem = Map<String, dynamic>? selectedItem =
brokerList brokerList
.where( .where(
@ -2607,6 +2692,113 @@ class _CreateEndorsementDialogState
); );
} }
Widget buildPartnerDropdown(BuildContext context) {
// FIX: find selected item by id match
Map<String, dynamic>? 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<Map<String, dynamic>>(
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 --------------------------------- // ------------------- STyle ---------------------------------
static final TextStyle _textStyle = TextStyle( static final TextStyle _textStyle = TextStyle(

View File

@ -100,10 +100,13 @@ class _endorsomentValidationState extends ConsumerState<endorsomentValidation> {
bool isStartDateFocused = false; bool isStartDateFocused = false;
bool isEndDateFocused = false; bool isEndDateFocused = false;
bool isPaymentModeFocused = false; bool isPaymentModeFocused = false;
bool isPartnerFocused = false;
String policyFrom = ""; String policyFrom = "";
String financialOrNonFinancial = ""; String financialOrNonFinancial = "";
String? selectedPartner;
bool isPolicyNumberReadOnly = true; bool isPolicyNumberReadOnly = true;
PlatformFile? uploadedFile; PlatformFile? uploadedFile;
@ -151,6 +154,10 @@ class _endorsomentValidationState extends ConsumerState<endorsomentValidation> {
List<Map<String, dynamic>> endorsementNoList = []; List<Map<String, dynamic>> endorsementNoList = [];
List<Map<String, dynamic>> insuredNameList = []; List<Map<String, dynamic>> insuredNameList = [];
// Partner / Agent lists
List<Map<String, dynamic>> getAgentData = [];
List<Map<String, dynamic>> filteredAgentData = [];
PlatformFile? docUploadedFile; PlatformFile? docUploadedFile;
PlatformFile? docUploadedEndorsFile; PlatformFile? docUploadedEndorsFile;
@ -195,6 +202,11 @@ class _endorsomentValidationState extends ConsumerState<endorsomentValidation> {
"status": lifecycleStatus, "status": lifecycleStatus,
}; };
// Add agent_id only when a Partner has been selected
if (selectedPartner != null && selectedPartner!.toString().isNotEmpty) {
data["agent_id"] = selectedPartner;
}
if (isInternal) { if (isInternal) {
data.addAll({ data.addAll({
"endorsement_no": endorsementNoController.text, "endorsement_no": endorsementNoController.text,
@ -268,8 +280,14 @@ class _endorsomentValidationState extends ConsumerState<endorsomentValidation> {
roleId = ref.read(userRoleProvider); roleId = ref.read(userRoleProvider);
userId = ref.read(userIdProvider); userId = ref.read(userIdProvider);
final effectiveManagerId = managerId ?? widget.managerId;
if (userId != null) { 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<endorsomentValidation> {
selectedEndorsement = item['endorsement_type']?.toString(); selectedEndorsement = item['endorsement_type']?.toString();
selectedEndrosementPolicyFrom = item['policy_from']; selectedEndrosementPolicyFrom = item['policy_from'];
lifecycleStatus = item['status']; lifecycleStatus = item['status'];
selectedPartner = item['agent_id']?.toString();
financialType = item['financia_or_non_financial'] ?? "Yes"; financialType = item['financia_or_non_financial'] ?? "Yes";
@ -369,32 +388,24 @@ class _endorsomentValidationState extends ConsumerState<endorsomentValidation> {
} }
Future<void> getPaymentMode() async { Future<void> getPaymentMode() async {
print('getPaymentMode called');
try { try {
final response = await apiService.fetchMasterDropDown('PaymentMode'); final response = await apiService.fetchMasterDropDown('PaymentMode');
if (response['status'] == 200) { if (response['status'] == 200) {
print('getPaymentModeData - ${response['data']}');
setState(() { setState(() {
getPaymentModeData = List<Map<String, dynamic>>.from( getPaymentModeData = List<Map<String, dynamic>>.from(response['data']);
response['data'],
);
print('API Data - $getPaymentModeData');
filteredPaymentModeData = List.from(getPaymentModeData); 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) { } catch (e) {
print('Exception occurred: $e'); print('Exception occurred: $e');
} finally { } finally {
setState(() { setState(() => isLoading = false);
isLoading = false;
});
} }
} }
@ -455,6 +466,49 @@ class _endorsomentValidationState extends ConsumerState<endorsomentValidation> {
} }
} }
Future<void> 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<Map<String, dynamic>>.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<void> getPolicyListSearchData(String val) async { Future<void> getPolicyListSearchData(String val) async {
try { try {
final response = await apiService.fetchPolicySearch(val); final response = await apiService.fetchPolicySearch(val);
@ -530,7 +584,7 @@ class _endorsomentValidationState extends ConsumerState<endorsomentValidation> {
isLoading = true; isLoading = true;
}); });
final id = int.parse(managerId); // final id = int.parse(managerId);
// FORCE BOTH VALUES TO STRING // FORCE BOTH VALUES TO STRING
final String managerIdStr = managerId?.toString() ?? ''; final String managerIdStr = managerId?.toString() ?? '';
final String roleStr = role?.toString() ?? ''; final String roleStr = role?.toString() ?? '';
@ -1225,7 +1279,8 @@ class _endorsomentValidationState extends ConsumerState<endorsomentValidation> {
), ),
), ),
const SizedBox(width: 20), const SizedBox(width: 20),
Spacer(), Expanded(child: buildPartnerDropdown(context)),
// Spacer(),
// Expanded(child: buildPendingDaysField(context)), // Expanded(child: buildPendingDaysField(context)),
], ],
), ),
@ -3209,6 +3264,113 @@ class _endorsomentValidationState extends ConsumerState<endorsomentValidation> {
}, },
); );
} }
Widget buildPartnerDropdown(BuildContext context) {
// FIX: find selected item by id match
Map<String, dynamic>? 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<Map<String, dynamic>>(
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 --------------------------------- // ------------------- STyle ---------------------------------
static final TextStyle _textStyle = TextStyle( static final TextStyle _textStyle = TextStyle(

View File

@ -2210,7 +2210,7 @@ class endosementState extends ConsumerState<Endorsement> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text('Upload Revised Endorsement Document (PDF)', style: _dataBold), Text('Upload Endorsement Document (PDF)', style: _dataBold),
const SizedBox(height: 10), const SizedBox(height: 10),
_buildEndorsementUploadField(item), _buildEndorsementUploadField(item),
], ],
@ -2233,12 +2233,12 @@ class endosementState extends ConsumerState<Endorsement> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
// UPLOAD LABEL // 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), const SizedBox(height: 6),
// UPLOAD FIELD // UPLOAD FIELD
ThemedUploadField( ThemedUploadField(
hintText: selectedFileNames ?? "Upload Revised Document", hintText: selectedFileNames ?? "Upload Document",
padHorizontal: 4, padHorizontal: 4,
padVertical: 5, padVertical: 5,
fontSZ: 11, fontSZ: 11,