diff --git a/app/Config/Routes.php b/app/Config/Routes.php
index 9996931c..cf545319 100755
--- a/app/Config/Routes.php
+++ b/app/Config/Routes.php
@@ -388,6 +388,10 @@ $routes->group("/util", ["filter" => "authMVC"], function ($routes) {
$routes->get("download_claim_dump_file/(:any)", "TicketController::downloadClaimDumpFile/$1");
$routes->post('uploadMultiFileFromRfq', 'LeadsController::uploadMultiFileFromRfq');
$routes->get('downloadMemberFile/(:any)', 'LeadsController::downloadMemberFile/$1');
+ $routes->get('downloadFullMemberDataExcelErrorFile/(:any)', 'LeadsController::downloadFullMemberDataExcelErrorFile/$1');
+ $routes->get('getMemberDataExcelFileErrors', 'LeadsController::getMemberDataExcelFileErrors');
+ $routes->post('savePlacementDataAndValidateMemberDataFile', 'LeadsController::savePlacementDataAndValidateMemberDataFile');
+ $routes->get('checkMemberDataFileValidationStatus', 'LeadsController::checkMemberDataFileValidationStatus');
});
$routes->post("policy_tranction/sendInstallmentRemainderMail","PolicyTransactionController::sendInstallmentRemainderMail");
@@ -700,6 +704,8 @@ $routes->group('test', function($routes) {
$routes->get('viewrfq', 'TestingController::viewRFQNonEb');
$routes->get('exportexcel', 'TestingController::exportExcel');
$routes->post('saverfq', 'TestingController::saverfq');
+ $routes->get('membervalidation', 'TestingController::membervalidation');
+ $routes->get('generateExcel', 'TestingController::generateExcel');
});
$routes->cli('cli/testcli', 'TestingController::testcli');
diff --git a/app/Controllers/JobWorker.php b/app/Controllers/JobWorker.php
index 1f322c84..50c9820b 100755
--- a/app/Controllers/JobWorker.php
+++ b/app/Controllers/JobWorker.php
@@ -167,6 +167,10 @@ class JobWorker extends AdminController
'type' => 'CC', // Handler Category
'handler' => 'App\Controllers\EmployeeMultiEventServiceController',
],
+ 'memberDataListExcelFileFormatValidation' => [
+ 'type' => 'CC', // Handler Category
+ 'handler' => 'App\Controllers\LeadsController',
+ ],
];
diff --git a/app/Controllers/LeadsController.php b/app/Controllers/LeadsController.php
index 308e7184..40afde50 100644
--- a/app/Controllers/LeadsController.php
+++ b/app/Controllers/LeadsController.php
@@ -81,11 +81,13 @@ class LeadsController extends BaseController
protected $claim_type_for_gpa;
protected $cause_of_death;
protected $buisnessType;
+ protected $member_data_excel_columns;
+ protected $general_relationships;
public function __construct()
{
- set_session_context('Leads');
+ set_session_context('LEAD CONTROLLER');
$this->myLogger = \Config\Services::mylogger();
$this->clientModel = new ClientModel();
@@ -138,6 +140,161 @@ class LeadsController extends BaseController
'suicide' => 'Suicide',
'accident' => 'Accident'
];
+
+ $this->member_data_excel_columns = [
+ 'sno' => [
+ 'col_idx' => 0,
+ 'col_cell_name' => 'A',
+ 'col_name' => 'Sl no',
+ 'is_mandatory' => false,
+ 'data_type' => 'str',
+ 'format' => null,
+ 'allowed_values' => null
+ ],
+ 'emp_code' => [
+ 'col_idx' => 1,
+ 'col_cell_name' => 'B',
+ 'col_name' => 'Emp Code',
+ 'is_mandatory' => true,
+ 'data_type' => 'str',
+ 'format' => null,
+ 'allowed_values' => null
+ ],
+ 'name' => [
+ 'col_idx' => 2,
+ 'col_cell_name' => 'C',
+ 'col_name' => 'Name',
+ 'is_mandatory' => true,
+ 'data_type' => 'str',
+ 'format' => null,
+ 'allowed_values' => null
+ ],
+ 'relationship' => [
+ 'col_idx' => 3,
+ 'col_cell_name' => 'D',
+ 'col_name' => 'Relationship',
+ 'is_mandatory' => true,
+ 'data_type' => 'str',
+ 'format' => null,
+ 'allowed_values' => [
+ 'Self', 'Spouse', 'Son', 'Daughter', 'Father', 'Mother',
+ 'Father-in-law', 'Mother-in-law',
+ 'self', 'spouse', 'son', 'daughter', 'father', 'mother',
+ 'father-in-law', 'mother-in-law'
+ ],
+ 'custom' => 'check_relationship_for_member_data',
+ 'params' => ['row', 'relationship', 'columns_to_check']
+ ],
+ 'gender' => [
+ 'col_idx' => 4,
+ 'col_cell_name' => 'E',
+ 'col_name' => 'Gender',
+ 'is_mandatory' => true,
+ 'data_type' => 'str',
+ 'format' => null,
+ 'allowed_values' => ['M', 'F']
+ ],
+ 'dob' => [
+ 'col_idx' => 5,
+ 'col_cell_name' => 'F',
+ 'col_name' => 'DOB',
+ 'is_mandatory' => true,
+ 'data_type' => 'str',
+ 'format' => 'd-M-Y',
+ 'allowed_values' => null,
+ 'age_validation' => true,
+ // 'custom' => 'check_dob_diff',
+ // 'params' => ['row', 'relationship', 'default_age_ratio', 'policy_details']
+ ],
+ 'age' => [
+ 'col_idx' => 6,
+ 'col_cell_name' => 'G',
+ 'col_name' => 'Age',
+ 'is_mandatory' => true,
+ 'data_type' => 'int',
+ 'format' => null,
+ 'allowed_values' => null
+ ],
+ 'email' => [
+ 'col_idx' => 7,
+ 'col_cell_name' => 'H',
+ 'col_name' => 'Email',
+ 'is_mandatory' => false,
+ 'data_type' => 'str',
+ 'format' => null,
+ 'allowed_values' => null
+ ],
+ 'mobile' => [
+ 'col_idx' => 8,
+ 'col_cell_name' => 'I',
+ 'col_name' => 'Mobile',
+ 'is_mandatory' => false,
+ 'data_type' => 'str',
+ 'format' => null,
+ 'allowed_values' => null
+ ],
+ 'si' => [
+ 'col_idx' => 9,
+ 'col_cell_name' => 'J',
+ 'col_name' => 'SI',
+ 'is_mandatory' => false,
+ 'data_type' => 'int',
+ 'format' => null,
+ 'allowed_values' => null,
+ ]
+ ];
+
+ $this->general_relationships = [
+ 'self' => [
+ 'name' => 'Self',
+ 'gender' => 'M',
+ 'age_min' => 18,
+ 'age_max' => null
+ ],
+ 'spouse' => [
+ 'name' => 'Spouse',
+ 'gender' => 'F',
+ 'age_min' => 18,
+ 'age_max' => null
+ ],
+ 'son' => [
+ 'name' => 'Son',
+ 'gender' => 'M',
+ 'age_min' => null,
+ 'age_max' => 25
+ ],
+ 'daughter' => [
+ 'name' => 'Daughter',
+ 'gender' => 'F',
+ 'age_min' => null,
+ 'age_max' => 25
+ ],
+ 'father' => [
+ 'name' => 'Father',
+ 'gender' => 'M',
+ 'age_min' => 18,
+ 'age_max' => null
+ ],
+ 'mother' => [
+ 'name' => 'Mother',
+ 'gender' => 'F',
+ 'age_min' => 18,
+ 'age_max' => null
+ ],
+ 'father-in-law' => [
+ 'name' => 'Father in Law',
+ 'gender' => 'M',
+ 'age_min' => 18,
+ 'age_max' => null
+ ],
+ 'mother-in-law' => [
+ 'name' => 'Mother in Law',
+ 'gender' => 'F',
+ 'age_min' => 18,
+ 'age_max' => null
+ ]
+ ];
+
}
public function viewLeadsList()
@@ -505,7 +662,7 @@ class LeadsController extends BaseController
if ($value['lead_form_type'] == 1) {
//for this push the job to the calculateMembersDemography() function
$job_details = new Jobs();
- $r = Jobs::addJob(['job_name' => 'calculateMembersDemography', 'payload' => [
+ $r = Jobs::addJob(['job_name' => 'memberDataListExcelFileFormatValidation', 'payload' => [
'lead_id' => $insert,
]]);
}
@@ -568,7 +725,11 @@ class LeadsController extends BaseController
// $data['premium_date'] = null;
// }
- $data['multi_file_data'] = $this->leadFilesModel->where('lead_id', $id)->first() ?? null;
+ $data['multi_file_data'] = $this->leadFilesModel
+ ->where('lead_id', $id)
+ ->where('type !=', 2)
+ ->where('is_active', 1)
+ ->first() ?? null;
$data['lastFiveYears'] = $this->getLastFiveFinancialYears();
$data['gpaClaimType'] = $this->claim_type_for_gpa;
@@ -645,7 +806,7 @@ class LeadsController extends BaseController
if (!empty($lead_form_type) && $lead_form_type == 1 && $key == 0) {
//for this push the job to the calculateMembersDemography() function
$job_details = new Jobs();
- $r = Jobs::addJob(['job_name' => 'calculateMembersDemography', 'payload' => [
+ $r = Jobs::addJob(['job_name' => 'memberDataListExcelFileFormatValidation', 'payload' => [
'lead_id' => $lead_id,
]]);
log_message('info', "calculateMembersDemography JOB PUSHED");
@@ -860,13 +1021,23 @@ class LeadsController extends BaseController
// 3. Optimize lead data query with specific field selection
$lead_data = $this->leadsModel
->select('
- leads.id, leads.policy_type_id, leads.lead_type, leads.source_policy_id,
- leads.policy_end_date, leads.lead_form_type, leads.created_by, leads.client_name,
- policy_type.question_json, policy_type.policy_type, policy_type.long_name,
- user_profiles.email as created_person_email
- ')
+ leads.id,
+ leads.policy_type_id,
+ leads.lead_type,
+ leads.source_policy_id,
+ leads.policy_end_date,
+ leads.lead_form_type,
+ leads.created_by,
+ leads.client_name,
+ lead_files.status as demography_file_status,
+ policy_type.question_json,
+ policy_type.policy_type,
+ policy_type.long_name,
+ user_profiles.email as created_person_email
+ ')
->join('policy_type', 'leads.policy_type_id = policy_type.id')
->join('user_profiles', 'leads.created_by = user_profiles.id', 'left')
+ ->join('lead_files', 'leads.id = lead_files.lead_id AND lead_files.type = 2 AND lead_files.is_active = 1', 'left')
->where('leads.id', $id)
->where('leads.is_active', 1)
->first();
@@ -930,6 +1101,7 @@ class LeadsController extends BaseController
// 10. Combine related queries
$data['multi_file_data'] = $this->leadFilesModel
->where('lead_id', $id)
+ ->where('type !=', 2)
->where('is_active', 1)
->findAll();
@@ -3047,7 +3219,6 @@ class LeadsController extends BaseController
'cd_amount' => $params['cd_amount'] ?? null,
'no_of_installment' => $params['no_of_installment'] ?? null,
'is_installment' => $params['is_installment'] ?? null,
- 'is_installment' => $params['is_installment'] ?? null,
'acm_id' => $params['acm_pk'] ?? null,
];
@@ -3609,6 +3780,13 @@ class LeadsController extends BaseController
$input_value = $cellData['input_value'] != "" ? $cellData['input_value'] : ($cellData['value'] ?? '');
$value = $cellData['value'] ?? '';
+ if( $item == "family_composition" && $subth == $insurer_name && $policy_type == 2){
+ $age_ratio_array = json_decode($input_value, true)['age_ratio'] ?? null;
+ if(!empty($age_ratio_array)){
+ $age_ratio = $age_ratio_array;
+ }
+ }
+
// Skip unwanted keys
if (in_array($parentth, ['Sno', 'Item Key', 'Particulars', 'Action']) || in_array($subth, ['Quote Asked'])) {
continue;
@@ -3770,7 +3948,6 @@ class LeadsController extends BaseController
return json_encode($placement_json_data);
}
-
//------------------------------------------------------------------------------------------------
@@ -3814,7 +3991,6 @@ class LeadsController extends BaseController
}
}
-
public function getLastFiveFinancialYears()
{
$currentYear = date('Y');
@@ -3878,7 +4054,11 @@ class LeadsController extends BaseController
$data['lead_edit_data'] = $this->leadsModel->where('id', $id)->first() ?? [];
- $data['lead_edit_data']['multi_file_data'] = $this->leadFilesModel->where('lead_id', $id)->where('is_active', 1)->findAll() ?? null;
+ $data['lead_edit_data']['multi_file_data'] = $this->leadFilesModel
+ ->where('lead_id', $id)
+ ->where('type !=', 2)
+ ->where('is_active', 1)
+ ->findAll() ?? null;
$data['lead_edit_data']['lead_file_count'] = count($data['lead_edit_data']['multi_file_data']);
// Decode and merge custom fields if present
@@ -5024,6 +5204,7 @@ class LeadsController extends BaseController
$lead_file = $this->leadFilesModel
->where('lead_id', $lead_id)
->where('id', $id)
+ ->where('type !=', 2)
->where('is_active', 1)
->first();
@@ -5061,7 +5242,6 @@ class LeadsController extends BaseController
return $attachments;
}
-
public function handleMemberDataGPATotalSumInsurerFromExcel($params)
{
$lead_id = $params['lead_id'];
@@ -5129,7 +5309,6 @@ class LeadsController extends BaseController
return [];
}
-
public function generateDemographyDataTable($param)
{
$returnData = $this->calculateMembersDemography($param, "internal");
@@ -5415,6 +5594,7 @@ class LeadsController extends BaseController
// Get the updated lead file data
$lead_file_data = $this->leadFilesModel
->where('is_active', 1)
+ ->where('type !=', 2)
->where('lead_id', $lead_id)
->findAll();
@@ -5455,8 +5635,7 @@ class LeadsController extends BaseController
}
}
-
- function renderFileFields($multi_file_data = [])
+ public function renderFileFields($multi_file_data = [])
{
$uploadFilePath = WRITEPATH . 'uploads/lead_files/';
$html = '';
@@ -5548,5 +5727,690 @@ class LeadsController extends BaseController
return $this->response->download($filePath, null);
}
+ // ----------- MEMBER DATA VALIDAATION ------------------------------------------------------------------------------------------------------
+
+ public function memberDataListValidation()
+ {
+ $lead_id = $this->request->getPost('lead_id');
+ $this->memberDataListExcelFileFormatValidation(['lead_id' => $lead_id]);
+ }
+
+ public function memberDataListExcelFileFormatValidation($params)
+ {
+ helper('excel_util_helper');
+
+ $this->myLogger->logme('error', 'Start memberDataListExcelFileFormatValidation');
+ $this->myLogger->logme('error', "Received params: " . json_encode($params));
+
+ $lead_id = $params['lead_id'];
+ $age_validation_check = $params['age_validation'] ?? null;
+ $lead_data = $this->leadsModel->where('id', $lead_id)->first();
+ // dd($lead_data);
+
+ $return = [];
+ if (!isset($lead_data)) {
+ $this->myLogger->logme('error', "Lead not found for lead_id: {$lead_id}");
+ $this->leadFilesModel->where('lead_id', $lead_id)->where('type', 2)->set(['status' => 'failed', 'error_data' => json_encode(['error_summary' => array_count_values([12]),'error_data' => 'file not found in DB'])])->update();
+ return array('status' => false, 'msg' => 'file not found in DB');
+ }
+
+ //get the lead files data
+ $lead_file_data = $this->leadFilesModel->where('is_active', 1)->where('type', 2)->first();
+
+ //check the lead file table has the error data entry if not than create new entry
+ if(empty($lead_file_data)){
+ $data['type'] = 2;
+ $data['file_name'] = $lead_data['file_name'];
+ $data['docs_name'] = "Member List";
+ $data['lead_id'] = $lead_id;
+ $lead_file_last_insert_id = $this->leadFilesModel->insert($data);
+ $this->myLogger->logme('error', "New lead file entry created for store the error data, insert_id : '{$lead_file_last_insert_id}'");
+ }
+
+ $family_composition = [];
+ if($age_validation_check && !empty($lead_data['proposel_data'])){
+ $family_composition = $this->getAgeRatioFromRfqJson($lead_id, $lead_data['proposel_data']);
+ $this->myLogger->logme('info', 'Family composition :',json_encode($family_composition));
+ }
+ // dd($family_composition);
+
+ // get the file path
+ $file_name_with_path = WRITEPATH . "/uploads/lead_files/" . $lead_data['file_name'];
+ $this->myLogger->logme('error', "File path: {$file_name_with_path}");
+
+ //check physical file
+ if (!file_exists($file_name_with_path)) {
+ //file not found update status and reason
+ $message = "Physcial file not found";
+ $this->myLogger->logme('error', ($message . ' for lead id ' . $lead_id));
+ $this->leadFilesModel
+ ->where('lead_id', $lead_id)
+ ->where('type', 2)
+ ->set(['status' => 'failed','error_data' => json_encode(['error_summary' => array_count_values([5]),'error_data' => $message])])
+ ->update();
+ return array('error_summary' => [5], 'error_data' => $message);
+ }
+
+ $this->myLogger->logme('info', 'File exists, starting validation process');
+
+ //start validation process
+ $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path);
+ $sheet = $spreadsheet->getActiveSheet();
+
+ $highestRowAndColumn = $sheet->getHighestRowAndColumn();
+ // dd($highestRowAndColumn);
+
+ $columns_to_check = $this->member_data_excel_columns;
+
+ $result = ['error_type' => 1, 'error_summary' => [], 'error_data' => []];
+ $keys = array_keys($columns_to_check);
+ $allowedHighestColumn = end($columns_to_check);
+ $excel_data = $sheet->rangeToArray('A1:' . $allowedHighestColumn['col_cell_name'] . $highestRowAndColumn['row']);
+ $excel_data = ExcelSanitizeHelper::sanitizeArrayData($excel_data);
+ $this->myLogger->logme('error', 'Excel data sanitized count : {row_count}', ['row_count' => count($excel_data)]);
+ // dd($excel_data);
+
+ //check number of columns in excel
+ $excel_columns = ($excel_data[0]);
+
+ //check columns order in excel
+ $column_count_res = check_columns_name_exist($columns_to_check, $excel_columns);
+ // dd($column_count_res);
+
+ if (isset($column_count_res) && count($column_count_res)) {
+ //columns count mismatch
+ $message = implode("\n", $column_count_res);
+ // echo $message;
+ $this->myLogger->logme('error', ($message . ' for lead id ' . $lead_id));
+ $this->leadFilesModel
+ ->where('lead_id', $lead_id)
+ ->where('type', 2)
+ ->set(['status' => 'failed','error_data' => json_encode(['error_summary' => array_count_values([6]),'error_data' => $message])])
+ ->update();
+ return array('error_summary' => [6], 'error_data' => $message);
+ }
+
+ $relationship = $this->general_relationships;
+
+ $column_count_res = update_excel_column_indexes($columns_to_check, $excel_columns);
+ // dd($column_count_res);
+
+ //remove header
+ unset($excel_data[0]);
+ $member_family_data = [];
+ foreach ($excel_data as $row_key => $row) {
+
+ //1. avoid empty rows
+ if (check_row_is_empty_or_null($row)) {
+ $this->myLogger->logme('error', "Empty row found at index {$row_key}, stopping row iteration");
+ break;
+ }
+
+ //iterate each row for columns validations
+ foreach ($row as $col_key => $col) {
+
+ $is_mandatory = $columns_to_check[$keys[$col_key]]['is_mandatory'];
+ $format = $columns_to_check[$keys[$col_key]]['format'];
+ $allowed_values = $columns_to_check[$keys[$col_key]]['allowed_values'];
+ $custom_function = isset($columns_to_check[$keys[$col_key]]['custom']) ? $columns_to_check[$keys[$col_key]]['custom'] : null;
+ $binding_params = isset($columns_to_check[$keys[$col_key]]['params']) ? $columns_to_check[$keys[$col_key]]['params'] : null;
+
+ $column_dispaly_name = $columns_to_check[$keys[$col_key]]['col_name'];
+ $column_index = $columns_to_check[$keys[$col_key]]['col_idx'];
+ $column_cell = $columns_to_check[$keys[$col_key]]['col_cell_name'];
+
+
+ //mandatory check
+ if (is_bool($is_mandatory) && $is_mandatory === true) {
+ if ($col == "" || $col == NULL) {
+ array_push($result['error_summary'], 1); //push error code for summary
+ $result['error_data'][$row_key][$keys[$col_key]]['col_name'] = $column_dispaly_name; //push column name
+ $result['error_data'][$row_key][$keys[$col_key]]['col_idx'] = $column_index; //push column index
+ $result['error_data'][$row_key][$keys[$col_key]]['error'][] = 'Value is mandatory'; //push exact error desc
+ }
+ }
+
+ //if is_mandatory is array (action based mandatory check)
+ if (is_array($is_mandatory)) {
+ $allowed_actions = $columns_to_check[$keys[$col_key]]['is_mandatory'];
+ if ($col == "" || $col == NULL) {
+ array_push($result['error_summary'], 1);
+ $result['error_data'][$row_key][$keys[$col_key]]['col_name'] = $column_dispaly_name; //push column name
+ $result['error_data'][$row_key][$keys[$col_key]]['col_idx'] = $column_index; //push column index
+ $result['error_data'][$row_key][$keys[$col_key]]['error'][] = 'Value is mandatory for this action/event';
+ }
+ }
+
+ //format check
+ if (isset($format)) {
+ $format_error = check_excel_date_format($col, $format);
+ if (!$format_error['status']) {
+ array_push($result['error_summary'], 2);
+ $result['error_data'][$row_key][$keys[$col_key]]['col_name'] = $column_dispaly_name; //push column name
+ $result['error_data'][$row_key][$keys[$col_key]]['col_idx'] = $column_index; //push column index
+ $result['error_data'][$row_key][$keys[$col_key]]['error'][] = $format_error['error'];
+ }
+ }
+
+ //allowed values check
+ if (($is_mandatory === true && isset($allowed_values) && is_array($allowed_values)) || (is_array($is_mandatory) && (isset($allowed_values) && is_array($allowed_values)))) {
+ if (!in_array((trim($col)), $allowed_values)) {
+ array_push($result['error_summary'], 3);
+ $result['error_data'][$row_key][$keys[$col_key]]['col_name'] = $column_dispaly_name; //push column name
+ $result['error_data'][$row_key][$keys[$col_key]]['col_idx'] = $column_index; //push column index
+ $result['error_data'][$row_key][$keys[$col_key]]['error'][] = "Value not allowed: Expected " . implode(",", $allowed_values) . " and received $col";
+ }
+ }
+
+ //custom function check
+ if (isset($custom_function)) {
+ //convert string params into PHP variables
+ // Create an array of variables to pass custom helper funcitons
+ $param_values = [];
+ foreach ($binding_params as $bkey => $bparam) {
+ $param_values[] = ($$bparam);
+ }
+ // dd(($param_values));//die();
+ $res = call_user_func_array($custom_function, $param_values);
+ if ($res['status'] === false) {
+ array_push($result['error_summary'], 4);
+ $result['error_data'][$row_key][$keys[$col_key]]['col_name'] = $column_dispaly_name; //push column name
+ $result['error_data'][$row_key][$keys[$col_key]]['col_idx'] = $column_index; //push column index
+ $result['error_data'][$row_key][$keys[$col_key]]['error'][] = $res['error'];
+ }
+ }
+ }
+
+ //age validation
+ $age_validation = isset($columns_to_check['dob']['age_validation']) ?? null;
+ if (isset($age_validation) && $age_validation && $age_validation_check && !empty($family_composition)) {
+ $format_error = check_age_validation($row, $family_composition);
+ if (!$format_error['status']) {
+ array_push($result['error_summary'], 2);
+ $result['error_data'][$row_key][$keys[$columns_to_check['dob']['col_idx']]]['col_name'] = $columns_to_check['dob']['col_name']; //push column name
+ $result['error_data'][$row_key][$keys[$columns_to_check['dob']['col_idx']]]['col_idx'] = $columns_to_check['dob']['col_idx']; //push column index
+ $result['error_data'][$row_key][$keys[$columns_to_check['dob']['col_idx']]]['error'][] = $format_error['error'];
+ }
+ }
+
+ $row['row_index'] = $row_key;
+ $relation_idx = $columns_to_check['relationship']['col_idx'];
+ $emp_code_idx = $columns_to_check['emp_code']['col_idx'];
+
+ if (isset($row[$relation_idx]) && strtolower($row[$relation_idx]) == 'self' && isset($member_family_data[$row[$emp_code_idx]])) {
+ array_unshift($member_family_data[$row[$emp_code_idx]], $row);
+ } else {
+ $member_family_data[$row[$emp_code_idx]][] = $row;
+ }
+ }
+ // dd($member_family_data);
+
+ $this->myLogger->logme('info', 'Row validation completed, starting duplicate check');
+ $check_row_dublicate = check_duplicate_rows_and_contacts($excel_data, $columns_to_check, $result);
+ // dd($check_row_dublicate);
+
+ if(count($check_row_dublicate)){
+ $result = $check_row_dublicate;
+ }
+
+ $this->myLogger->logme('info', 'Starting family validation');
+ $result = validateFamily($member_family_data, $columns_to_check, $result);
+ // dd($family_validation);
+
+ if (isset($result['error_summary']) && count($result['error_summary'])) {
+ $result['error_summary'] = array_count_values($result['error_summary']);
+ $status = 'failed';
+ $failure_reason = ((json_encode($result)));
+ $this->leadFilesModel->where('lead_id', $lead_id)->where('type', 2)->set(['status' => $status,'error_data' => $failure_reason])->update();
+ $this->myLogger->logme("error", '{lead_id} uploaded failed for this lead id', ['lead_id' => $lead_id]);
+ } else {
+ $this->leadFilesModel->where('lead_id', $lead_id)->where('type', 2)->set(['status' => 'success','error_data' => ''])->update();
+ $r = Jobs::addJob(['job_name' => 'calculateMembersDemography', 'payload' => ['lead_id' => $lead_id]]);
+ }
+
+ return $result;
+ }
+
+ public function getAgeRatioFromRfqJson($lead_id, $porposel_data)
+ {
+ $age_ratio = [];
+ $rfq_data = $this->RFQModel->where('is_active', 1)->where('lead_id', $lead_id)->orderBy('id', 'desc')->first();
+ if(empty($rfq_data) || empty($rfq_data['json'])){
+ return $age_ratio;
+ }
+
+ $data = json_decode($rfq_data['json'], true);
+ $proposal_and_insurer = json_decode($porposel_data, true);
+ $insurer_key = $proposal_and_insurer['insurer_name'] ?? null;
+
+ if(isset($data['table_data']['data'])){
+ foreach ($data['table_data']['data'] as $key => $value) {
+ if($value['items'] == 'family_composition'){
+ foreach ($value['data'] as $family_composition) {
+ if($family_composition['subth'] == $insurer_key){
+ $age_ratio = json_decode($family_composition['input_value'] ?? "", true) ?? [];
+ }
+ }
+ }
+ }
+ }
+
+ return $age_ratio;
+ }
+
+ public function getMemberDataExcelFileErrors()
+ {
+ $lead_id = $this->request->getGet('lead_id');
+ // $lead_id = 329;
+
+ // Render views and capture output
+ $result = $this->getMemberDataListExcelErrorData($lead_id);
+
+ if ($result != 0) {
+
+ $result['lead_id'] = $lead_id;
+ echo view('excel_errors', $result);
+ } else if ($result == 0) {
+
+ $data['message'] = 'File Not Found Physically';
+ return view('errors/404', $data);
+ } else {
+
+ echo view('errors/html/production');
+ }
+ }
+
+ public function getMemberDataListExcelErrorData($lead_id)
+ {
+ try {
+ $file = $this->leadFilesModel->where('lead_id', $lead_id)->where('type', 2)->where('is_active', 1)->first();
+ $error_data = json_decode($file['error_data']);
+ // dd($error_data);
+ // return $error_data;
+
+ $file_name_with_path = WRITEPATH . "/uploads/lead_files/" . $file['file_name'];
+
+ //check the file exist or not
+ if (!file_exists($file_name_with_path)) {
+ $error_message = "File not found";
+ $this->myLogger->logme('error', ($error_message . ' for file id ' . $lead_id));
+ return 0;
+ }
+
+ $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path);
+ $sheet = $spreadsheet->getActiveSheet();
+
+ $highestRowAndColumn = $sheet->getHighestRowAndColumn();
+ $excel_data = $sheet->rangeToArray('A1:' . $highestRowAndColumn['column'] . $highestRowAndColumn['row']);
+ $excelErrorData['excel_header'] = $excel_data[0];
+ unset($excel_data[0]);
+ // Kint::dump($excel_data);
+
+ if ($error_data->error_type == 1) {
+
+ $finalArray = [];
+ foreach ($error_data->error_data as $key => $value) {
+
+ foreach ($value as $key2 => $value2) {
+ $error_data = $value2->error;
+ $data = ['value' => $excel_data[$key][$value2->col_idx], 'error' => $error_data,];
+ $excel_data[$key][$value2->col_idx] = $data;
+ }
+ array_push($finalArray, $excel_data[$key]);
+ }
+
+ foreach ($finalArray as $fkey => $value) {
+ foreach ($value as $vkey => $arrayData) {
+ if (!is_array($arrayData)) {
+ $data = ['value' => $arrayData];
+ $finalArray[$fkey][$vkey] = $data;
+ }
+ }
+ }
+
+ $excelErrorData['excel_data'] = $finalArray;
+ return $excelErrorData;
+ } else if ($error_data->error_type == 2) {
+
+
+ $allErrors = [];
+ $typeTowArray = [];
+
+ foreach ($error_data->error_data as $index => $item) {
+
+ foreach ($item as $field) {
+ if (!isset($allErrors[$index])) {
+ $allErrors[$index] = [];
+ }
+ $allErrors[$index] = array_merge($allErrors[$index], $field->error);
+ }
+ }
+
+ // dd(array_keys($allErrors));
+ foreach ($allErrors as $key => $value) {
+ // echo $key;
+ // print_r($value);
+ foreach ($excel_data as $excel_data_index => $excel_data_value) {
+ if ($excel_data_value[0] == $key) {
+ $data = ['value' => $excel_data[$excel_data_index][1], 'error' => $value,];
+ $excel_data[$excel_data_index][1] = $data;
+ array_push($typeTowArray, $excel_data[$excel_data_index]);
+ break;
+ }
+ }
+ }
+ // dd($data);
+ foreach ($typeTowArray as $fkey => $value) {
+ foreach ($value as $vkey => $arrayData) {
+ if (!is_array($arrayData)) {
+ $data = ['value' => $arrayData];
+ $typeTowArray[$fkey][$vkey] = $data;
+ }
+ }
+ }
+
+ $excelErrorData['excel_data'] = $typeTowArray;
+ return $excelErrorData;
+ }
+ } catch (\Exception $e) {
+ // Handle any exceptions
+ $errorMessage = $e->getMessage(); //die();
+ $this->myLogger->logme('error', $errorMessage);
+ return false; // You can return an error response here
+ }
+ }
+
+ public function downloadFullMemberDataExcelErrorFile($lead_id, $rowIndex = 1, $colIndex = 1)
+ {
+ // Get file data from the database
+ $file_data = $this->leadFilesModel->where('lead_id', $lead_id)->where('type', 2)->where('is_active', 1)->first();
+
+ $error = json_decode($file_data['error_data']);
+
+ // Check if the file exists
+ if (!$file_data) {
+ $error_message = "File not found";
+ $this->myLogger->logme('error', $error_message . ' for file id ' . $lead_id);
+ return $error_message;
+ }
+
+ $fileName = $file_data['file_name'];
+ $filePath = WRITEPATH . '/uploads/lead_files/' . $fileName;
+
+ // Check if the file exists
+ if (!file_exists($filePath)) {
+ $error_message = "File not found";
+ $this->myLogger->logme('error', $error_message . ' for file id ' . $lead_id);
+ $data['message'] = 'Physical File Not Found';
+ return view('errors/404', $data);
+ }
+
+ // Load the Excel file
+ $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($filePath);
+ $sheet = $spreadsheet->getActiveSheet();
+
+ foreach ($error->error_data as $index => $error_data) {
+
+ $rowIndex = $index + 1;
+
+ if ($error->error_type == 1) {
+
+ foreach ($error_data as $key => $value) {
+
+ $colIndex = $value->col_idx + 1;
+
+ $originalValue = $sheet->getCell([$colIndex, $rowIndex])->getValue();
+
+ $newValue = implode(', ', $value->error);
+ $val = $originalValue . ' ( ' . $newValue . ' )';
+ $sheet->setCellValue([$colIndex, $rowIndex], $val);
+
+ $style = [
+ 'fill' => [
+ 'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
+ 'startColor' => ['rgb' => 'ffad99'] // Red color
+ ]
+ ];
+
+ $sheet->getStyle([$colIndex, $rowIndex])->applyFromArray($style);
+ }
+ } else if ($error->error_type == 2) {
+
+
+ foreach ($error_data as $key => $value) {
+
+
+ $originalValue = $sheet->getCell([1, $rowIndex])->getValue();
+
+ $newValue = implode(', ', $value->error);
+ $val = $originalValue . ' ( ' . $newValue . ' )';
+ $sheet->setCellValue([$colIndex, $rowIndex], $val);
+
+ $style = [
+ 'fill' => [
+ 'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
+ 'startColor' => ['rgb' => 'ffad99'] // Red color
+ ]
+ ];
+ $sheet->getStyle([$colIndex, $rowIndex])->applyFromArray($style);
+ }
+ }
+ }
+
+ // Create a new filename for the modified Excel file
+ $newFileName = 'error_with_highlight_' . $fileName;
+
+ // Save the modified Excel file to a new location
+ $newFilePath = WRITEPATH . '/uploads/lead_files/' . $newFileName;
+ $writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
+ $writer->save($newFilePath);
+
+ // Set headers to force download
+ $response = service('response');
+ $response->setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
+ $response->setHeader('Content-Disposition', 'attachment;filename="' . $newFileName . '"');
+ $response->setHeader('Cache-Control', 'max-age=0');
+ $response->setHeader('Content-Length', filesize($newFilePath));
+ $response->setBody(file_get_contents($newFilePath));
+
+ // Delete the temporary file
+ unlink($newFilePath);
+
+ // Return the response
+ return $response;
+ }
+
+ public function savePlacementDataAndValidateMemberDataFile()
+ {
+ try {
+
+ $this->myLogger->logme('error', '--- savePlacementDataAndValidateMemberDataFile START ---');
+
+ $params = $this->request->getPost();
+ $this->myLogger->logme('error', 'Received params: ' . json_encode($params));
+
+ if (empty($params['lead_id'])) {
+ $this->myLogger->logme('error', 'Lead ID missing');
+ return $this->respond([
+ 'status' => false,
+ 'code' => 400,
+ 'message' => 'Lead ID is required'
+ ], 400);
+ }
+
+ $lead_id = $params['lead_id'];
+ $proposal_insurer = $params['proposal_insurer'] ?? '';
+
+ // Handle proposal and insurer details
+ if (!empty($proposal_insurer) && strpos($proposal_insurer, '-') !== false) {
+ list($proposal_key, $insurer_key) = explode('-', $proposal_insurer, 2);
+ $lead_update_data = json_encode([
+ 'proposel_name' => $proposal_key,
+ 'insurer_name' => $insurer_key,
+ 'insurer' => $params['insurer_and_branch'] ?? null,
+ ]);
+ $this->myLogger->logme('error', "Proposal/Insurer parsed successfully: $proposal_key - $insurer_key");
+ } else {
+ $lead_update_data = null;
+ $this->myLogger->logme('error', 'Proposal/Insurer not provided or invalid format');
+ }
+
+ $data = [
+ 'proposel_data' => $lead_update_data,
+ 'placement_date' => !empty($params['placement_date']) ? change_date_format($params['placement_date']) : null,
+ 'payment_date' => !empty($params['payment_date']) ? change_date_format($params['payment_date']) : null,
+ 'utr_no' => $params['utr_no'] ?? null,
+ 'is_cd' => $params['is_cd'] ?? null,
+ 'premium_amount' => $params['premium_amount'] ?? null,
+ 'total_amount' => $params['total_amount'] ?? null,
+ 'cd_amount' => $params['cd_amount'] ?? null,
+ 'no_of_installment' => $params['no_of_installment'] ?? null,
+ 'is_installment' => $params['is_installment'] ?? null,
+ 'acm_id' => $params['acm_pk'] ?? null,
+ ];
+
+ // get lead data
+ $lead_data = $this->leadsModel->where('id', $lead_id)->first();
+
+ // Compare and update only if changed the start and end date
+ if (!empty($params['policy_start_date'])) {
+ $converted_start = change_date_format($params['policy_start_date']);
+ if ($converted_start !== $lead_data['policy_start_date']) {
+ $data['policy_start_date'] = $converted_start;
+ $this->myLogger->logme('error', "Policy start date updated: $converted_start");
+ }
+ }
+
+ if (!empty($params['policy_end_date'])) {
+ $converted_end = change_date_format($params['policy_end_date']);
+ if ($converted_end !== $lead_data['policy_end_date']) {
+ $data['policy_end_date'] = $converted_end;
+ $this->myLogger->logme('error', "Policy end date updated: $converted_end");
+ }
+ }
+
+ // Handle TPA details
+ if (!empty($params['tpa_id']) && strpos($params['tpa_id'], '-') !== false) {
+ list($tpaBranchId, $tpaId) = explode('-', $params['tpa_id']);
+ $data['tpa_branch_id'] = $tpaBranchId;
+ $data['tpa_id'] = $tpaId;
+ $this->myLogger->logme('error', "TPA details added: branch=$tpaBranchId, id=$tpaId");
+ }
+
+ $this->myLogger->logme('error', 'Prepared lead update data: ' . json_encode($data));
+
+ // Update main lead record
+ $this->leadsModel->update($lead_id, $data);
+ $this->myLogger->logme('error', "Lead updated successfully for ID: $lead_id");
+
+ // Save installment details
+ if (!empty($params['installments'])) {
+ $installments = json_decode($params['installments'], true);
+ $this->myLogger->logme('error', "Installments data received: " . json_encode($installments));
+
+ if (is_array($installments) && !empty($installments)) {
+ foreach ($installments as $installment) {
+ $installment['payment_date'] = !empty($installment['payment_date']) && strtotime($installment['payment_date'])
+ ? date('Y-m-d', strtotime($installment['payment_date']))
+ : null;
+
+ $installment['lead_id'] = $lead_id;
+
+ if (!empty($installment['id'])) {
+ $this->leadInstallmentPaymentDetails->update($installment['id'], $installment);
+ $this->myLogger->logme('error', "Installment updated: " . json_encode($installment));
+ } else {
+ $this->leadInstallmentPaymentDetails->insert($installment);
+ $this->myLogger->logme('error', "Installment inserted: " . json_encode($installment));
+ }
+ }
+ }
+ } else {
+ $this->myLogger->logme('error', "No installments provided");
+ }
+
+ // Update lead file status to pending
+ $this->leadFilesModel->where('lead_id', $lead_id)->where('type', 2)->set(['status' => 'pending'])->update();
+
+ // Queue job after save
+ $r = Jobs::addJob(['job_name' => 'memberDataListExcelFileFormatValidation', 'payload' => ['lead_id' => $lead_id, 'age_validation' => true]]);
+ $this->myLogger->logme('error', "Job queued successfully: " . json_encode($r));
+
+ $this->myLogger->logme('error', "--- savePlacementDataAndValidateMemberDataFile END (SUCCESS) ---");
+
+ return $this->respond([
+ 'status' => true,
+ 'code' => 200,
+ 'message' => 'Placement data saved successfully. File being validated',
+ 'lead_id' => $lead_id,
+ 'data' => $data,
+ 'params' => $params
+ ], 200);
+
+ } catch (\Exception $e) {
+ $errorDetails = [
+ 'error_message' => $e->getMessage(),
+ 'file' => $e->getFile(),
+ 'line' => $e->getLine(),
+ 'stack_trace' => $e->getTraceAsString(),
+ ];
+ $this->myLogger->logme('error', "--- savePlacementDataAndValidateMemberDataFile ERROR --- " . json_encode($errorDetails));
+ return $this->respond([
+ 'status' => false,
+ 'code' => 500,
+ 'message' => 'Error while validating the member data',
+ 'error' => $errorDetails
+ ], 500);
+ }
+ }
+
+ public function checkMemberDataFileValidationStatus()
+ {
+ $lead_id = $this->request->getVar('lead_id');
+ if (empty($lead_id)) {
+ return $this->respond([
+ 'status' => false,
+ 'code' => 400,
+ 'message' => 'lead_id is required'
+ ], 400);
+ }
+
+ // Fetch file validation status
+ $lead_file = $this->leadFilesModel
+ ->select('id, lead_id, status')
+ ->where('lead_id', $lead_id)
+ ->where('type', 2)
+ ->first();
+
+ if (!$lead_file) {
+ return $this->respond([
+ 'status' => false,
+ 'code' => 404,
+ 'message' => 'No file found for this lead_id'
+ ], 404);
+ }
+
+ // If validation is still running
+ if ($lead_file['status'] === 'pending' || $lead_file['status'] === null) {
+ return $this->respond([
+ 'status' => true,
+ 'code' => 202, // Accepted - still processing
+ 'message' => 'Validation in progress',
+ 'data' => ['status' => $lead_file['status']]
+ ], 200);
+ }
+
+ // If validation finished (success or failed)
+ return $this->respond([
+ 'status' => true,
+ 'code' => 200,
+ 'message' => 'Validation completed',
+ 'data' => $lead_file
+ ], 200);
+ }
+
+
+ // ----------- END OF MEMBER DATA VALIDAATION ------------------------------------------------------------------------------------------------------
+
}
diff --git a/app/Controllers/TestingController.php b/app/Controllers/TestingController.php
index 87310adc..d9756a7b 100644
--- a/app/Controllers/TestingController.php
+++ b/app/Controllers/TestingController.php
@@ -11,6 +11,12 @@ use CodeIgniter\API\ResponseTrait;
use Dompdf\Dompdf;
use Dompdf\Options;
+use PhpOffice\PhpSpreadsheet\Spreadsheet;
+use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
+use PhpOffice\PhpSpreadsheet\Style\Alignment;
+use PhpOffice\PhpSpreadsheet\Style\Fill;
+use PhpOffice\PhpSpreadsheet\Style\Border;
+
class TestingController extends BaseController
{
use ResponseTrait;
@@ -346,4 +352,185 @@ class TestingController extends BaseController
dd($policy_data);
}
+ public function membervalidation($lead_id = 329)
+ {
+ $lead_controll = new LeadsController();
+ // $lead_controll->getMemberDataExcelFileErrors();
+ $res = $lead_controll->memberDataListExcelFileFormatValidation(['lead_id' => $lead_id]);
+ dd($res);
+ }
+
+ private $firstNames = [
+ 'Rajesh', 'Priya', 'Amit', 'Sneha', 'Vikram', 'Anjali', 'Rahul', 'Deepika',
+ 'Sanjay', 'Kavita', 'Arun', 'Pooja', 'Manoj', 'Nisha', 'Suresh', 'Meera',
+ 'Karthik', 'Divya', 'Ravi', 'Lakshmi', 'Anand', 'Swathi', 'Vijay', 'Rekha',
+ 'Ashok', 'Sangeetha', 'Prakash', 'Uma', 'Ramesh', 'Vani', 'Kumar', 'Radha',
+ 'Dinesh', 'Shanti', 'Ganesh', 'Parvati', 'Mohan', 'Sita', 'Arjun', 'Geetha'
+ ];
+
+ private $lastNames = [
+ 'Kumar', 'Sharma', 'Singh', 'Patel', 'Reddy', 'Nair', 'Iyer', 'Krishnan',
+ 'Rao', 'Gupta', 'Verma', 'Agarwal', 'Joshi', 'Mehta', 'Desai', 'Pillai',
+ 'Menon', 'Bhat', 'Naidu', 'Varma', 'Malhotra', 'Kapoor', 'Chopra', 'Saxena',
+ 'Pandey', 'Mishra', 'Tiwari', 'Dubey', 'Sinha', 'Jain', 'Shah', 'Thakur'
+ ];
+
+ private $relationships = ['Self', 'Spouse', 'Son', 'Daughter', 'Father', 'Mother'];
+ private $genders = ['M', 'F'];
+ private $domains = ['gmail.com', 'yahoo.com', 'outlook.com', 'company.com', 'example.com'];
+
+ public function generateExcel()
+ {
+ // Increase execution time and memory for large files
+ ini_set('max_execution_time', 600);
+ ini_set('memory_limit', '1024M');
+
+ $spreadsheet = new Spreadsheet();
+ $sheet = $spreadsheet->getActiveSheet();
+
+ // Define headers
+ $headers = [
+ 'Sl no',
+ 'Emp Code',
+ 'Name',
+ 'Relationship',
+ 'Gender',
+ 'DOB',
+ 'Age',
+ 'Email',
+ 'Mobile',
+ 'SI',
+ 'SI Enhancement',
+ 'Proposed Sum Insured 1',
+ 'Proposed Sum Insured 2',
+ 'Proposed Sum Insured 3',
+ 'Proposed Sum Insured 4'
+ ];
+
+ // Set headers in row 1
+ $col = 'A';
+ foreach ($headers as $header) {
+ $sheet->setCellValue($col . '1', $header);
+ $col++;
+ }
+
+ // Style the header row
+ $headerStyle = [
+ 'font' => ['bold' => true, 'color' => ['rgb' => 'FFFFFF']],
+ 'fill' => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => '4472C4']],
+ 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER],
+ 'borders' => ['allBorders' => ['borderStyle' => Border::BORDER_THIN]]
+ ];
+ $sheet->getStyle('A1:O1')->applyFromArray($headerStyle);
+
+ // Generate 70,000 sample records
+ $totalRecords = 1000;
+ $batchSize = 1000;
+
+ for ($i = 1; $i <= $totalRecords; $i++) {
+ $row = $i + 1; // Start from row 2 (row 1 is header)
+
+ $record = $this->generateSampleRecord($i);
+
+ $sheet->setCellValue('A' . $row, $record['sl_no']);
+ $sheet->setCellValue('B' . $row, $record['emp_code']);
+ $sheet->setCellValue('C' . $row, $record['name']);
+ $sheet->setCellValue('D' . $row, $record['relationship']);
+ $sheet->setCellValue('E' . $row, $record['gender']);
+ $sheet->setCellValue('F' . $row, $record['dob']);
+ $sheet->setCellValue('G' . $row, $record['age']);
+ $sheet->setCellValue('H' . $row, $record['email']);
+ $sheet->setCellValue('I' . $row, $record['mobile']);
+ $sheet->setCellValue('J' . $row, $record['si']);
+ $sheet->setCellValue('K' . $row, $record['si_enhancement']);
+ $sheet->setCellValue('L' . $row, $record['proposed_si_1']);
+ $sheet->setCellValue('M' . $row, $record['proposed_si_2']);
+ $sheet->setCellValue('N' . $row, $record['proposed_si_3']);
+ $sheet->setCellValue('O' . $row, $record['proposed_si_4']);
+
+ // Clear memory every batch
+ if ($i % $batchSize == 0) {
+ $sheet->garbageCollect();
+ }
+ }
+
+ // Auto-size columns
+ foreach (range('A', 'O') as $col) {
+ $sheet->getColumnDimension($col)->setAutoSize(true);
+ }
+
+ // Generate filename
+ $filename = 'employee_data_70k_' . date('Y-m-d_His') . '.xlsx';
+
+ // Set headers for download
+ header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
+ header('Content-Disposition: attachment;filename="' . $filename . '"');
+ header('Cache-Control: max-age=0');
+
+ // Write file to output
+ $writer = new Xlsx($spreadsheet);
+ $writer->save('php://output');
+
+ // Clean up
+ $spreadsheet->disconnectWorksheets();
+ unset($spreadsheet);
+ exit;
+ }
+
+ private function generateSampleRecord($index)
+ {
+ $firstName = $this->firstNames[array_rand($this->firstNames)];
+ $lastName = $this->lastNames[array_rand($this->lastNames)];
+ $name = $firstName . ' ' . $lastName;
+
+ $relationship = $this->relationships[array_rand($this->relationships)];
+ $gender = $this->genders[array_rand($this->genders)];
+
+ // Generate random age between 18 and 65
+ $age = rand(18, 65);
+
+ // Calculate DOB based on age
+ $year = date('Y') - $age;
+ $month = str_pad(rand(1, 12), 2, '0', STR_PAD_LEFT);
+ $day = str_pad(rand(1, 28), 2, '0', STR_PAD_LEFT);
+ $dob = "{$day}-{$month}-{$year}";
+
+ // Generate employee code
+ $empCode = 'EMP' . str_pad($index, 6, '0', STR_PAD_LEFT);
+
+ // Generate email
+ $email = strtolower($firstName . '.' . $lastName . $index) . '@' . $this->domains[array_rand($this->domains)];
+
+ // Generate mobile number (Indian format)
+ $mobile = '+91' . rand(7000000000, 9999999999);
+
+ // Generate insurance amounts
+ $siOptions = [100000, 200000, 300000, 500000, 1000000];
+ $si = $siOptions[array_rand($siOptions)];
+ $si_enhancement = rand(0, 1) ? rand(50000, 200000) : 0;
+
+ $proposed_si_1 = $si + rand(100000, 500000);
+ $proposed_si_2 = $proposed_si_1 + rand(100000, 500000);
+ $proposed_si_3 = $proposed_si_2 + rand(100000, 500000);
+ $proposed_si_4 = $proposed_si_3 + rand(100000, 500000);
+
+ return [
+ 'sl_no' => $index,
+ 'emp_code' => $empCode,
+ 'name' => $name,
+ 'relationship' => $relationship,
+ 'gender' => $gender,
+ 'dob' => $dob,
+ 'age' => $age,
+ 'email' => $email,
+ 'mobile' => $mobile,
+ 'si' => $si,
+ 'si_enhancement' => $si_enhancement,
+ 'proposed_si_1' => $proposed_si_1,
+ 'proposed_si_2' => $proposed_si_2,
+ 'proposed_si_3' => $proposed_si_3,
+ 'proposed_si_4' => $proposed_si_4
+ ];
+ }
+
}
diff --git a/app/Helpers/excel_util_helper.php b/app/Helpers/excel_util_helper.php
index 932e53c8..e608b013 100755
--- a/app/Helpers/excel_util_helper.php
+++ b/app/Helpers/excel_util_helper.php
@@ -1993,7 +1993,6 @@ if (!function_exists('group_slab_rates_basedon_name')) {
}
}
-
//this key generating mandantory for display employee info in enrolment app w/o error
if (!function_exists('generate_family_floater_key')) {
function generate_family_floater_key($relationship)
@@ -2002,7 +2001,7 @@ if (!function_exists('generate_family_floater_key')) {
$relation = 'parent';
} else if (strtolower(trim($relationship)) === 'son' || strtolower(trim($relationship)) === 'daughter') {
$relation = 'child';
- } else if ((strtolower(trim($relationship)) === 'father in Law' || strtolower(trim($relationship)) === 'mother in Law') || (strtolower(trim($relationship)) === 'father-in-Law' || strtolower(trim($relationship)) === 'mother-in-Law')) {
+ } else if ((strtolower(trim($relationship)) === 'father in law' || strtolower(trim($relationship)) === 'mother in law') || (strtolower(trim($relationship)) === 'father-in-law' || strtolower(trim($relationship)) === 'mother-in-law')) {
$relation = 'parent_in_law';
} else if (strtolower(trim($relationship)) === 'spouse') {
$relation = 'spouse';
@@ -2041,3 +2040,331 @@ if (!function_exists('formatIndianCurrency')) {
return $formatted . $decimal;
}
}
+
+// ------------- FUNCTION FOR LEAD MEMBER DATA LIST VALIDATIONS --------------------------------------
+
+if (!function_exists('check_columns_name_exist')) {
+ function check_columns_name_exist($definedColumns, $excelColumns)
+ {
+ $mismatchedColumns = [];
+
+ foreach ($definedColumns as $colKey => $definedCol) {
+ $definedColName = strtolower(trim($definedCol['col_name']));
+
+ // Normalize excel columns to lowercase for comparison
+ $excelColsLower = array_map('strtolower', array_map('trim', $excelColumns));
+
+ if (!in_array($definedColName, $excelColsLower)) {
+ $mismatchedColumns[] = "Missing column: " . $definedCol['col_name'] . " in Excel file.
";
+ }
+ }
+
+ return $mismatchedColumns;
+ }
+}
+
+if (!function_exists('update_excel_column_indexes')) {
+ function update_excel_column_indexes($definedColumns, $excelColumns)
+ {
+ // $excelColumns is the first row of the Excel file (header row)
+ // Example: ['Emp Code', 'Name', 'Gender', 'DOB', 'SI']
+
+ foreach ($definedColumns as $key => &$definedCol) {
+ $definedColName = strtolower(trim($definedCol['col_name']));
+ $excelColsLower = array_map('strtolower', array_map('trim', $excelColumns));
+
+ // Find column index in Excel
+ $colIndex = array_search($definedColName, $excelColsLower);
+
+ if ($colIndex !== false) {
+ $definedCol['col_idx'] = $colIndex;
+ $definedCol['col_cell_name'] = chr(65 + $colIndex); // A=65, B=66...
+ } else {
+ // If column missing in Excel
+ $definedCol['col_idx'] = null;
+ $definedCol['col_cell_name'] = null;
+ }
+ }
+
+ return $definedColumns;
+ }
+}
+
+if (!function_exists('check_duplicate_rows_and_contacts')) {
+ function check_duplicate_rows_and_contacts($excel_data, $columns_to_check, $err_data)
+ {
+ $exl_col = $columns_to_check;
+ $keys = array_keys($columns_to_check);
+ unset($columns_to_check['sno'], $columns_to_check['si'], $columns_to_check['email'], $columns_to_check['mobile'], $columns_to_check['age']);
+
+ $seenRows = [];
+ $emailSeen = [];
+ $mobileSeen = [];
+ $duplicateRows = [];
+
+ foreach ($excel_data as $rowIndex => $row) {
+
+ // Build unique key from selected columns
+ $values = [];
+ foreach ($columns_to_check as $colIdx) {
+ $values[] = isset($row[$colIdx['col_idx']]) ? trim($row[$colIdx['col_idx']]) : '';
+ }
+ $rowKey = json_encode($values);
+
+ // =============== STEP 1: Main duplicate check ===============
+ if (!isset($seenRows[$rowKey])) {
+ $seenRows[$rowKey] = [$rowIndex];
+ } else {
+ // First duplicate occurrence — mark all related rows
+ $seenRows[$rowKey][] = $rowIndex;
+ $indexes = $seenRows[$rowKey];
+
+ $rows_str = implode(', ', array_map(fn($i) => $i + 1, $indexes));
+ $error_message = "Duplicate found in selected columns: Rows {$rows_str} are identical";
+
+ foreach ($indexes as $i) {
+ // Avoid re-adding duplicate errors
+ if (!in_array($i, $duplicateRows)) {
+ array_push($err_data['error_summary'], 1);
+ $err_data['error_data'][$i][$keys[0]]['col_name'] = 'Sl no';
+ $err_data['error_data'][$i][$keys[0]]['col_idx'] = 0;
+ $err_data['error_data'][$i][$keys[0]]['error'][] = $error_message;
+ $duplicateRows[] = $i;
+ }
+ }
+
+ // Skip email/mobile check for this duplicate row
+ continue;
+ }
+
+ // =============== STEP 2: Email & Mobile check (only if not duplicate) ===============
+ $email = isset($row[$exl_col['email']['col_idx']]) ? trim($row[$exl_col['email']['col_idx']]) : '';
+ $mobile = isset($row[$exl_col['mobile']['col_idx']]) ? trim($row[$exl_col['mobile']['col_idx']]) : '';
+
+ // Check email duplicates
+ if ($email !== '') {
+ if (isset($emailSeen[$email])) {
+ $firstIndex = $emailSeen[$email] + 1;
+ $currentRow = $rowIndex + 1;
+ $error_message = "Duplicate email found: Row {$currentRow} and Row {$firstIndex} have the same email '$email'";
+ array_push($err_data['error_summary'], 1);
+ $err_data['error_data'][$rowIndex][$keys[$exl_col['email']['col_idx']]]['col_name'] = $exl_col['email']['col_name'];
+ $err_data['error_data'][$rowIndex][$keys[$exl_col['email']['col_idx']]]['col_idx'] = $exl_col['email']['col_idx'];
+ $err_data['error_data'][$rowIndex][$keys[$exl_col['email']['col_idx']]]['error'][] = $error_message;
+ } else {
+ $emailSeen[$email] = $rowIndex;
+ }
+ }
+
+ // Check mobile duplicates
+ if ($mobile !== '') {
+ if (isset($mobileSeen[$mobile])) {
+ $firstIndex = $mobileSeen[$mobile] + 1;
+ $currentRow = $rowIndex + 1;
+ $error_message = "Duplicate mobile number found: Row {$currentRow} and Row {$firstIndex} have the same mobile '$mobile'";
+ array_push($err_data['error_summary'], 1);
+ $err_data['error_data'][$rowIndex][$keys[$exl_col['mobile']['col_idx']]]['col_name'] = $exl_col['mobile']['col_name'];
+ $err_data['error_data'][$rowIndex][$keys[$exl_col['mobile']['col_idx']]]['col_idx'] = $exl_col['mobile']['col_idx'];
+ $err_data['error_data'][$rowIndex][$keys[$exl_col['mobile']['col_idx']]]['error'][] = $error_message;
+ } else {
+ $mobileSeen[$mobile] = $rowIndex;
+ }
+ }
+ }
+
+ return $err_data;
+ }
+}
+
+if (!function_exists('check_relationship_for_member_data')) {
+ function check_relationship_for_member_data($row, $relationship, $columns_to_check)
+ {
+ $relation_col_idx = $columns_to_check['relationship']['col_idx'] ?? null;
+ $gender_col_idx = $columns_to_check['gender']['col_idx'] ?? null;
+
+ if ($relation_col_idx !== null && $gender_col_idx !== null && !empty($row[$relation_col_idx]) && !empty($row[$gender_col_idx])) { //$row[5] = relationship $row[4] = Gender
+
+ $slug = \Config\Services::slug();
+ $col = $slug->slugify($row[$relation_col_idx]);
+
+ if ($col != 'self' && $col != 'spouse') {
+ if (!isset($relationship[$col])) {
+ return array('status' => false, 'error' => 'Rule Conflict: Unknown Relationship');
+ }
+
+ if (isset($relationship[$col]) && $relationship[$col]['gender'] != $row[$gender_col_idx]) {
+ $error = "Gender relationship conflict: Expected " . $relationship[$col]['gender'] . ", received $row[$gender_col_idx]";
+ return array('status' => false, 'error' => $error);
+ }
+ }
+
+ return array('status' => true);
+ } else {
+ return array('status' => false, 'error' => 'Rule Conflict: Both Relationship and Gender required for check relationship conflict');
+ }
+ }
+}
+
+if (!function_exists('member_data_group_by_family')) {
+ function member_data_group_by_family($member_data, $columns_to_check)
+ {
+ $result = [];
+ // Kint::dump($member_data);
+ foreach ($member_data as $rowIndex => $row) {
+ if (!check_row_is_empty_or_null($row)) {
+
+ $row['row_index'] = $rowIndex;
+
+ $relation_idx = $columns_to_check['relationship']['col_idx'];
+ $emp_code_idx = $columns_to_check['emp_code']['col_idx'];
+
+ if (isset($row[$relation_idx]) && strtolower($row[$relation_idx]) == 'self' && isset($result[$row[$emp_code_idx]])) {
+ array_unshift($result[$row[$emp_code_idx]], $row);
+ } else {
+ $result[$row[$emp_code_idx]][] = $row;
+ }
+ }
+ }
+ return $result;
+ }
+}
+
+if (!function_exists('validateFamily')) {
+ function validateFamily($familyData, $columns_to_check, $errors) {
+
+ $keys = array_keys($columns_to_check);
+ foreach ($familyData as $familyId => $members) {
+
+ $selfMember = null;
+ $spouseMember = null;
+ $selfCount = 0;
+ $row_index = null;
+
+ // Find Self and Spouse members
+ foreach ($members as $member) {
+ $relation = trim($member[3]); // Relationship field
+
+ if (strtolower($relation) == 'self') {
+ $selfCount++;
+ $selfMember = $member;
+ }
+
+ if (strtolower($relation) == 'spouse') {
+ $spouseMember = $member;
+ }
+
+ if($row_index == null){
+ if(strtolower($relation) == 'self'){
+ $row_index = $member['row_index'];
+ }else if(strtolower($relation) == 'spouse'){
+ $row_index = $member['row_index'];
+ }else{
+ $row_index = $member['row_index'];
+ }
+ }
+
+ }
+
+ // Validation 1: Check if Self exists
+ if ($selfCount === 0) {
+
+ $message = "Emp ID - {$familyId}: Missing 'Self' member";
+ array_push($errors['error_summary'], 4);
+ $errors['error_data'][$row_index][$keys[$columns_to_check['emp_code']['col_idx']]]['col_name'] = $columns_to_check['emp_code']['col_name'];
+ $errors['error_data'][$row_index][$keys[$columns_to_check['emp_code']['col_idx']]]['col_idx'] = $columns_to_check['emp_code']['col_idx'];
+ $errors['error_data'][$row_index][$keys[$columns_to_check['emp_code']['col_idx']]]['error'][] = $message;
+
+ continue;
+ }
+
+ // Validation 2: Check if there's exactly one Self
+ if ($selfCount > 1) {
+ $message = "Emp ID - {$familyId}: Multiple 'Self' members found. Only one 'Self' is allowed per family";
+ array_push($errors['error_summary'], 5);
+ $errors['error_data'][$row_index][$keys[$columns_to_check['emp_code']['col_idx']]]['col_name'] = $columns_to_check['emp_code']['col_name'];
+ $errors['error_data'][$row_index][$keys[$columns_to_check['emp_code']['col_idx']]]['col_idx'] = $columns_to_check['emp_code']['col_idx'];
+ $errors['error_data'][$row_index][$keys[$columns_to_check['emp_code']['col_idx']]]['error'][] = $message;
+
+ continue;
+ }
+
+ // Validation 3: Validate spouse gender if spouse exists
+ if ($spouseMember !== null) {
+
+ $selfGender = strtoupper(trim($selfMember[4])); // Gender field
+ $spouseGender = strtoupper(trim($spouseMember[4]));
+ $selfName = $selfMember[2]; // Name field
+ $spouseName = $spouseMember[2];
+
+ // Check gender compatibility
+ $message = '';
+ if ($selfGender === 'M' && $spouseGender !== 'F') {
+ $message = "Emp ID - {$familyId}: Self ('{$selfName}') is Male (M); spouse must be Female (F). Found spouse ('{$spouseName}') with gender '({$spouseGender})'.";
+ } elseif ($selfGender === 'F' && $spouseGender !== 'M') {
+ $message = "Emp ID - {$familyId}: Self ('{$selfName}') is Female (F); spouse must be Male (M). Found spouse ('{$spouseName}') with gender '({$spouseGender})'.";
+ } elseif (!in_array($selfGender, ['M', 'F'])) {
+ $message = "Emp ID - {$familyId}: Invalid gender for Self member ('{$selfName}'). Expected 'M' or 'F', found '({$selfGender})'.";
+ }
+
+ if(isset($message) && !empty($message)){
+ array_push($errors['error_summary'], 6);
+ $errors['error_data'][$row_index][$keys[$columns_to_check['emp_code']['col_idx']]]['col_name'] = $columns_to_check['emp_code']['col_name'];
+ $errors['error_data'][$row_index][$keys[$columns_to_check['emp_code']['col_idx']]]['col_idx'] = $columns_to_check['emp_code']['col_idx'];
+ $errors['error_data'][$row_index][$keys[$columns_to_check['emp_code']['col_idx']]]['error'][] = $message;
+ }
+ }
+ }
+
+ return $errors;
+ }
+}
+
+if (!function_exists('check_age_validation')) {
+ function check_age_validation($row, $family_composition)
+ {
+ if ($row[5] != null) {
+
+ $dateString = convert_string_to_date($row[5]);
+ if ($dateString === false) {
+ return array('status' => false, 'error' => 'Not a valid Date');
+ }
+
+ $relationships = $family_composition['age_ratio'];
+
+ $dob = $dateString;
+ $currentDateTime = new DateTime();
+
+ $passedDateTime = new DateTime($dob);
+ $interval = $currentDateTime->diff($passedDateTime);
+
+ $slug = \Config\Services::slug();
+ $relationship = $slug->slugify($row[3]);
+ if($relationship == 'son' || $relationship == 'daughter'){
+ $relationship = 'child';
+ }
+ if($relationship == 'father' || $relationship == 'mother' || $relationship == 'mother-in-law'|| $relationship == 'father-in-law' ){
+ $relationship = 'elders';
+ }
+
+ $age_min = isset($relationships[$relationship]['min']) ? $relationships[$relationship]['min'] : NULL;
+ $age_max = isset($relationships[$relationship]['max']) ? $relationships[$relationship]['max'] : NULL;
+
+ // Kint::dump($dob,$currentDateTime,$passedDateTime, $interval->y, $age_min, $age_max, $relationship, $relationships);
+
+ if ($age_min !== null && $age_min > $interval->y) {
+ return array('status' => false, 'error' => "Age conflict : minimum $age_min yrs allowed, received $interval->y");
+ }
+ if ($age_max !== null && $age_max < $interval->y) {
+ return array('status' => false, 'error' => "Age conflict : maximum $age_max yrs allowed, received $interval->y");
+ }
+ return array('status' => true);
+
+ } else {
+ return array('status' => false, 'error' => 'Rule Conflict: Both DOB and Relationship required for age check');
+ }
+ }
+}
+
+// ------------- END OF LEAD MEMBER DATA LIST VALIDATIONS --------------------------------------
+
+
diff --git a/app/Models/LeadFilesModel.php b/app/Models/LeadFilesModel.php
index 37db8e16..f3532d1f 100644
--- a/app/Models/LeadFilesModel.php
+++ b/app/Models/LeadFilesModel.php
@@ -17,7 +17,10 @@ class LeadFilesModel extends Model
'updated_by',
'created_at',
'updated_at',
- 'is_active'
+ 'is_active',
+ 'error_data',
+ 'status',
+ 'type',
];
// Callbacks
diff --git a/app/Models/LeadsModel.php b/app/Models/LeadsModel.php
index 005eacd2..7cc56602 100644
--- a/app/Models/LeadsModel.php
+++ b/app/Models/LeadsModel.php
@@ -147,6 +147,7 @@ class LeadsModel extends Model
$data = $this->select('
leads.*,
+ lead_files.status as demography_file_status,
kyc_entity_type.name as entity_type,
policy_type.policy_type,
user_profiles.first_name as salse_person_name,
@@ -169,6 +170,7 @@ class LeadsModel extends Model
->join('kyc_entity_type', 'leads.entity_type_id = kyc_entity_type.id', 'left')
->join('user_profiles', 'leads.salse_person_id = user_profiles.id', 'left')
->join('policy_type', 'leads.policy_type_id = policy_type.id', 'left')
+ ->join('lead_files', 'leads.id = lead_files.lead_id AND lead_files.type = 2 AND lead_files.is_active = 1', 'left')
->where('leads.is_active', 1);
if (!empty($where)) {
diff --git a/app/Views/excel_errors.php b/app/Views/excel_errors.php
index 04db844d..7e9141e4 100755
--- a/app/Views/excel_errors.php
+++ b/app/Views/excel_errors.php
@@ -110,7 +110,18 @@ table.dataTable tbody td {
+
+
\ No newline at end of file