diff --git a/lib/core/services/api_service.dart b/lib/core/services/api_service.dart index 96b2252..d6cc8e1 100644 --- a/lib/core/services/api_service.dart +++ b/lib/core/services/api_service.dart @@ -923,7 +923,7 @@ class ApiService { final roleTrimmed = role?.trim(); final fileIdTrimmed = fileId?.trim(); final endpoint = Uri.parse('${Env.apiUrl}grid'); - // final endpoint = Uri.parse('http://localhost/nhance_partner_be/grid'); + final queryParameters = {}; if (roleTrimmed != null && roleTrimmed.isNotEmpty) { queryParameters['role'] = roleTrimmed; @@ -957,7 +957,7 @@ class ApiService { } final endpoint = Uri.parse('${Env.apiUrl}grid/download'); - // final endpoint = Uri.parse('http://localhost/nhance_partner_be/grid/download'); + final queryParameters = {}; void addQuery(String key, String? value) { @@ -1944,13 +1944,14 @@ class ApiService { dynamic url; print('fetchAGENTNameDropDown 1'); - // url = Uri.parse( - // '${Env.apiUrl}invoice/getAgentUnusedCommissionList?manager_id=$id', - // ); + url = Uri.parse( + '${Env.apiUrl}invoice/getAgentUnusedCommissionList?manager_id=$id', + ); // url = Uri.parse( // 'http://localhost/nhance_partner_be/invoice/getAgentUnusedCommissionList?manager_id=$id', // ); + print('fetchAGENTNameDropDown 2'); final headers = { 'Authorization': 'Bearer $_token' ?? '', @@ -2050,8 +2051,7 @@ class ApiService { // --------------------------------- PayOut Module---------------------------------------------- Future> getCommissionRateList(data) async { print("getCommissionRateList------- $data}"); - // final url = Uri.parse('${Env.apiUrl}/invoice/commission-rate-list'); - // final url = Uri.parse('http://localhost/nhance_partner_be/invoice/commission-rate-list'); + final url = Uri.parse('${Env.apiUrl}/invoice/commission-rate-list'); print("getCommissionRateList 1"); // final token = await getToken(); // Fetch token @@ -2078,7 +2078,6 @@ class ApiService { Future> getCreateOrUpdate(data) async { final url = Uri.parse('${Env.apiUrl}invoice/create-or-update'); - // final url = Uri.parse('http://localhost/nhance_partner_be/invoice/create-or-update'); // final token = await getToken(); // Fetch token @@ -2122,7 +2121,6 @@ class ApiService { } final url = Uri.parse('${Env.apiUrl}invoice/list'); - //final url = Uri.parse('http://localhost/nhance_partner_be/invoice/list'); final headers = { 'Authorization': 'Bearer $_token' ?? '', @@ -2188,7 +2186,6 @@ class ApiService { } final url = Uri.parse('${Env.apiUrl}invoice/add-payment'); - // final url = Uri.parse('http://localhost/nhance_partner_be/invoice/add-payment'); final headers = { 'Authorization': 'Bearer $_token', @@ -2206,7 +2203,6 @@ class ApiService { } final url = Uri.parse('${Env.apiUrl}invoice/utrDetails?invoice_id=$invoiceId'); - //final url = Uri.parse('http://localhost/nhance_partner_be/invoice/utrDetails?invoice_id=$invoiceId'); final headers = { 'Authorization': 'Bearer $_token' ?? '', @@ -2224,7 +2220,7 @@ class ApiService { } final url = Uri.parse('${Env.apiUrl}invoice/updateUtrDetails'); - // final url = Uri.parse('http://localhost/nhance_partner_be/invoice/updateUtrDetails'); + final headers = { 'Authorization': 'Bearer $_token', 'Content-Type': 'application/json', @@ -2242,9 +2238,6 @@ class ApiService { final url = Uri.parse( '${Env.apiUrl}invoice/add-payment-history?invoice_id=$invoiceId', ); - // final url = Uri.parse( - // 'http://localhost/nhance_partner_be/invoice/add-payment-history?invoice_id=$invoiceId', - // ); final headers = { 'Authorization': 'Bearer $_token' ?? '', @@ -2262,9 +2255,7 @@ class ApiService { final url = Uri.parse( '${Env.apiUrl}invoice/listUtrDetails?invoice_id=$invoiceId', ); - // final url = Uri.parse( - // 'http://localhost/nhance_partner_be/invoice/listUtrDetails?invoice_id=$invoiceId', - // ); + final headers = { 'Authorization': 'Bearer $_token' ?? '', 'app-signature': Env.App_Signature, @@ -2485,7 +2476,6 @@ class ApiService { Future> updatePolicyCommissionApi(data) async { final url = Uri.parse('${Env.apiUrl}policy/updatePolicyCommission'); - //final url = Uri.parse('http://localhost/nhance_partner_be/policy/updatePolicyCommission'); if (_token == null) { throw Exception('Token not found. Please log in.'); diff --git a/lib/presentation/screens/payout/payout_details.dart b/lib/presentation/screens/payout/payout_details.dart index d5480bf..619b126 100644 --- a/lib/presentation/screens/payout/payout_details.dart +++ b/lib/presentation/screens/payout/payout_details.dart @@ -614,11 +614,19 @@ class _PayOutDetailsState extends ConsumerState { } String _normalizePolicyNo(dynamic value) { - return (value ?? '') - .toString() - .trim() - .toLowerCase() - .replaceAll(RegExp(r'\s+'), ''); + var text = (value ?? '').toString().trim(); + if (text.isEmpty) return ''; + + // Remove common Excel text-protection wrappers around policy number. + text = text.replaceAll(RegExp(r"^[`']+"), '').replaceAll(RegExp(r"[`']+$"), ''); + + // Excel often turns large integer-looking values into "12345.0". + final trailingPointZero = RegExp(r'^(\d+)\.0+$').firstMatch(text); + if (trailingPointZero != null) { + text = trailingPointZero.group(1) ?? text; + } + + return text.toLowerCase().replaceAll(RegExp(r'\s+'), ''); } String _displayText(dynamic value) { @@ -638,6 +646,37 @@ class _PayOutDetailsState extends ConsumerState { return double.tryParse(cleaned); } + PlatformFile? _buildSanitizedCommissionUploadFile( + List> rows, + ) { + if (rows.isEmpty) return null; + final excelOut = Excel.createExcel(); + final defaultSheet = excelOut.getDefaultSheet(); + final sheet = excelOut[defaultSheet ?? 'Sheet1']; + + sheet.appendRow([ + TextCellValue('Agent Code'), + TextCellValue('Policy Number'), + TextCellValue('Payout Amount'), + ]); + + for (final row in rows) { + sheet.appendRow([ + TextCellValue((row['agent_code'] ?? '').trim()), + TextCellValue((row['policy_no'] ?? '').trim()), + TextCellValue((row['payout_amount'] ?? '').trim()), + ]); + } + + final bytes = excelOut.encode(); + if (bytes == null || bytes.isEmpty) return null; + return PlatformFile( + name: 'policy_commission_upload_cleaned.xlsx', + size: bytes.length, + bytes: Uint8List.fromList(bytes), + ); + } + List> _buildUtrPayloadForSelectedPolicies({ required String defaultUtrDate, }) { @@ -910,19 +949,36 @@ class _PayOutDetailsState extends ConsumerState { return; } + int headerRowIndex = -1; int policyNoCol = -1; int commissionCol = -1; int agentCodeCol = -1; - for (int i = 0; i < rows.first.length; i++) { - final normalized = _normalizeHeader(_excelCellValue(rows.first[i])); - if (normalized == 'policynumber') policyNoCol = i; - if (normalized == 'payoutamount' || normalized == 'commissionamount') commissionCol = i; - if (normalized == 'agentcode') agentCodeCol = i; + final int headerScanLimit = rows.length < 5 ? rows.length : 5; + for (int r = 0; r < headerScanLimit; r++) { + int pCol = -1; + int cCol = -1; + int aCol = -1; + final currentRow = rows[r]; + for (int i = 0; i < currentRow.length; i++) { + final normalized = _normalizeHeader(_excelCellValue(currentRow[i])); + if (normalized == 'policynumber') pCol = i; + if (normalized == 'payoutamount' || normalized == 'commissionamount') { + cCol = i; + } + if (normalized == 'agentcode') aCol = i; + } + if (pCol != -1 && cCol != -1) { + headerRowIndex = r; + policyNoCol = pCol; + commissionCol = cCol; + agentCodeCol = aCol; + break; + } } if (policyNoCol == -1 || commissionCol == -1) { ToastHelper.showWarningToast( context, - 'Excel is missing required columns: Policy Number and Payout Amount.', + 'Excel header not found. Required columns: Policy Number and Payout Amount.', ); return; } @@ -930,8 +986,9 @@ class _PayOutDetailsState extends ConsumerState { final Map uploadMap = {}; final Map uploadPolicyDisplay = {}; final Map uploadAgentCodeMap = {}; + final List> sanitizedRowsForUpload = []; int invalidRows = 0; - for (int rowIndex = 1; rowIndex < rows.length; rowIndex++) { + for (int rowIndex = headerRowIndex + 1; rowIndex < rows.length; rowIndex++) { final row = rows[rowIndex]; final policyRaw = row.length > policyNoCol ? _excelCellValue(row[policyNoCol]) : ''; final commissionRaw = row.length > commissionCol ? _excelCellValue(row[commissionCol]) : ''; @@ -954,6 +1011,11 @@ class _PayOutDetailsState extends ConsumerState { if (agentCodeRaw.trim().isNotEmpty) { uploadAgentCodeMap[normalizedPolicy] = agentCodeRaw.trim().toUpperCase(); } + sanitizedRowsForUpload.add({ + 'agent_code': agentCodeRaw.trim().toUpperCase(), + 'policy_no': policyRaw.trim(), + 'payout_amount': parsedCommission.toStringAsFixed(2), + }); } if (uploadMap.isEmpty) { @@ -1027,9 +1089,12 @@ class _PayOutDetailsState extends ConsumerState { } } + final sanitizedUploadFile = _buildSanitizedCommissionUploadFile( + sanitizedRowsForUpload, + ); final response = await apiService.uploadPolicyCommissionExcel( id: selectedAgentId!.first, - file: selectedFile, + file: sanitizedUploadFile ?? selectedFile, proceedPartnerMismatch: partnerMismatchCount > 0, ); if (response['status'] != 'success' && response['status'] != 200) {