diff --git a/.env.sample b/.env.sample new file mode 100644 index 0000000..36880c7 --- /dev/null +++ b/.env.sample @@ -0,0 +1,185 @@ +#-------------------------------------------------------------------- +# ENVIRONMENT +#-------------------------------------------------------------------- + +CI_ENVIRONMENT = development + +#-------------------------------------------------------------------- +# APP +#-------------------------------------------------------------------- + +app.baseURL = +app.appTimezone = 'Asia/Kolkata' +# If you have trouble with `.`, you could also use `_`. +# app_baseURL = '' +# app.forceGlobalSecureRequests = false +# app.CSPEnabled = false + +#-------------------------------------------------------------------- +# DATABASE +#-------------------------------------------------------------------- +DB_SSL_ENABLE = false +database.default.hostname = +database.default.database = +database.default.username = +database.default.password = +# database.default.DBDriver = MySQLi +# database.default.DBPrefix = +# database.default.port = 3306 + +#-------------------------------------------------------------------- +# CONTENT SECURITY POLICY +#-------------------------------------------------------------------- + +# contentsecuritypolicy.reportOnly = false +# contentsecuritypolicy.defaultSrc = 'none' +# contentsecuritypolicy.scriptSrc = 'self' +# contentsecuritypolicy.styleSrc = 'self' +# contentsecuritypolicy.imageSrc = 'self' +# contentsecuritypolicy.baseURI = null +# contentsecuritypolicy.childSrc = null +# contentsecuritypolicy.connectSrc = 'self' +# contentsecuritypolicy.fontSrc = null +# contentsecuritypolicy.formAction = null +# contentsecuritypolicy.frameAncestors = null +# contentsecuritypolicy.frameSrc = null +# contentsecuritypolicy.mediaSrc = null +# contentsecuritypolicy.objectSrc = null +# contentsecuritypolicy.pluginTypes = null +# contentsecuritypolicy.reportURI = null +# contentsecuritypolicy.sandbox = false +# contentsecuritypolicy.upgradeInsecureRequests = false +# contentsecuritypolicy.styleNonceTag = '{csp-style-nonce}' +# contentsecuritypolicy.scriptNonceTag = '{csp-script-nonce}' +# contentsecuritypolicy.autoNonce = true + +#-------------------------------------------------------------------- +# COOKIE +#-------------------------------------------------------------------- + +# cookie.prefix = '' +# cookie.expires = 0 +# cookie.path = '/' +# cookie.domain = '' +# cookie.secure = false +# cookie.httponly = false +# cookie.samesite = 'Lax' +# cookie.raw = false + +#-------------------------------------------------------------------- +# ENCRYPTION +#-------------------------------------------------------------------- + +# encryption.key = +# encryption.driver = OpenSSL +# encryption.blockSize = 16 +# encryption.digest = SHA512 + +#-------------------------------------------------------------------- +# HONEYPOT +#-------------------------------------------------------------------- + +# honeypot.hidden = 'true' +# honeypot.label = 'Fill This Field' +# honeypot.name = 'honeypot' +# honeypot.template = '' +# honeypot.container = '
{template}
' + +#-------------------------------------------------------------------- +# SECURITY +#-------------------------------------------------------------------- + +# security.csrfProtection = 'cookie' +# security.tokenRandomize = false +# security.tokenName = 'csrf_token_name' +# security.headerName = 'X-CSRF-TOKEN' +# security.cookieName = 'csrf_cookie_name' +# security.expires = 7200 +# security.regenerate = true +# security.redirect = false +# security.samesite = 'Lax' + +#-------------------------------------------------------------------- +# SESSION +#-------------------------------------------------------------------- + +# session.driver = 'CodeIgniter\Session\Handlers\FileHandler' +# session.cookieName = 'ci_session' +session.expiration = 28800 +# session.savePath = null +# session.matchIP = false +# session.timeToUpdate = 300 +# session.regenerateDestroy = false + +#-------------------------------------------------------------------- +# LOGGER +#-------------------------------------------------------------------- + +logger.threshold = 4 + +#-------------------------------------------------------------------- +# CURLRequest +#-------------------------------------------------------------------- + +# curlrequest.shareOptions = true + +GOOGLE_OAUTH_APP_NAME = +#GOOGLE_OAUTH_CLIENT_ID = +#GOOGLE_OAUTH_CLIENT_SECRET = + +GOOGLE_OAUTH_CLIENT_ID = +GOOGLE_OAUTH_CLIENT_SECRET = +GOOGLE_OAUTH_REDIRECT_URI = +GOOGLE_OAUTH_SCOPES = +App_Url = +NHANCE_LOGO = +helpdeskURL = +TOKENTIMEOUT = +POST_ENROLLMENT_APP_LINK = +GDRIVE_ROOT_FOLDER_ID = + + +email.fromEmail = +email.fromName = +ZEPTO_API_KEY = +email.SMTPPass = + +#-------------------------------------------------------------------- +# SET COOKIE DATA +#-------------------------------------------------------------------- +cookie.Path = '/'; +cookie.Domain = '.nhanceindia.in'; //Enter Domain Name with preceding .(dot) -> .nhanceindia.in +cookie.secure = 'true';// if https set as true or if http set as false + +unlayer.projectID = +email.enquiryMail = + +POST_ENROLLMENT_BASEURL = + +database.postDB.hostname = +database.postDB.database = +database.postDB.username = +database.postDB.password = +database.postDB.DBDriver = +database.postDB.DBPrefix = +database.postDB.port = + +POST_ENROLLMENT_BASEURL = + +#SMS +SMS_API_KEY = +SMS_SENDER_ID = +SMS_TEMPLATE_ID = +SMS_SERVICE_NAME = +SMS_APP_NAME = + +# CORS Configuration +CORS_ALLOWED_ORIGINS= +CORS_ALLOW_CREDENTIALS=true +CORS_ALLOWED_METHODS=GET,POST,PUT,PATCH,DELETE,OPTIONS +CORS_ALLOWED_HEADERS=Content-Type,Authorization,X-Requested-With,Accept,Origin,App-Signature +CORS_EXPOSE_HEADERS=X-Total-Count,X-Page-Count,X-RateLimit-Remaining +CORS_MAX_AGE=7200 +CORS_DEBUG=true + +APP_SIGNATURE = diff --git a/.htaccess b/.htaccess index cf3c184..6782611 100755 --- a/.htaccess +++ b/.htaccess @@ -5,6 +5,28 @@ Options -Indexes # Rewrite engine # ---------------------------------------------------------------------- + +## ADDED for - block any script execution inside folder of public + + Deny from all + # Disable PHP engine + + php_flag engine off + + + # Disable CGI and other executable handlers + Options -ExecCGI + AddHandler cgi-script .php .pl .py .jsp .asp .sh .cgi + + # Block access to any script-like files entirely + + ForceType text/plain + #Order allow,deny + Deny from all + + + + # Turning on the rewrite engine is necessary for the following rules and features. # FollowSymLinks must be enabled for this to work. diff --git a/app/Config/Database.php b/app/Config/Database.php index f59b49f..f7f63c3 100755 --- a/app/Config/Database.php +++ b/app/Config/Database.php @@ -20,6 +20,7 @@ class Database extends Config * use if no other is specified. */ public string $defaultGroup = 'default'; + public string $enableSSL; /** * The default database connection. @@ -38,6 +39,7 @@ class Database extends Config 'DBCollat' => 'utf8_general_ci', 'swapPre' => '', 'encrypt' => false, + // 'encrypt' => ['ssl_verify' => true,'ssl_ca' => ROOTPATH .'ca.pem'], 'compress' => false, 'strictOn' => false, 'failover' => [], @@ -95,5 +97,21 @@ class Database extends Config if (ENVIRONMENT === 'testing') { $this->defaultGroup = 'tests'; } + + $this->enableSSL = env('DB_SSL_ENABLE') ?? false; + + if ($this->enableSSL === true || $this->enableSSL === 'true' || $this->enableSSL === 1 || $this->enableSSL === '1') { + + + // Enable SSL authentication + $this->default['encrypt'] = [ + 'ssl_ca' => ROOTPATH . 'ca.pem', + 'ssl_verify' => true, + ]; + $this->postDB['encrypt'] = [ + 'ssl_ca' => ROOTPATH . 'ca.pem', + 'ssl_verify' => true, + ]; + } } } diff --git a/app/Config/Filters.php b/app/Config/Filters.php index 76924a2..969dadf 100755 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -16,6 +16,8 @@ use App\Filters\VerifyAppSignature; use App\Filters\AuthJWT; use App\Filters\Cors; +use App\Filters\GlobalPostFileUploadGuard; +use App\Filters\SecurityInputFilter; class Filters extends BaseConfig { @@ -39,6 +41,8 @@ class Filters extends BaseConfig 'CloseDbConnection' => CloseDbConnection::class, 'Cors' => Cors::class, 'appSignature' => VerifyAppSignature::class, + 'GlobalPostFileUploadGuard' => GlobalPostFileUploadGuard::class, + 'SecurityInputFilter' => SecurityInputFilter::class, ]; @@ -53,7 +57,8 @@ class Filters extends BaseConfig 'before' => [ 'HttpRequestLog' => ['except' => 'cli/*'], 'Cors', - // 'csrf', + 'SecurityInputFilter', + 'GlobalPostFileUploadGuard', // 'invalidchars', ], 'after' => [ diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 6524071..2610b9e 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -438,6 +438,7 @@ $routes->cli('cli/sendZeptoMail', 'MasterController::testZeptoSMTP'); $routes->cli('cli/check_bounce_mail_cli', 'MasterController::testCheckBounceMails'); $routes->cli('cli/app_check_list', 'MasterController::appCheckList'); $routes->cli('cli/new_gdrive_token', 'GoogleDriveController::generateNewGoogleDriveAccessToken'); +$routes->cli('cli/check_env', 'MasterController::checkEnv'); @@ -534,10 +535,12 @@ $routes->group("employeeRest", ['filter' => ['appSignature'] ], function ($route $routes->post("verifyOtp", "RestAuthenticationController::verifyOtp"); $routes->post("checkPassword", "RestAuthenticationController::checkPassword"); $routes->get("downloadSampleExcel", "EmployeeRestController::downloadSampleExcel"); - + // $routes->post("getPreEmployeePolicyCount", "EmployeeRestController::getPreEmployeePolicyCount"); }); +$routes->post("getPreEmployeePolicyCount","EmployeeRestController::getPreEmployeePolicyCount", ['filter' => ['appSignature']]); + $routes->get("getEmployeeActiveOrInactivePolicy", "EmployeeRestController::getEmployeeActiveOrInactivePolicy"); $routes->get("sendPushNotification", "EmployeeRestController::sendPushNotification"); $routes->post("sendEmail", "EmployeeRestController::send_email"); @@ -554,7 +557,7 @@ $routes->get("sendCroneRemainderMail", "DashboardController::sendCroneRemainderM // $routes->get("getEmployeePolicy", "EmployeeRestController::getEmployeePolicy"); $routes->get("getAddOnPolicy", "EmployeeRestController::getAddOnPolicy"); $routes->post("addEmployeeAndDependence", "EmployeeRestController::addEmployeeAndDependence"); -$routes->post("getPreEmployeePolicyCount", "EmployeeRestController::getPreEmployeePolicyCount"); + diff --git a/app/Controllers/ClientController.php b/app/Controllers/ClientController.php index 5afb6bb..3d989a0 100755 --- a/app/Controllers/ClientController.php +++ b/app/Controllers/ClientController.php @@ -507,7 +507,7 @@ class ClientController extends AdminController // echo "
";
         // print_r($data); die;
-        $data['placeHolders'] = ['member_name', 'nhance_logo', 'tpa_id', 'ecard_download_link', 'client_logo', 'policy_no', 'member_summary', 'app_link', 'post_enrollment_app_link', 'client_name'];
+        $data['placeHolders'] = ['member_name', 'nhance_logo', 'tpa_id', 'ecard_download_link', 'client_logo', 'policy_no', 'member_summary', 'app_link', 'post_enrollment_app_link', 'client_name', 'enrollment_open_date', 'enrollment_close_date'];
 
         // dd($data['placeHolders']);
 
@@ -653,7 +653,7 @@ class ClientController extends AdminController
         $editData['client_policy']    = $clientPoliceData;
         $editData['client_policy']['role'] = get_role_id();
         $editData['notification'] = $this->notificationModel->select('template_name,enabled')->where('client_id', $id)->findAll();
-        $editData['placeHolders'] = ['member_name', 'member_mobile', 'nhance_logo', 'tpa_id', 'ecard_download_link', 'client_logo', 'policy_no', 'member_summary', 'app_link', 'post_enrollment_app_link', 'client_name'];
+        $editData['placeHolders'] = ['member_name', 'member_mobile', 'nhance_logo', 'tpa_id', 'ecard_download_link', 'client_logo', 'policy_no', 'member_summary', 'app_link', 'post_enrollment_app_link', 'client_name', 'enrollment_open_date', 'enrollment_close_date'];
         
         $editData['auto_fetch_client_list'] =  $this->getClientListFromPost();
 
@@ -4623,7 +4623,7 @@ class ClientController extends AdminController
         // $res = $employeeRestController->getExcelErrorData(['file_id' => 897]);
         // $employeeRestController->employeesOnboardPreprocess(['file_id' => 644]);
         // $employeeRestController->employeesOnboardProcess(['file_id' => 835]);
-        // $employeeRestController->employeesEnrollmentInsert(['file_id' => 836]);
+        // $res = $employeeRestController->employeesEnrollmentInsert(['file_id' => 1138]);
         // $r = Jobs::addJob(['job_name' => 'employeesEnrollmentInsert','payload' => ['file_id' => 721]]);
         // dd($res);
 
diff --git a/app/Controllers/EmployeeController.php b/app/Controllers/EmployeeController.php
index dcb7ec7..8b9785d 100755
--- a/app/Controllers/EmployeeController.php
+++ b/app/Controllers/EmployeeController.php
@@ -179,7 +179,7 @@ class EmployeeController extends AdminController
     }
 
     //handles employee & dependent  bulk upload with events like inception,addition,deletion, correction and SI enhancements
-    public function employeesUplodWithEvents()
+    public function employeesUplodWithEvents($post_data = [])
     {
 
         // $empDataServiceController = new EmpDataServiceController();
@@ -233,77 +233,184 @@ class EmployeeController extends AdminController
         // $this->truncateFileData(747, 5) ;
         // print_rr($this->cloneWorksheet());
         // die();
-        if ($this->request->getMethod() == 'post') {
+
+        // old
+        // if ($this->request->getMethod() == 'post') {
+
+        //     //validate uploaded file
+        //     $filename = '';
+        //     $fileSize = '';
+        //     $validated = $this->validate([
+        //         'emplist' => [
+        //             'uploaded[emplist]',
+        //             'mime_in[emplist,application/vnd.ms-excel,application/vnd,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.oasis.opendocument.spreadsheet]',
+        //             'max_size[emplist,16384]',
+        //         ],
+        //     ]);
+            
+        //     if ($validated) 
+        //     {
+        //             $avatar = $this->request->getFile('emplist');
+        //             if (!$avatar) {
+        //                 $this->myLogger->logme("error", 'File not found');
+        //                 return $this->respond(['dataStatus' => false, 'code' => 400, 'message' => 'File not found'], 400);
+        //             }
+
+        //             $is_moved = $avatar->move(WRITEPATH . 'uploads/excel/');
+        //             if ($is_moved) {
+        //                 $filename = $avatar->getName();
+        //                 $fileSize = $avatar->getSize(); // File size in bytes
+        //                 $fileSize = $fileSize / (1024 * 1024); // Convert to MB
+        //                 // Handle successful upload, e.g., log success or further processing
+        //                 $this->myLogger->logme("error", 'File move successful');
+                        
+        //             } else {
+        //                 $this->myLogger->logme("error", 'File move failed');
+        //                 return $this->respond(['dataStatus' => false, 'code' => 500, 'message' => 'File move failed'], 500);
+        //             }
+        //     } else {
+        //         $this->myLogger->logme("error", 'Upload failed Invalid file');
+        //         return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'Invalid file'], 404);
+        //     }
+
+        //     //process post variable entry in file table
+        //     $loggedInUserID = get_session_userid();
+        //     // dd($loggedInUserID);
+        //     // $loggedInUserID = 8;
+
+        //     $client_id = $this->request->getPost('client_id');
+        //     $policy_id = $this->request->getPost('policy_id');
+        //     $branch_id = $this->request->getPost('branch_id');
+        //     $enrollment_open_date = $this->request->getPost('enrollment_open_date');
+        //     $enrollment_close_date = $this->request->getPost('enrollment_close_date');
+        //     $action = $this->request->getPost('upload-action-type');
+        //     $status = 'inprogress';
+
+        //     $enrollment_open_date = change_date_format($enrollment_open_date, 'd/m/Y', 'Y-m-d');
+        //     $enrollment_close_date = change_date_format($enrollment_close_date, 'd/m/Y', 'Y-m-d');
+
+        //     $file_id = $this->fileModel->insert(['file_name' => $filename, 'client_id' => $client_id, 'policy_id' => $policy_id, 'created_by' => $loggedInUserID, 'status' => $status, 'action' => $action, 'client_branch_id' => $branch_id,'uploaded_by' => 1, 'enrollment_open_date' => $enrollment_open_date, 'enrollment_close_date' => $enrollment_close_date]); //here field policy_id have client_policy_id and not policy id from policy master
+        //     $this->myLogger->logme("error", '{file_id} uploaded success', ['file_id' => $file_id]);
+
+        //     //start validation process
+        //     if($fileSize < 1) // if file size less than 1
+        //     {
+        //         $empServiceController = new EmployeeServiceController();
+        //         $result = $empServiceController->excelFileFormatValidation(['file_id' => $file_id]);
+        //         $this->myLogger->logme("error", '{file_id} is less than 1MB, validating on the fly', ['file_id' => $file_id]);
+        //         //endof validation process
+        //         if (isset($result['error_summary']) && count($result['error_summary'])) {
+        //             return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'file rejected with errors'], 200);
+        //         }
+        //     }
+        //     else //if file size greater than 1 add the file as job
+        //     {
+        //         $job_details  = new Jobs();
+        //         $r = Jobs::addJob(['job_name' => 'excelFileFormatValidation','payload' => ['file_id' => $file_id]]);
+        //         $this->myLogger->logme("error", '{file_id} is greather than 1MB, validating with job queue', ['file_id' => $file_id]);
+        //     }
+
+        //     return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => 'file upload success'], 200);
+        // }
+
+        if (!empty($post_data) || $this->request->is('post') == 'post') {
 
             //validate uploaded file
             $filename = '';
             $fileSize = '';
-            $validated = $this->validate([
-                'emplist' => [
-                    'uploaded[emplist]',
-                    'mime_in[emplist,application/vnd.ms-excel,application/vnd,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.oasis.opendocument.spreadsheet]',
-                    'max_size[emplist,16384]',
-                ],
-            ]);
-            
-            if ($validated) 
-            {
-                    $avatar = $this->request->getFile('emplist');
-                    if (!$avatar) {
-                        $this->myLogger->logme("error", 'File not found');
+
+            if (empty($post_data)) {
+                $validated = $this->validate([
+                    'emplist' => [
+                        'uploaded[emplist]',
+                        'mime_in[emplist,application/vnd.ms-excel,application/vnd,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.oasis.opendocument.spreadsheet]',
+                        'max_size[emplist,16384]',
+                    ],
+                ]);
+            } else {
+                $validated = validateExcelFile($post_data['emplist']);
+            }
+
+            if ($validated) {
+
+                $avatar = isset($post_data['emplist']) ? $post_data['emplist'] : $this->request->getFile('emplist');
+                if (!$avatar) {
+                    $this->myLogger->logme("error", 'File not found');
+                    if (!empty($post_data)) {
+                        return ['status' => false, 'message' => 'File not found'];
+                    } else {
                         return $this->respond(['dataStatus' => false, 'code' => 400, 'message' => 'File not found'], 400);
                     }
+                }
 
-                    $is_moved = $avatar->move(WRITEPATH . 'uploads/excel/');
-                    if ($is_moved) {
-                        $filename = $avatar->getName();
-                        $fileSize = $avatar->getSize(); // File size in bytes
-                        $fileSize = $fileSize / (1024 * 1024); // Convert to MB
-                        // Handle successful upload, e.g., log success or further processing
-                        $this->myLogger->logme("error", 'File move successful');
-                        
+                $is_moved = $avatar->move(WRITEPATH . 'uploads/excel/');
+                if ($is_moved) {
+                    $filename = $avatar->getName();
+                    $fileSize = $avatar->getSize(); // File size in bytes
+                    $fileSize = $fileSize / (1024 * 1024); // Convert to MB
+                    // Handle successful upload, e.g., log success or further processing
+                    $this->myLogger->logme("error", 'File move successful');
+                } else {
+                    $this->myLogger->logme("error", 'File move failed');
+                    if (!empty($post_data)) {
+                        return ['status' => false, 'message' => 'File move failed'];
                     } else {
-                        $this->myLogger->logme("error", 'File move failed');
                         return $this->respond(['dataStatus' => false, 'code' => 500, 'message' => 'File move failed'], 500);
                     }
+                }
             } else {
                 $this->myLogger->logme("error", 'Upload failed Invalid file');
-                return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'Invalid file'], 404);
+                if (!empty($post_data)) {
+                    return ['status' => false, 'message' => 'Invalid file'];
+                } else {
+                    return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'Invalid file'], 404);
+                }
             }
 
             //process post variable entry in file table
-            $loggedInUserID = get_session_userid();
-            // dd($loggedInUserID);
-            // $loggedInUserID = 8;
+            $loggedInUserID = $post_data['created_by'] ?? get_session_userid();
 
-            $client_id = $this->request->getPost('client_id');
-            $policy_id = $this->request->getPost('policy_id');
-            $branch_id = $this->request->getPost('branch_id');
-            $action = $this->request->getPost('upload-action-type');
-            $status = 'inprogress';
+            $client_id             = isset($post_data['client_id']) ? $post_data['client_id'] : $this->request->getPost('client_id');
+            $policy_id             = isset($post_data['policy_id']) ? $post_data['policy_id'] : $this->request->getPost('policy_id');
+            $branch_id             = isset($post_data['client_branch_id']) ? $post_data['client_branch_id'] : $this->request->getPost('branch_id');
+            $action                = isset($post_data['file_action']) ? $post_data['file_action'] : $this->request->getPost('upload-action-type');
+            $enrollment_open_date  = isset($post_data['enrollment_open_date']) ? $post_data['enrollment_open_date'] : $this->request->getPost('enrollment_open_date') ?? null;
+            $enrollment_close_date = isset($post_data['enrollment_close_date']) ? $post_data['enrollment_close_date'] : $this->request->getPost('enrollment_close_date') ?? null;
+            $status                = 'inprogress';
+            $hr_id                 = $post_data['created_by'] ?? null;
 
-            $file_id = $this->fileModel->insert(['file_name' => $filename, 'client_id' => $client_id, 'policy_id' => $policy_id, 'created_by' => $loggedInUserID, 'status' => $status, 'action' => $action, 'client_branch_id' => $branch_id,'uploaded_by' => 1]); //here field policy_id have client_policy_id and not policy id from policy master
+            $enrollment_open_date = change_date_format($enrollment_open_date, 'd/m/Y', 'Y-m-d');
+            $enrollment_close_date = change_date_format($enrollment_close_date, 'd/m/Y', 'Y-m-d');
+
+            $file_id = $this->fileModel->insert(['file_name' => $filename, 'client_id' => $client_id, 'policy_id' => $policy_id, 'created_by' => $loggedInUserID, 'status' => $status, 'action' => $action, 'client_branch_id' => $branch_id, 'uploaded_by' => 1, 'enrollment_open_date' => $enrollment_open_date, 'enrollment_close_date' => $enrollment_close_date, 'hr_id' => $hr_id]); //here field policy_id have client_policy_id and not policy id from policy master
             $this->myLogger->logme("error", '{file_id} uploaded success', ['file_id' => $file_id]);
 
             //start validation process
-            if($fileSize < 1) // if file size less than 1
+            if ($fileSize < 1) // if file size less than 1
             {
                 $empServiceController = new EmployeeServiceController();
                 $result = $empServiceController->excelFileFormatValidation(['file_id' => $file_id]);
                 $this->myLogger->logme("error", '{file_id} is less than 1MB, validating on the fly', ['file_id' => $file_id]);
                 //endof validation process
                 if (isset($result['error_summary']) && count($result['error_summary'])) {
-                    return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'file rejected with errors'], 200);
+                    if(!empty($post_data)){
+                        return ['status' => true, 'message' => 'file rejected with errors', 'file_id' => $file_id];
+                    }else{
+                        return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'file rejected with errors'], 200);
+                    }
                 }
-            }
-            else //if file size greater than 1 add the file as job
+            } else //if file size greater than 1 add the file as job
             {
                 $job_details  = new Jobs();
-                $r = Jobs::addJob(['job_name' => 'excelFileFormatValidation','payload' => ['file_id' => $file_id]]);
+                $r = Jobs::addJob(['job_name' => 'excelFileFormatValidation', 'payload' => ['file_id' => $file_id]]);
                 $this->myLogger->logme("error", '{file_id} is greather than 1MB, validating with job queue', ['file_id' => $file_id]);
             }
 
-            return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => 'file upload success'], 200);
+            if (!empty($post_data)) {
+                return ['status' => true, 'message' => 'File upload successs, Data validation is in-progress', 'file_id' => $file_id];
+            } else {
+                return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => 'file upload success'], 200);
+            }
         }
 
         $data['page_name'] = 'View Inception';
@@ -328,9 +435,9 @@ class EmployeeController extends AdminController
 
         $data['fileList'] = $this->fileModel
                             ->select([
-                                'files.id','files.file_name','files.created_by','files.created_at','files.is_active','files.status','files.client_id','files.policy_id','files.client_branch_id','files.action','files.uploaded_by',
+                                'files.id','files.file_name','files.created_by','files.created_at','files.is_active','files.status','files.client_id','files.policy_id','files.client_branch_id','files.action','files.uploaded_by', 'enrollment_open_date', 'enrollment_close_date',
                                 'up.emp_code',
-                                'up.first_name',
+                                // 'up.first_name',
                                 'c.short_name',
                                 'cb.branch_name',
                                 'cp.id as client_policy_id',
@@ -344,8 +451,23 @@ class EmployeeController extends AdminController
                                   WHERE e.file_id = files.id AND ep.client_policy_id = files.policy_id) as total',
                                  'policy_type.policy_type' ,
                                  'cp.policy_no' ,
+                                 "CASE
+                                    WHEN files.hr_id IS NOT NULL THEN
+                                        CONCAT(
+                                            (
+                                                SELECT lc.name
+                                                FROM level_contacts lc
+                                                WHERE lc.id = files.hr_id
+                                                LIMIT 1
+                                            ),
+                                            ' (HR)'
+                                        )
+                                    ELSE up.first_name
+                                END AS first_name
+                                ",
+                                'files.hr_id'
                             ])
-                            ->join('user_profiles up', 'files.created_by = up.id')
+                            ->join('user_profiles up', 'files.created_by = up.id', 'left')
                             ->join('client_policy cp', 'files.policy_id = cp.id', 'left')
                             ->join('client_branch cb', 'files.client_branch_id = cb.id', 'left')
                             ->join('policy_type', 'policy_type.id = cp.policy_type_id')
@@ -378,14 +500,22 @@ class EmployeeController extends AdminController
         }
     }
 
-    public function getExcelFileErrors()
+    public function getExcelFileErrors($file_id, $retun_type)
     {
-        $file_id = $this->request->uri->getSegment(3);
+        // $file_id = $this->request->uri->getSegment(3);
         $empServiceController = new EmployeeServiceController();
 
         // Render views and capture output
         $result = $empServiceController->getExcelErrorData($file_id);
 
+        if($retun_type == 'api'){
+            if(!empty($result)){
+                return $this->respond(['status' => true, 'code' => 200, 'message' => 'Error data feteched successfully', 'data' => $result], 200);
+            }else{
+                return $this->respond(['status' => false, 'code' => 404,  'message' => 'Failed to fetch error data', 'data' => []], 200);
+            }
+        }
+
         if ($result != 0) {
 
             $result['file_id'] = $file_id;
@@ -2828,7 +2958,7 @@ class EmployeeController extends AdminController
         if (!is_dir($exportDir)) {
             mkdir($exportDir, 0777, true);
         } else {
-            chmod($exportDir, 0777);
+            // chmod($exportDir, 0777);
         }
 
         $filename = 'inception_export_' . date('Ymd_His') . '.xlsx';
diff --git a/app/Controllers/EmployeeRestController.php b/app/Controllers/EmployeeRestController.php
index f3d0b2f..e810120 100755
--- a/app/Controllers/EmployeeRestController.php
+++ b/app/Controllers/EmployeeRestController.php
@@ -236,7 +236,7 @@ class EmployeeRestController extends AdminController
             $data = $this->request->getJSON();
 
             //enrolment check
-            $openForEnrollment = $this->findThePolicyIsOpenForEnrollment($data[0]->client_policy_id);
+            $openForEnrollment = $this->findThePolicyIsOpenForEnrollment($data[0]->client_policy_id, $data[0]->emp_code);
             if($openForEnrollment == false){  
                 return $this->respond(['status' => 'failed','code' => 404,'data' => [],'message' => 'Enrollment closed.'], 200); 
             }
@@ -369,7 +369,20 @@ class EmployeeRestController extends AdminController
             $basic_cover_si = $policy_terms->sum_insured;
             }
 
-            $checkDataExist = $this->employeePolicyModel->where('employee_id',$employee_id)->where('client_policy_id',$client_policy_id)->first();
+            $other_employee_policy_data = $this->employeePolicyModel
+                ->select('employee_polices.*')
+                ->join('employees', 'employee_polices.employee_id = employees.id', 'left')
+                ->where('employees.emp_code', $emp_code)
+                ->where('employee_polices.client_policy_id', $client_policy_id)
+                ->where('employee_polices.is_active', 1)
+                ->where('employees.is_active', 1)
+                ->whereIn('employee_polices.status', ['draft', 'enrolled'])
+                ->whereIn('employees.emp_status', ['draft', 'enrolled'])                
+                ->where('employee_polices.enrollment_open_date is not null')
+                ->where('employee_polices.enrollment_close_date is not null')
+                ->first();
+
+            $checkDataExist = $this->employeePolicyModel->where('employee_id',$employee_id)->where('client_policy_id',$client_policy_id)->where('is_active', 1)->first();
 
             if($checkDataExist){
 
@@ -389,6 +402,11 @@ class EmployeeRestController extends AdminController
                 $data['status']= 'draft';
                 $data['date_coverage'] = $this->getEmployeeCoverageDate($emp_code, $client_policy_id);
 
+                if(!empty($other_employee_policy_data)){
+                    $data['enrollment_open_date']= $other_employee_policy_data['enrollment_open_date'] ?? null;
+                    $data['enrollment_close_date']= $other_employee_policy_data['enrollment_close_date'] ?? null;
+                }
+
                 // dd($data);
                 $this->employeePolicyModel->insert($data);
 
@@ -470,7 +488,6 @@ class EmployeeRestController extends AdminController
         }else{ return null; }
     }
 
-
     public function RelationshipMap($value){
        
             if ($value === 'Mother' || $value === 'Father') {
@@ -526,16 +543,30 @@ class EmployeeRestController extends AdminController
         try {
             
             if($this->request->getGet('id'))
-            {
-                $this->employeeModel->where('id', $this->request->getGet('id') )
-                                    ->where('is_active', 1 )
-                                    ->set(array('is_active'=> 0 ))
-                                    ->update();
+            {   
+                $is_from_copy = $this->request->getGet('is_from_copy') ?? null;
+
+                if($is_from_copy == 'false' || $is_from_copy == false || $is_from_copy == 'null' || $is_from_copy == null){
+
+                    $this->employeeModel->where('id', $this->request->getGet('id') )
+                                        ->where('is_active', 1 )
+                                        ->set(array('is_active'=> 0 ))
+                                        ->update();
+                }
+
+                $query = $this->employeePolicyModel
+                                ->where('employee_id', $this->request->getGet('id'))
+                                ->where('is_active', 1);
+
+                // 👉 Add condition only if client_policy_id exists
+                $clientPolicyId = $this->request->getGet('client_policy_id') ?? null;
+                if (!empty($clientPolicyId)) {
+                    $query->where('client_policy_id', $clientPolicyId);
+                }
+
+                $query->set(['is_active' => 0])->update();
+
 
-                $this->employeePolicyModel->where('employee_id',$this->request->getGet('id') )
-                                            ->where('is_active', 1 )
-                                            ->set(array('is_active'=> 0 ))
-                                            ->update();
                 return $this->respond(['status' => 'success','code' => 200,'data' =>[] ], 200);
                
             }else{
@@ -559,7 +590,7 @@ class EmployeeRestController extends AdminController
             // print_r($requestData);
             // dd($requestData);
 
-            $openForEnrollment = $this->findThePolicyIsOpenForEnrollment($requestData[0]->client_policy_id);
+            $openForEnrollment = $this->findThePolicyIsOpenForEnrollment($requestData[0]->client_policy_id, $requestData[0]->emp_code);
             if($openForEnrollment == false){  return $this->respond(['status' => 'failed','code' => 404,'data' => 'Enrollment closed'], 404); }
 
             foreach ($requestData as $key => $value) 
@@ -755,8 +786,48 @@ class EmployeeRestController extends AdminController
         
     }
 
-    // Upload the Employee Detail in DB by Sheet Data
     public function employeeUpload()
+    {
+        try{
+
+            $post_data = [
+                'client_id'             => $this->request->getPost('client_id') ?? null,
+                'client_branch_id'      => $this->request->getPost('client_branch_id'),
+                'policy_id'             => $this->request->getPost('policy_id'),
+                'enrollment_open_date'  => $this->request->getPost('enrollment_open_date'),
+                'enrollment_close_date' => $this->request->getPost('enrollment_close_date'),
+                'file_action'           => "enrollment",
+                'created_by'            => $this->request->getPost('created_by'),
+                'emplist'               => $this->request->getFile('file')
+            ];
+            // print_r($post_data); die;
+
+            if(empty($post_data['client_id'])){
+                return $this->respondCreated(['status' => false, 'message' => 'Client is required', 'data' => []]);
+            }
+
+            $employeeController = new EmployeeController();
+            $responce = $employeeController->employeesUplodWithEvents($post_data);
+            // print_r($responce); die;
+
+            if($responce['status']){
+                $file_data = $this->getDataFromFilesTable(['file_id' => $responce['file_id']]);
+                $responce['data'] = $file_data;
+                return $this->respond($responce, 200);
+            }else{
+                $responce['data'] = [];
+                return $this->respond($responce, 200);
+            }
+
+            
+
+        }catch(\Exception $e){
+            return $this->respondCreated(['status' => false, 'message' => $e->getMessage(), 'data' => []]);
+        }
+    }
+
+    // Upload the Employee Detail in DB by Sheet Data  (DO NOT REMOVE THIS)
+    public function employeeUploadOld()
     {
         try {
             $file = $this->request->getFile('file');
@@ -1114,9 +1185,69 @@ class EmployeeRestController extends AdminController
             return $this->respond(['status' => 'failed','code' => 500,'data' => $th->getMessage(), 'error_data' =>  $errorData], 500);
         }
 
-        
+    }
 
-        
+    public function getDataFromFilesTable($search_data)
+    {
+        $file_download_base = base_url('util/download-file-list/');
+        $builder = $this->fileModel
+            ->select("
+                    files.id, 
+                    files.client_id, 
+                    files.client_branch_id, 
+                    files.policy_id, 
+                    cp.policy_no, 
+                    files.file_name, 
+                    files.action, 
+                    files.created_at, 
+                    files.created_by, 
+                    files.updated_at, 
+                    files.updated_by,
+                    c.short_name, 
+                    cb.branch_name, 
+                    lc.name as first_name,
+                    CONCAT(UCASE(LEFT(files.status, 1)), LCASE(SUBSTRING(files.status, 2))) as status,
+                    CASE 
+                        WHEN status = 'failed' THEN 1 
+                        ELSE 0 
+                    END AS file_error_status,
+                    CONCAT('{$file_download_base}', files.id, '/api') AS file_download_link
+                ", false)
+            ->join('clients c', 'files.client_id = c.id AND c.is_active = 1', 'left')
+            ->join('client_branch cb', 'files.client_branch_id = cb.id AND cb.is_active = 1', 'left')
+            ->join('client_policy cp', 'files.policy_id = cp.id AND cp.is_active = 1', 'left')
+            ->join('level_contacts lc', 'files.hr_id = lc.id AND lc.contact_type = "client" AND lc.is_active = 1', 'left');
+
+
+        if (isset($search_data['policy_id']) && !empty($search_data['policy_id'])) {
+            $builder->where("files.policy_id", $search_data['policy_id']);
+        }
+
+        if (isset($search_data['created_by']) && !empty($search_data['created_by'])) {
+            $builder->where("files.hr_id", $search_data['created_by']);
+        }
+
+        if (isset($search_data['policy_no']) && !empty($search_data['policy_no'])) {
+            $builder->where("cp.policy_no", $search_data['policy_no']);
+        }
+
+        if (isset($search_data['client_id']) && !empty($search_data['client_id'])) {
+            $builder->where("files.client_id", $search_data['client_id']);
+        }
+
+        if (isset($search_data['file_id']) && !empty($search_data['file_id'])) {
+            $builder->where("files.id", $search_data['file_id']);
+        }
+
+
+        // Execute query
+        $data = $builder->get()->getResultArray();
+
+        if (!empty($data)) {
+            return $data;
+        }
+
+        return [];
     }
 
 
@@ -1160,13 +1291,25 @@ class EmployeeRestController extends AdminController
 
                                             
             if ($empPolicy) {
-
+                
+                $latest_gmc_policy_id = getLatestGMCPolicy((array)$empPolicy);
                 $result = [];
                 foreach ($empPolicy as $array) { 
-                    // Reset employee array
-                    $empData = $employeeData;
 
-                
+                    // Reset employee array
+                    // $empData = $employeeData;
+                    $empData = $this->employeeModel
+                            ->select('employees.*')
+                            ->join('employee_polices', 'employee_polices.employee_id = employees.id')
+                            ->where('employees.emp_code',$emp_code)
+                            ->where('employees.client_id',$client_id)
+                            ->where('employees.client_branch_id',$client_branch_id)
+                            ->where('employee_polices.client_policy_id',$array->ClientPolicyId)
+                            ->where('employees.is_active', 1 )
+                            ->where('employee_polices.is_active', 1 )
+                            ->where('employees.is_addon_value',0)
+                            ->findAll();
+                        
                     // Removes specific keys from the decoded array and assigns the result to $refusingData
                     $decodedArray = json_decode($array->Policy_Terms);
                     $refusingData = (object) array_diff_key((array) $decodedArray, array_flip($keysToRemove));
@@ -1248,6 +1391,11 @@ class EmployeeRestController extends AdminController
                         $array->to_be_added_relationship = [];
                         $array->existing_relationship = [];
                         
+                        if(!empty($latest_gmc_policy_id) && $latest_gmc_policy_id == $array->ClientPolicyId){
+                            $array->copy_dependence_data_enable = true;
+                        }else{
+                             $array->copy_dependence_data_enable = false;
+                        }
                     
                         // Map family floaters that already exist in the employee table
                         $familyFloates = $array->Policy_Terms->family_floaters;
@@ -1415,25 +1563,55 @@ class EmployeeRestController extends AdminController
 
                         $array->mapped_family_floaters = $data;
                         $array->type = "GMC";
-                        $array->family_floaters_of_dependent_and_si_value = $dependent_and_si_value > 0 ?  $dependent_and_si_value : 0;
+                        $array->family_floaters_of_dependent_and_si_value = $dependent_and_si_value > 0 ?  $dependent_and_si_value : 0.0;
                         if($array->is_premium_summery == 1){
-                            $array->family_floaters_of_dependent_and_si_premium_value = $dependent_and_si_premium_value > 0 ?  round($dependent_and_si_premium_value) : 0;
-                            $array->family_floaters_of_dependent_and_gst_value = $dependent_and_si_gst_value > 0 ?  round($dependent_and_si_gst_value) : 0;
+                            $array->family_floaters_of_dependent_and_si_premium_value = $dependent_and_si_premium_value > 0 ?  round($dependent_and_si_premium_value) : 0.0;
+                            $array->family_floaters_of_dependent_and_gst_value = $dependent_and_si_gst_value > 0 ?  round($dependent_and_si_gst_value) : 0.0;
                         }else{
-                            $array->family_floaters_of_dependent_and_si_premium_value = 0;
-                            $array->family_floaters_of_dependent_and_gst_value =  0;  
+                            $array->family_floaters_of_dependent_and_si_premium_value = 0.0;
+                            $array->family_floaters_of_dependent_and_gst_value =  0.0;  
                         }
                     
-                        $checkGmcParentsPolicyExist = $this->clientPolicyModel->select('client_policy.id as ClientPolicyId , client_policy.client_id as ClientId, client_policy.policy_type_id as policy_type_id, policy_type.long_name as Policy_Name , client_policy.is_addon as is_addon , client_policy.open_for_enrollment as OpenForEnrollment , client_policy.inception_type  as inception_type , client_policy.policy_terms as Policy_Terms , client_policy.is_premium_summery as is_premium_summery, client_policy.enrolment_visibility')
-                                                                                ->join('policy_type', 'client_policy.policy_type_id = policy_type.id', 'left')
-                                                                                ->where('client_policy.policy_type_id',  3 )
-                                                                                ->where('client_policy.is_addon',  1 )
-                                                                                ->where('client_policy.client_id', $this->request->getGet('client_id') )
-                                                                                ->where('client_policy.client_branch_id', $this->request->getGet('client_branch_id') )
-                                                                                ->where('client_policy.is_active', 1 )
-                                                                                ->where('client_policy.enrolment_visibility', 1 )
-                                                                                ->get()
-                                                                                ->getResult();
+                        $checkGmcParentsPolicyExist = $this->clientPolicyModel->select("
+                                                                                    client_policy.id as ClientPolicyId, 
+                                                                                    client_policy.client_id as ClientId, 
+                                                                                    client_policy.policy_type_id as policy_type_id, 
+                                                                                    policy_type.long_name as Policy_Name , 
+                                                                                    client_policy.is_addon as is_addon ,
+                                                                                    (
+                                                                                        SELECT COALESCE(
+                                                                                            MAX(
+                                                                                                CASE
+                                                                                                    WHEN ep.enrollment_open_date <= CURDATE()
+                                                                                                    AND ep.enrollment_close_date >= CURDATE()
+                                                                                                    THEN 1
+                                                                                                    ELSE 0
+                                                                                                END
+                                                                                            ), 0
+                                                                                        )
+                                                                                        FROM employee_polices ep
+                                                                                        INNER JOIN employees e ON e.id = ep.employee_id
+                                                                                        WHERE e.is_active = 1
+                                                                                        AND ep.is_active = 1
+                                                                                        AND ep.enrollment_open_date IS NOT NULL
+                                                                                        AND ep.enrollment_close_date IS NOT NULL
+                                                                                        AND e.emp_code = '{$emp_code}'
+                                                                                        AND ep.client_policy_id = client_policy.id
+                                                                                    ) AS OpenForEnrollment,
+                                                                                    client_policy.inception_type  as inception_type , 
+                                                                                    client_policy.policy_terms as Policy_Terms , 
+                                                                                    client_policy.is_premium_summery as is_premium_summery, 
+                                                                                    client_policy.enrolment_visibility
+                                                                                ")
+                                                                            ->join('policy_type', 'client_policy.policy_type_id = policy_type.id', 'left')
+                                                                            ->where('client_policy.policy_type_id',  3 )
+                                                                            ->where('client_policy.is_addon',  1 )
+                                                                            ->where('client_policy.client_id', $this->request->getGet('client_id') )
+                                                                            ->where('client_policy.client_branch_id', $this->request->getGet('client_branch_id') )
+                                                                            ->where('client_policy.is_active', 1 )
+                                                                            ->where('client_policy.enrolment_visibility', 1 )
+                                                                            ->get()
+                                                                            ->getResult();
                         if($checkGmcParentsPolicyExist)
                         {
                             $GmcParrentsData =  $this->getGmcParrentsPolicy($checkGmcParentsPolicyExist,$emp_code,$client_id,$client_branch_id);
@@ -1442,7 +1620,7 @@ class EmployeeRestController extends AdminController
                             $result[] = $GmcParrentsData;
                         }
 
-                        if($this->request->getGet('policy') == 'GMC'){
+                        if($this->request->getGet('policy') == 'GMC' && !$checkGmcParentsPolicyExist){
                             // return $this->respond(['status' => 'success','code' => 200,'data' => [$array]], 200);
                             $result[] = $array;
                         }
@@ -1453,7 +1631,8 @@ class EmployeeRestController extends AdminController
                 }
 
                 if(!empty($result) && $this->request->getGet('policy') == 'GMC'){
-                    return $this->respond(['status' => 'success','code' => 200,'data' => $result], 200);
+                    // return $this->respond(['status' => 'success','code' => 200,'data' => $result], 200);
+                    echo json_encode(['status' => 'success','code' => 200,'data' => $result], JSON_PRETTY_PRINT | JSON_PRESERVE_ZERO_FRACTION);
                 }else{
                     return $this->respond(['status' => 'success','code' => 200,'data' => []], 200);
                 }
@@ -1462,6 +1641,7 @@ class EmployeeRestController extends AdminController
             }else{
                 return $this->respond(['status' => 'failed','code' => 404,'data' => []], 200);
             }
+            
         } catch (\Exception $e) {
 
             $errorData = [
@@ -1483,11 +1663,11 @@ class EmployeeRestController extends AdminController
     public function getGmcParrentsPolicy($GmcParrentsPolicy,$emp_code,$client_id,$client_branch_id)
     {
 
-        $employeeData = $this->employeeModel->where('emp_code',$emp_code)
-                                            ->where('client_id',$client_id)
-                                            ->where('client_branch_id',$client_branch_id)
-                                            ->where('is_active', 1 )
-                                            ->where('is_addon_value',0)->findAll();
+        // $employeeData = $this->employeeModel->where('emp_code',$emp_code)
+        //                                     ->where('client_id',$client_id)
+        //                                     ->where('client_branch_id',$client_branch_id)
+        //                                     ->where('is_active', 1 )
+        //                                     ->where('is_addon_value',0)->findAll();
         // return  $employeeData;
         foreach ($GmcParrentsPolicy as $key => $array) {
 
@@ -1496,8 +1676,18 @@ class EmployeeRestController extends AdminController
         
 
             // Reset employee array
-            $empData = $employeeData;
-
+            // $empData = $employeeData;
+            $empData = $this->employeeModel
+                            ->select('employees.*')
+                            ->join('employee_polices', 'employee_polices.employee_id = employees.id')
+                            ->where('employees.emp_code',$emp_code)
+                            ->where('employees.client_id',$client_id)
+                            ->where('employees.client_branch_id',$client_branch_id)
+                            ->where('employee_polices.client_policy_id',$array->ClientPolicyId)
+                            ->where('employees.is_active', 1 )
+                            ->where('employee_polices.is_active', 1 )
+                            ->where('employees.is_addon_value',0)
+                            ->findAll();
 
             $array->Policy_Terms = json_decode($array->Policy_Terms);
 
@@ -1511,6 +1701,7 @@ class EmployeeRestController extends AdminController
                                             ->join('employee_polices', 'employee_polices.employee_id = employees.id')
                                             ->where('employees.emp_code',$emp_code)
                                             ->where('employees.is_active',1)
+                                            ->where('employee_polices.is_active',1)
                                             ->where('employee_polices.client_policy_id',$array->ClientPolicyId)
                                             ->get()
                                             ->getResult();
@@ -1627,29 +1818,29 @@ class EmployeeRestController extends AdminController
 
             // Add family floter buttons placement data for FE validation
             if(count($floters)){
-            foreach ($floters as $familyFloatesValue) {
+                foreach ($floters as $familyFloatesValue) {
 
-                $temp2['is_value_exist'] = false;
-                $temp2['data']['family_floater_key'] = $familyFloatesValue;
-                $temp2['data']['relationship'] = ucfirst(str_replace('_', ' ', preg_replace('/\d/', '', $familyFloatesValue))); 
-                $temp2['data']['client_policy_id'] = $array->ClientPolicyId; 
-                $temp2['data']['button_name'] = 'Add '.ucfirst(str_replace('_', ' ', preg_replace('/\d/', '', $familyFloatesValue))); 
-                $temp2['data']['form_type'] = preg_replace('/\d/', '', $familyFloatesValue);
-                $temp2['data']['age_validation'] = $this->getAgeRange($array->Policy_Terms,$familyFloatesValue);     
-                array_push($data,$temp2);
+                    $temp2['is_value_exist'] = false;
+                    $temp2['data']['family_floater_key'] = $familyFloatesValue;
+                    $temp2['data']['relationship'] = ucfirst(str_replace('_', ' ', preg_replace('/\d/', '', $familyFloatesValue))); 
+                    $temp2['data']['client_policy_id'] = $array->ClientPolicyId; 
+                    $temp2['data']['button_name'] = 'Add '.ucfirst(str_replace('_', ' ', preg_replace('/\d/', '', $familyFloatesValue))); 
+                    $temp2['data']['form_type'] = preg_replace('/\d/', '', $familyFloatesValue);
+                    $temp2['data']['age_validation'] = $this->getAgeRange($array->Policy_Terms,$familyFloatesValue);     
+                    array_push($data,$temp2);
 
 
-                array_push($array->to_be_added_relationship,['relationship'=>$temp2['data']['relationship'],'age_validation'=>$temp2['data']['age_validation']]);
-                $array->to_be_added_relationship = array_values(
-                    array_map('unserialize',
-                        array_unique(
-                            array_map('serialize', $array->to_be_added_relationship)
+                    array_push($array->to_be_added_relationship,['relationship'=>$temp2['data']['relationship'],'age_validation'=>$temp2['data']['age_validation']]);
+                    $array->to_be_added_relationship = array_values(
+                        array_map('unserialize',
+                            array_unique(
+                                array_map('serialize', $array->to_be_added_relationship)
+                            )
                         )
-                    )
-                );
+                    );
 
+                }
             }
-        }
 
         $array->relationship = [];
         foreach ($array->to_be_added_relationship as $key => $value) {
@@ -1685,13 +1876,13 @@ class EmployeeRestController extends AdminController
 
             $array->mapped_family_floaters = $data;
             $array->type = "GMC - Parents";
-            $array->family_floaters_of_dependent_and_si_value = $dependent_and_si_value > 0 ?  $dependent_and_si_value : 0;
+            $array->family_floaters_of_dependent_and_si_value = $dependent_and_si_value > 0 ?  $dependent_and_si_value : 0.0;
             if($array->is_premium_summery == 1){
-                $array->family_floaters_of_dependent_and_si_premium_value = $dependent_and_si_premium_value > 0 ?  round($dependent_and_si_premium_value) : 0;
-                $array->family_floaters_of_dependent_and_gst_value = $dependent_and_si_gst_value > 0 ?  round($dependent_and_si_gst_value) : 0;
+                $array->family_floaters_of_dependent_and_si_premium_value = $dependent_and_si_premium_value > 0 ?  round($dependent_and_si_premium_value) : 0.0;
+                $array->family_floaters_of_dependent_and_gst_value = $dependent_and_si_gst_value > 0 ?  round($dependent_and_si_gst_value) : 0.0;
             }else{
-                $array->family_floaters_of_dependent_and_si_premium_value = 0;
-                $array->family_floaters_of_dependent_and_gst_value = 0;
+                $array->family_floaters_of_dependent_and_si_premium_value = 0.0;
+                $array->family_floaters_of_dependent_and_gst_value = 0.0;
             }
 
             return $array;
@@ -1703,7 +1894,36 @@ class EmployeeRestController extends AdminController
 
     public function getAdditionalGPAPolicy($empData,$policy_type,$emp_code,$client_id,$client_branch_id,$login_by_hr)
     {
-        $checkPolicyExist = $this->clientPolicyModel->select('client_policy.id as ClientPolicyId , client_policy.client_id as ClientId,  client_policy.policy_type_id as policy_type_id,  client_policy.is_addon as is_addon , client_policy.open_for_enrollment as OpenForEnrollment , client_policy.inception_type  as inception_type , client_policy.policy_terms as Policy_Terms , client_policy.enrolment_visibility,client_policy.is_premium_summery')
+        $checkPolicyExist = $this->clientPolicyModel->select("
+                                                                client_policy.id as ClientPolicyId , 
+                                                                client_policy.client_id as ClientId,  
+                                                                client_policy.policy_type_id as policy_type_id,  
+                                                                client_policy.is_addon as is_addon ,
+                                                                (
+                                                                    SELECT COALESCE(
+                                                                        MAX(
+                                                                            CASE
+                                                                                WHEN ep.enrollment_open_date <= CURDATE()
+                                                                                AND ep.enrollment_close_date >= CURDATE()
+                                                                                THEN 1
+                                                                                ELSE 0
+                                                                            END
+                                                                        ), 0
+                                                                    )
+                                                                    FROM employee_polices ep
+                                                                    INNER JOIN employees e ON e.id = ep.employee_id
+                                                                    WHERE e.is_active = 1
+                                                                    AND ep.is_active = 1
+                                                                    AND ep.enrollment_open_date IS NOT NULL
+                                                                    AND ep.enrollment_close_date IS NOT NULL
+                                                                    AND e.emp_code = '{$emp_code}'
+                                                                    AND ep.client_policy_id = client_policy.id
+                                                                ) AS OpenForEnrollment, 
+                                                                client_policy.inception_type  as inception_type , 
+                                                                client_policy.policy_terms as Policy_Terms , 
+                                                                client_policy.enrolment_visibility,
+                                                                client_policy.is_premium_summery
+                                                            ")
                                                     ->where('client_policy.policy_type_id',  $policy_type )
                                                     ->where('client_policy.is_addon',  1 )
                                                     ->where('client_policy.client_id', $client_id )
@@ -2019,6 +2239,7 @@ class EmployeeRestController extends AdminController
     {            
         try {
 
+            $emp_code = $this->request->getGet('emp_code');
             $addOnEmployeeData = $this->employeeModel->where('is_active', 1 )
                                                     ->where('emp_code',$this->request->getGet('emp_code'))
                                                     ->where('client_id',$this->request->getGet('client_id'))
@@ -2027,7 +2248,30 @@ class EmployeeRestController extends AdminController
 
        
 
-            $clientPolicy = $this->clientPolicyModel->where('client_id',$this->request->getGet('client_id'))
+            $clientPolicy = $this->clientPolicyModel->select("
+                                                                client_policy.*, 
+                                                                 (
+                                                                    SELECT COALESCE(
+                                                                        MAX(
+                                                                            CASE
+                                                                                WHEN ep.enrollment_open_date <= CURDATE()
+                                                                                AND ep.enrollment_close_date >= CURDATE()
+                                                                                THEN 1
+                                                                                ELSE 0
+                                                                            END
+                                                                        ), 0
+                                                                    )
+                                                                    FROM employee_polices ep
+                                                                    INNER JOIN employees e ON e.id = ep.employee_id
+                                                                    WHERE e.is_active = 1
+                                                                    AND ep.is_active = 1
+                                                                    AND ep.enrollment_open_date IS NOT NULL
+                                                                    AND ep.enrollment_close_date IS NOT NULL
+                                                                    AND e.emp_code = '{$emp_code}'
+                                                                    AND ep.client_policy_id = client_policy.id
+                                                                ) AS open_for_enrollment
+                                                            ")
+                                                    ->where('client_id',$this->request->getGet('client_id'))
                                                     ->where('client_branch_id',$this->request->getGet('client_branch_id'))
                                                     ->where('policy_status', 1)
                                                     ->where('is_active', 1)
@@ -2036,6 +2280,7 @@ class EmployeeRestController extends AdminController
             
             if(count($clientPolicy))
             {
+
             $self = $this->employeeModel->where('employees.is_active', 1)
                         ->where('employees.emp_code', $this->request->getGet('emp_code'))
                         ->where('employees.client_id', $this->request->getGet('client_id'))
@@ -2280,13 +2525,13 @@ class EmployeeRestController extends AdminController
                         }
                    
                         $responce['family_floaters_of_dependent_and_si_array'] = $data;
-                        $responce['family_floaters_of_dependent_and_si_value'] = $dependent_and_si_value > 0 ?  $dependent_and_si_value : 0;
+                        $responce['family_floaters_of_dependent_and_si_value'] = $dependent_and_si_value > 0 ?  $dependent_and_si_value : 0.0;
                         if($array['is_premium_summery']){
-                            $responce['family_floaters_of_dependent_and_si_premium_value'] = $dependent_and_si_premium_value > 0 ?  round($dependent_and_si_premium_value) : 0;
-                            $responce['family_floaters_of_dependent_and_gst_value'] = $dependent_and_si_gst_value > 0 ?  round($dependent_and_si_gst_value) : 0;
+                            $responce['family_floaters_of_dependent_and_si_premium_value'] = $dependent_and_si_premium_value > 0 ?  round($dependent_and_si_premium_value) : 0.0;
+                            $responce['family_floaters_of_dependent_and_gst_value'] = $dependent_and_si_gst_value > 0 ?  round($dependent_and_si_gst_value) : 0.0;
                         }else{
-                            $responce['family_floaters_of_dependent_and_si_premium_value'] = 0;
-                            $responce['family_floaters_of_dependent_and_gst_value'] = 0;
+                            $responce['family_floaters_of_dependent_and_si_premium_value'] = 0.0;
+                            $responce['family_floaters_of_dependent_and_gst_value'] = 0.0;
                         }
                         
 
@@ -2295,7 +2540,8 @@ class EmployeeRestController extends AdminController
                     
 
                     if($this->request->getGet('policy') == 'GMC-DEPENDENT-ADDON'){
-                        return $this->respond(['status' => 'success','code' => 200,'data' => ['gmc_dependent_addon'=>$responce]], 200);
+                        // return $this->respond(['status' => 'success','code' => 200,'data' => ['gmc_dependent_addon'=>$responce]], 200);
+                        echo json_encode(['status' => 'success','code' => 200,'data' => ['gmc_dependent_addon'=>$responce]], JSON_PRETTY_PRINT | JSON_PRESERVE_ZERO_FRACTION);
                     }
                 
                     //array_push($PolicyData, $responce);
@@ -2462,7 +2708,8 @@ class EmployeeRestController extends AdminController
             $array_list = [];
             foreach ($client_policy_id as $key => $value) 
             {
-                $policy = $this->clientPolicyModel->where('id',$value)->where('open_for_enrollment',1)->find();
+                // $policy = $this->clientPolicyModel->where('id',$value)->where('open_for_enrollment',1)->find();
+                $policy = $this->findThePolicyIsOpenForEnrollment($client_policy_id, $emp_code);
                 if($policy)
                 {
                     $this->myLogger->logme("error", 'client policy id = '.$value.' is open for enrollment');
@@ -3589,20 +3836,33 @@ class EmployeeRestController extends AdminController
     }
 
 
-    public function findThePolicyIsOpenForEnrollment($plicy_id)
+    public function findThePolicyIsOpenForEnrollment($policy_id, $emp_code)
     {
 
-        $policy = $this->clientPolicyModel->where('id',$plicy_id)->where('open_for_enrollment',1)->find();
-
+        // $policy = $this->clientPolicyModel->where('id',$plicy_id)->where('open_for_enrollment',1)->find();
+        $policy = $this->employeePolicyModel
+                        ->join('employees', 'employee_polices.employee_id = employees.id')
+                        ->where('employees.emp_code',$emp_code)
+                        ->where('employee_polices.client_policy_id',$policy_id)
+                        ->where('employee_polices.enrollment_open_date <= CURDATE()', null, false)
+                        ->where('employee_polices.enrollment_close_date >= CURDATE()', null, false)
+                        ->where('employee_polices.enrollment_open_date is not null')
+                        ->where('employee_polices.enrollment_close_date is not null')
+                        ->where('employees.is_active', 1)
+                        ->where('employee_polices.is_active', 1)
+                        ->whereIn('employee_polices.status', ['draft', 'enrolled'])
+                        ->whereIn('employees.emp_status', ['draft', 'enrolled'])
+                        ->first();
+        
         if($policy)
-        return true;
+            return true;
         else
-        return false;
+            return false;
 
     }
 
 
-    public function getPreEmployeePolicyCount()
+    public function getPreEmployeePolicyCountOld()
     {
         log_message('error', 'STEP 1: getPreEmployeePolicyCount API called');
 
@@ -3650,6 +3910,7 @@ class EmployeeRestController extends AdminController
                 ->join('client_policy cp', 'employee_polices.client_policy_id = cp.id')
                 ->where('employees.is_active', 1)
                 ->whereIn('employees.emp_status', ['draft', 'enrolled'])
+                ->where('employees.family_floater_key', 'self')
                 ->where('employee_polices.is_active', 1)
                 ->whereIn('employee_polices.status', ['draft', 'enrolled'])
                 ->where('cp.enrolment_visibility', 1)
@@ -3686,6 +3947,161 @@ class EmployeeRestController extends AdminController
         }
     }
 
+    public function getPreEmployeePolicyCount()
+    {
+        log_message('error', 'STEP 1: getPreEmployeePolicyCount API called');
+
+        $request            = $this->request->getJSON(true);
+        $mobile_no          = $request['mobile_number'] ?? null;
+        $email_id           = $request['email_id'] ?? null;
+        $client_short_name  = $request['client_short_name'] ?? null;
+
+        log_message('error', 'STEP 2: Received input - ' . json_encode($request));
+
+        /** ---------------------------------------------------------------
+         *   STEP 3: Resolve Client ID (If client_short_name passed)
+         * --------------------------------------------------------------- */
+        $clientId = null;
+        if (!empty($client_short_name)) {
+            log_message('error', 'STEP 3: Looking up client with short_name: ' . $client_short_name);
+
+            $client = $this->clientModel
+                        ->select('id')
+                        ->where('is_active', 1)
+                        ->where('short_name', $client_short_name)
+                        ->first();
+            
+            if (!empty($client)) {
+                $clientId = $client['id'];
+                log_message('error', 'STEP 4: Found client ID: ' . $clientId);
+            } else {
+                log_message('error', 'STEP 4: No client found for short_name: ' . $client_short_name);
+            }
+        } else {
+            log_message('error', 'STEP 3: client_short_name is empty.');
+        }
+
+        /** ---------------------------------------------------------------
+         *   STEP 4: Validate Request (either mobile or email is required)
+         * --------------------------------------------------------------- */
+        if (empty($mobile_no) && empty($email_id)) {
+            log_message('error', 'STEP 5: Mobile number and Email both empty. Returning 0.');
+            return $this->respond(['data' => 0, 'empNotEnrolledCount' => 0]);
+        }
+
+        try {
+            /** ---------------------------------------------------------------
+             *   STEP 6: Base Query Builder (extract common conditions)
+             * --------------------------------------------------------------- */
+            $baseQuery = $this->employeeModel
+                ->join('employee_polices', 'employees.id = employee_polices.employee_id')
+                ->join('client_policy cp', 'employee_polices.client_policy_id = cp.id')
+                ->where('employees.is_active', 1)
+                ->where('employee_polices.is_active', 1)
+                ->where('cp.enrolment_visibility', 1)
+                // ->where('cp.open_for_enrollment', 1)
+                ->where('employee_polices.enrollment_open_date <= CURDATE()', null, false)
+                ->where('employee_polices.enrollment_close_date >= CURDATE()', null, false)
+                ->where('cp.policy_status', 1)
+                ->whereIn('cp.policy_type_id', [1, 2, 3, 6, 7])
+                ->orderBy('employees.created_at', 'desc')
+                ->groupBy('employee_polices.client_policy_id');
+
+            // 🔹 Apply Client Filter if Provided
+            if (!empty($clientId)) {
+                $baseQuery->where('employees.client_id', $clientId);
+                log_message('error', 'Applied client ID filter: ' . $clientId);
+            }
+
+            // 🔹 Apply Mobile Filter if Provided
+            if (!empty($mobile_no)) {
+                $baseQuery->where('employees.mobile', $mobile_no);
+                log_message('error', 'Applied mobile_no filter: ' . $mobile_no);
+            }
+
+            // 🔹 Apply Email Filter if Provided
+            if (!empty($email_id)) {
+                $baseQuery->where('employees.email_corporate', $email_id);
+                log_message('error', 'Applied email_id filter: ' . $email_id);
+            }
+
+            /** ---------------------------------------------------------------
+             *   STEP 7: Count Enrolled + Draft (eligible)
+             * --------------------------------------------------------------- */
+            $baseQuery->whereIn('employees.emp_status', ['draft', 'enrolled'])
+                        ->whereIn('employee_polices.status', ['draft', 'enrolled'])
+                        ->where('employees.family_floater_key', 'self');
+
+            $count = $baseQuery->get()->getNumRows();
+            log_message('error', 'Eligible policy count = ' . $count);
+
+            /** ---------------------------------------------------------------
+             *   STEP 8: Count Only Draft (Not Enrolled yet)
+             * --------------------------------------------------------------- */
+            $notEnrolledQuery = $this->employeeModel
+                ->select("
+                    (
+                        SELECT COUNT(e2.id)
+                        FROM employees AS e2
+                        WHERE e2.is_active = 1
+                        AND e2.emp_status = 'draft'
+                        AND e2.emp_code = employees.emp_code
+                    ) AS draft_count
+                ")
+                ->join('employee_polices', 'employees.id = employee_polices.employee_id')
+                ->join('client_policy cp', 'employee_polices.client_policy_id = cp.id')
+                ->where('employees.is_active', 1)
+                ->where('employee_polices.is_active', 1)
+                ->where('cp.enrolment_visibility', 1)
+                // ->where('cp.open_for_enrollment', 1)
+                ->where('employee_polices.enrollment_open_date <= CURDATE()', null, false)
+                ->where('employee_polices.enrollment_close_date >= CURDATE()', null, false)
+                ->where('cp.policy_status', 1)
+                ->whereIn('cp.policy_type_id', [1, 2, 3, 6, 7])
+                ->orderBy('employees.created_at', 'desc');
+
+            // 🔹 Apply Client Filter if Provided
+            if (!empty($clientId)) {
+                $notEnrolledQuery->where('employees.client_id', $clientId);
+                log_message('error', 'Applied client ID filter: ' . $clientId);
+            }
+
+            // 🔹 Apply Mobile Filter if Provided
+            if (!empty($mobile_no)) {
+                $notEnrolledQuery->where('employees.mobile', $mobile_no);
+                log_message('error', 'Applied mobile_no filter: ' . $mobile_no);
+            }
+
+            // 🔹 Apply Email Filter if Provided
+            if (!empty($email_id)) {
+                $notEnrolledQuery->where('employees.email_corporate', $email_id);
+                log_message('error', 'Applied email_id filter: ' . $email_id);
+            }
+
+            $notEnrolledQuery->whereIn('employees.emp_status', ['draft'])
+                            ->whereIn('employee_polices.status', ['draft']);
+
+            $not_enrolled_count = $notEnrolledQuery->get()->getRowArray()['draft_count'] ?? 0;
+            log_message('error', 'Not enrolled policy count = ' . $not_enrolled_count);
+
+            /** ---------------------------------------------------------------
+             *   STEP 9: Final Response
+             * --------------------------------------------------------------- */
+            return $this->respond([
+                'pre_policy_count'        => $count,
+                'emp_not_enrolled_count'  => (int) $not_enrolled_count
+            ]);
+
+        } catch (\Throwable $e) {
+            log_message('error', 'Exception occurred: ' . $e->getMessage());
+            return $this->respond([
+                'pre_policy_count'        => 0,
+                'emp_not_enrolled_count'  => 0
+            ]);
+        }
+    }
+
+
 
 
     //--------------------------------------------------------------------------------------------
@@ -3882,7 +4298,7 @@ class EmployeeRestController extends AdminController
         $empData = $this->employeeModel
             ->where('emp_code', $emp_code)
             ->where('client_id', $client_id)
-            ->where('emp_status', 'enrolled')
+            // ->where('emp_status', 'enrolled')
             ->where('is_active', 1)
             ->findAll();
         
@@ -3890,10 +4306,17 @@ class EmployeeRestController extends AdminController
             return $this->respond(['status' => "failed", 'code' => 404, 'message' => "employee data not found", 'data' => []], 200);
         }
 
+        $selfData = array_column(
+            array_filter($empData, function($row) {
+                return isset($row['relationship']) && strtolower($row['relationship']) == 'self';
+            }),
+            'id'
+        );
+
+        $selfId = !empty($selfData) ? reset($selfData) : null;
         $floters = $this->FloterConvertion($family_floaters);
 
         $data = [];
-
         foreach ($floters as $familyFloatesValue) {
 
             $dependent =   preg_replace('/\d/', '', $familyFloatesValue);
@@ -3902,6 +4325,8 @@ class EmployeeRestController extends AdminController
                 foreach ($empData as $key => $value) {
                     if ($value['family_floater_key'] === $dependent) {
 
+                        $employee_policy = $this->employeePolicyModel->where('employee_id', $selfId)->where('client_policy_id',$new_client_policy_id)->where('is_active', 1 )->get()->getRow();
+
                         $temp['is_value_exist'] = true;
                         $temp['data']['family_floater_key'] = $familyFloatesValue;
                         $temp['data']['employee_id'] = $value['id'];
@@ -3910,7 +4335,7 @@ class EmployeeRestController extends AdminController
                         $temp['data']['dob'] = $this->convertDateFormatDMY($value['dob']);
                         $temp['data']['client_policy_id'] = $new_client_policy_id;
                         $temp['data']['form_type'] = $dependent;
-                        $temp['data']['basic_cover_si'] = null;
+                        $temp['data']['basic_cover_si'] = isset($employee_policy->basic_cover_si) ? $employee_policy->basic_cover_si : 0;
 
 
                         $temp['data']['age_validation'] = $this->getAgeRange($policy_terms, $familyFloatesValue);
diff --git a/app/Controllers/EmployeeServiceController.php b/app/Controllers/EmployeeServiceController.php
index 300e6aa..c52ebd7 100755
--- a/app/Controllers/EmployeeServiceController.php
+++ b/app/Controllers/EmployeeServiceController.php
@@ -1069,6 +1069,20 @@ class EmployeeServiceController extends AdminController
                                 }
                             }
 
+                            // check the employee code if dublicate exist
+                            if(($file['action'] == 'inception' || $file['action'] == 'missed_inception' || $file['action'] == 'addition' || $file['action'] == 'enrollment'))
+                            {
+                                $res = check_emp_code_duplication($family, $file);
+                                // dd($res);
+                                if($res['status'])
+                                {   
+                                    foreach ($res['row_ids'] as $row_id) {
+                                        array_push($result['error_summary'],26);
+                                        $result['error_data'][ $row_id ]['emp_id']['error'][] = "Employee Code is already exist in the system";
+                                    }
+                                }
+                            }
+
                             //check self avaialbe  either same policy DB level(i.e.) gMC parents
                             if($file['action'] == 'dependent_addition' || ($policy_details['policy_type_id'] == 3 && !$is_self_available_in_policy_terms)) // 3 is GMC parents as base policy not as dep addon)
                             {
@@ -1981,221 +1995,251 @@ public function getFileMetaDataByFileId($file_id, $status = 'success'){
     public function employeesEnrollmentInsert($params)
     {
         // dd($this->request);
-            helper('excel_util_helper');
-            //get file name
-            $file_id = $params['file_id'];
-            $file = $this->fileModel->find($file_id);
-            // dd($file);
-            $return = [];
-            if(!isset($file))
-            {
-                //file not found in DB
-                return array('status' => false, 'msg' => 'file not found in DB');
-            }
-            $file_name_with_path = WRITEPATH."/uploads/excel/".$file['file_name'];
-            
-            //check physical file
-            if(!file_exists($file_name_with_path))
-            {
-                //file not found  update status and reason 
-                 $message = "Physical file not found";
-                // echo $message;
-                $this->myLogger->logme('error',($message . ' for file id ' . $file_id));
-                 $this->fileModel->where('id', $file_id)->set(['status' => 'failed','reason' => json_encode(['error_summary' => array_count_values([5]),'error_data' => $message])])->update();
-                return  array('error_summary' => [5], 'error_data' => $message);
-            }
+        helper('excel_util_helper');
+        //get file name
+        $file_id = $params['file_id'];
+        $file = $this->fileModel->find($file_id);
+        // dd($file);
+        $return = [];
+        if (!isset($file)) {
+            //file not found in DB
+            return array('status' => false, 'msg' => 'file not found in DB');
+        }
+        $file_name_with_path = WRITEPATH . "/uploads/excel/" . $file['file_name'];
 
-            //get excel data
-            $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path);
-            $sheet = $spreadsheet->getActiveSheet();
-            
-            $highestRowAndColumn = $sheet->getHighestRowAndColumn();
-            $result = ['error_type' => 2,'error_summary' => [], 'error_data' => [] ];
-            $columns_to_check = $this->enrollment_excel_columns;
-            $keys = array_keys($columns_to_check);
-            $allowedHighestColumn = end($columns_to_check);
-            $excel_data = $sheet->rangeToArray('A1:' . $allowedHighestColumn['col_cell_name'] . $highestRowAndColumn['row']);
-            // print_r($keys);die();
-             //get existing units in the current branch
-            $existing_units = $this->clientBranchModel->getExisitingUnits(client_id: $file['client_id'],client_branch_id: $file['client_branch_id']);
-            //remove header
-            unset($excel_data[0]);
-            // dd($excel_data);
-            $emp_emails = [];
+        //check physical file
+        if (!file_exists($file_name_with_path)) {
+            //file not found  update status and reason 
+            $message = "Physical file not found";
+            // echo $message;
+            $this->myLogger->logme('error', ($message . ' for file id ' . $file_id));
+            $this->fileModel->where('id', $file_id)->set(['status' => 'failed', 'reason' => json_encode(['error_summary' => array_count_values([5]), 'error_data' => $message])])->update();
+            return  array('error_summary' => [5], 'error_data' => $message);
+        }
 
-            //check is welcome notification enabled
-            $notification = $this->notificationModel->where('client_id',$file['client_id'])->where('template_name','member_welcome_mail')->first();
-            // dd($notification);
-            $client_details = $this->clientModel->where('id', $file['client_id'])->first();
-            $policy_details = $this->clientPolicyModel->where('id', $file['policy_id'])->first();
+        //get excel data
+        $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path);
+        $sheet = $spreadsheet->getActiveSheet();
 
-            // dd($policy_details);
-            
-            //get policy slab rates 
-            // $slab_details = $this->policiesModel->getPolicySlabRatesForEmpOnboard($file['policy_id'],$file['client_id']);
-            // dd($slab_details);
+        $highestRowAndColumn = $sheet->getHighestRowAndColumn();
+        $result = ['error_type' => 2, 'error_summary' => [], 'error_data' => []];
+        $columns_to_check = $this->enrollment_excel_columns;
+        $keys = array_keys($columns_to_check);
+        $allowedHighestColumn = end($columns_to_check);
+        $excel_data = $sheet->rangeToArray('A1:' . $allowedHighestColumn['col_cell_name'] . $highestRowAndColumn['row']);
+        // print_r($keys);die();
+        //get existing units in the current branch
+        $existing_units = $this->clientBranchModel->getExisitingUnits(client_id: $file['client_id'], client_branch_id: $file['client_branch_id']);
+        //remove header
+        unset($excel_data[0]);
+        // dd($excel_data);
+        $emp_emails = [];
 
-            foreach ($excel_data as $key => $row) 
-            {
-                $is_row_empty = check_row_is_empty_or_null($row);
-                if(!$is_row_empty)
-                {
+        //check is welcome notification enabled
+        $notification = $this->notificationModel->where('client_id', $file['client_id'])->where('template_name', 'member_welcome_mail')->first();
+        // dd($notification);
+        $client_details = $this->clientModel->where('id', $file['client_id'])->first();
+        $policy_details = $this->clientPolicyModel->where('id', $file['policy_id'])->first();
 
-                    $value = [];
-                    $policy_data = [];
-                    $temp_unit = '';
-                    if(empty($row[12]))
-                    {
-                        $temp_unit = $existing_units[0];
-                    }
-                   
-                    $value['emp_code'] = $row[1];
-                    $value['name'] = $row[2];
-                    $value['doj'] = (!empty($row[3]) ? change_date_format($row[3],'d-M-Y','Y-m-d') : null );
-                    $value['gender'] = $row[4];
-                    $value['relationship'] = ucfirst(trim($row[5]));
-                    $value['dob'] = change_date_format($row[6],'d-M-Y','Y-m-d');
-                    $value['email_corporate'] = $row[7];
-                    $value['mobile'] = $row[8];
-                    $value['band'] = $row[10];
-                    $value['basic_pay'] = $row[11];
-                    $value['unit'] = $temp_unit;
-                    $value['family_floater_key'] = null;
-                    $value['client_id'] = $file['client_id'];
-                    $value['client_branch_id'] = $file['client_branch_id'];
-                    $value['file_id'] = $file_id;
-                    $value['is_addon_value'] = $policy_details['policy_type_id'] == 3 ? 1 : 0;
+        // dd($policy_details);
 
-                    $value['temp']['emp_id'] = null; // dummy value for using exisitng funciton in model
-                    if (strtolower(trim($value['relationship'])) === 'mother' || strtolower(trim($value['relationship'])) === 'father') {
-                                $relation = 'parent';
-                            } else if(strtolower(trim($value['relationship'])) === 'son' || strtolower(trim($value['relationship'])) === 'daughter'){
-                                $relation = 'child';
-                            }else if((strtolower(trim($value['relationship'])) === 'father in law' || strtolower(trim($value['relationship'])) === 'mother in law') || (strtolower(trim($value['relationship'])) === 'father-in-law' || strtolower(trim($value['relationship'])) === 'mother-in-law')){
-                                $relation = 'parent_in_law';
-                            }else if(strtolower(trim($value['relationship'])) === 'spouse'){
-                                $relation = 'spouse';
-                            }else if(strtolower(trim($value['relationship'])) === 'self'){
-                                $relation = 'self';
-                            }else {
-                                $relation = '';
-                            }
-                            $value['family_floater_key'] = $relation;
+        //get policy slab rates 
+        // $slab_details = $this->policiesModel->getPolicySlabRatesForEmpOnboard($file['policy_id'],$file['client_id']);
+        // dd($slab_details);
+        $parent_policy_mail_sended_emp_code = [];
+        foreach ($excel_data as $key => $row) {
+            $is_row_empty = check_row_is_empty_or_null($row);
+            if (!$is_row_empty) {
 
-                            $policy_data['basic_cover_si'] = $row[9];
-                            $policy_data['date_coverage'] = $row[13] != "" && $row[13] != null ? change_date_format($row[13],'d-M-Y','Y-m-d') : null;
-                            $policy_data['client_policy_id'] = $file['policy_id'];
-
-                             $employee = $this->employeeModel->checkExistingEmployee($value,$file['client_branch_id']);
-                             unset($value['temp']);
-                            //save employee table
-                             // dd($employee['id']);
-                            if($employee !== null)
-                            {
-                                $value['updated_by'] = $file['created_by'];
-                                $value['id'] = $employee['id'];
-                                $value['emp_status'] = 'draft';
-                                
-                                $log_message = 'Enrollment Update Employee - '.$employee['name'].'('.$employee['emp_code'].') with PK '.$employee['id'];
-                            }
-                            else
-                            {
-                                $value['emp_status'] = 'draft';
-                                $value['created_by'] = $file['created_by'];
-                                $log_message = 'Enrollment Insert Employee- '.$value['name'] .'('.$value['emp_code'] .') with PK ';
-                            }
-                            $value = ExcelSanitizeHelper::sanitizeArrayData($value);
-
-                            $this->employeeModel->save($value);
-                             if (isset($value['id'])) 
-                             {  $emp_id = $value['id']; } 
-                             else { $emp_id = $this->employeeModel->getInsertID(); 
-                                    $log_message .= $emp_id;
-                             }
-
-                            // $emp_id = $this->employeeModel->getInsertID();
-                            // if($emp_id != 0){  $log_message .= $emp_id; }
-                            // else{ $emp_id = $employee['id']; }
-                            
-                            $this->myLogger->logme('error',$log_message);
-
-                            //save policy table
-                            $employee_policy = $this->employeePolicyModel->checkExistingEmpPolicy(['employee_id' => $emp_id,'client_policy_id' => $file['policy_id']]);
-                            if(count($employee_policy))
-                            {
-                                $policy_data['updated_by'] = $file['created_by'];
-                                $policy_data['id'] = $employee_policy[0]['id'];
-                                $policy_data['status'] = 'draft';
-                                $policy_data['payable_employee'] = check_pay_by_employee_or_company($policy_details['policy_terms'], $value['relationship']);
-                                $policy_data['file_id'] = isset($employee_policy[0]['file_id']) && $employee_policy[0]['file_id'] != '' ? $employee_policy[0]['file_id'] : $file_id ;
-                                $log_message = 'Update Employee Policy for '. $value['name'].'('. $value['emp_code'].') with PK- ' . $employee_policy[0]['id'] .' client policy ID '.$employee_policy[0]['client_policy_id'].' with SI '.$policy_data['basic_cover_si'];
-                                // echo 'insert policy';
-                            }
-                            else
-                            {
-                                $policy_data['employee_id'] = $emp_id;
-                                $policy_data['client_policy_id'] = $file['policy_id'];
-                                $policy_data['created_by'] = $file['created_by'];
-                                $policy_data['status'] = 'draft';
-                                $policy_data['payable_employee'] = check_pay_by_employee_or_company($policy_details['policy_terms'], $value['relationship']);
-                                $policy_data['file_id'] = $file_id;
-                                $log_message = 'Insert Employee Policy for '. $value['name'].'('. $value['emp_code'].') - client policy id -'. $file['policy_id'].' - with SI '.$policy_data['basic_cover_si'];
-                                // echo 'update policy';
-                            }
-
-                            log_message('error',json_encode($policy_data));
-                            // dd($policy_data);
-                            $this->employeePolicyModel->save($policy_data);
-                            $emp_policy_id = $this->employeePolicyModel->getInsertID();
-                            $this->myLogger->logme('error',$log_message);
-
-                            $employeeRestController = new EmployeeRestController();
-                            $employeeRestController->updatePremiumAmount($file['policy_id'], $value['emp_code'], $file['client_branch_id']);
-                    
-
-                            //save email of self for send mail later
-                            if (isset($notification) && $notification['enabled'] == 1 && $notification['mail_content'] != '') 
-                            {
-                                if(strtolower($value['relationship']) == 'self' && $value['email_corporate'] != "")
-                                {
-                                    $params['dataToInsert'] = $value; //holds employee master data
-                                    $params['notification'] = $notification;
-                                    $params['client_data'] = $client_details;
-                                    $params['common'] = [
-                                        'client_id' => $file['client_id'],
-                                        'client_branch_id' => $file['client_branch_id'],
-                                        'client_policy_id' => $file['policy_id'],
-                                        'employee_policy_id' => $emp_policy_id ?? null,
-                                        'employee_id' => $emp_id,
-                                        'mail_type' => 'member_welcome_mail',
-                                    ];
-                                   //store email and mail content via helper to send notification
-                                   $emp_emails[] = sendMailNotification::sendMailNotification('member_welcome_mail', $params);
-                                }
-                            }
-                }// endof if row is empty check
-            } //end of for loop
-
-            // dd($emp_emails);
-
-             // for bulk mail queue job push  
-            if (!empty($emp_emails) && count($emp_emails) > 0) {
-
-                $emp_emails = array_chunk($emp_emails, 20);
-
-                foreach ($emp_emails as $key => $value) {
-                    $job_details  = new Jobs();
-                    $r = Jobs::addJob(['job_name' => 'bulk_mail', 'payload' => $value]);
+                $value = [];
+                $policy_data = [];
+                $temp_unit = '';
+                if (empty($row[12])) {
+                    $temp_unit = $existing_units[0];
                 }
+
+                $value['emp_code'] = $row[1];
+                $value['name'] = $row[2];
+                $value['doj'] = (!empty($row[3]) ? change_date_format($row[3], 'd-M-Y', 'Y-m-d') : null);
+                $value['gender'] = $row[4];
+                $value['relationship'] = ucfirst(trim($row[5]));
+                $value['dob'] = change_date_format($row[6], 'd-M-Y', 'Y-m-d');
+                $value['email_corporate'] = $row[7];
+                $value['mobile'] = $row[8];
+                $value['band'] = $row[10];
+                $value['basic_pay'] = $row[11];
+                $value['unit'] = $temp_unit;
+                $value['family_floater_key'] = null;
+                $value['client_id'] = $file['client_id'];
+                $value['client_branch_id'] = $file['client_branch_id'];
+                $value['file_id'] = $file_id;
+                $value['is_addon_value'] = $policy_details['policy_type_id'] == 3 ? 1 : 0;
+
+                $value['temp']['emp_id'] = null; // dummy value for using exisitng funciton in model
+                if (strtolower(trim($value['relationship'])) === 'mother' || strtolower(trim($value['relationship'])) === 'father') {
+                    $relation = 'parent';
+                } else if (strtolower(trim($value['relationship'])) === 'son' || strtolower(trim($value['relationship'])) === 'daughter') {
+                    $relation = 'child';
+                } else if ((strtolower(trim($value['relationship'])) === 'father in law' || strtolower(trim($value['relationship'])) === 'mother in law') || (strtolower(trim($value['relationship'])) === 'father-in-law' || strtolower(trim($value['relationship'])) === 'mother-in-law')) {
+                    $relation = 'parent_in_law';
+                } else if (strtolower(trim($value['relationship'])) === 'spouse') {
+                    $relation = 'spouse';
+                } else if (strtolower(trim($value['relationship'])) === 'self') {
+                    $relation = 'self';
+                } else {
+                    $relation = '';
+                }
+                $value['family_floater_key'] = $relation;
+
+                $policy_data['basic_cover_si'] = $row[9];
+                $policy_data['date_coverage'] = $row[13] != "" && $row[13] != null ? change_date_format($row[13], 'd-M-Y', 'Y-m-d') : null;
+                $policy_data['client_policy_id'] = $file['policy_id'];
+                $policy_data['enrollment_open_date'] = $file['enrollment_open_date'] ?? null;
+                $policy_data['enrollment_close_date'] = $file['enrollment_close_date'] ?? null;
+
+
+                $employee = $this->employeeModel->checkExistingEmployee($value, $file['client_branch_id']);
+                unset($value['temp']);
+                //save employee table
+                // dd($employee['id']);
+                if ($employee !== null) {
+                    $value['updated_by'] = $file['created_by'];
+                    $value['id'] = $employee['id'];
+                    $value['emp_status'] = 'draft';
+
+                    $log_message = 'Enrollment Update Employee - ' . $employee['name'] . '(' . $employee['emp_code'] . ') with PK ' . $employee['id'];
+                } else {
+                    $value['emp_status'] = 'draft';
+                    $value['created_by'] = $file['created_by'];
+                    $log_message = 'Enrollment Insert Employee- ' . $value['name'] . '(' . $value['emp_code'] . ') with PK ';
+                }
+                $value = ExcelSanitizeHelper::sanitizeArrayData($value);
+
+                $this->employeeModel->save($value);
+                if (isset($value['id'])) {
+                    $emp_id = $value['id'];
+                } else {
+                    $emp_id = $this->employeeModel->getInsertID();
+                    $log_message .= $emp_id;
+                }
+
+                // $emp_id = $this->employeeModel->getInsertID();
+                // if($emp_id != 0){  $log_message .= $emp_id; }
+                // else{ $emp_id = $employee['id']; }
+
+                $this->myLogger->logme('error', $log_message);
+
+                //save policy table
+                $employee_policy = $this->employeePolicyModel->checkExistingEmpPolicy(['employee_id' => $emp_id, 'client_policy_id' => $file['policy_id']]);
+                if (count($employee_policy)) {
+                    $policy_data['updated_by'] = $file['created_by'];
+                    $policy_data['id'] = $employee_policy[0]['id'];
+                    $policy_data['status'] = 'draft';
+                    $policy_data['payable_employee'] = check_pay_by_employee_or_company($policy_details['policy_terms'], $value['relationship']);
+                    $policy_data['file_id'] = isset($employee_policy[0]['file_id']) && $employee_policy[0]['file_id'] != '' ? $employee_policy[0]['file_id'] : $file_id;
+                    $log_message = 'Update Employee Policy for ' . $value['name'] . '(' . $value['emp_code'] . ') with PK- ' . $employee_policy[0]['id'] . ' client policy ID ' . $employee_policy[0]['client_policy_id'] . ' with SI ' . $policy_data['basic_cover_si'];
+                    // echo 'insert policy';
+                } else {
+                    $policy_data['employee_id'] = $emp_id;
+                    $policy_data['client_policy_id'] = $file['policy_id'];
+                    $policy_data['created_by'] = $file['created_by'];
+                    $policy_data['status'] = 'draft';
+                    $policy_data['payable_employee'] = check_pay_by_employee_or_company($policy_details['policy_terms'], $value['relationship']);
+                    $policy_data['file_id'] = $file_id;
+                    $log_message = 'Insert Employee Policy for ' . $value['name'] . '(' . $value['emp_code'] . ') - client policy id -' . $file['policy_id'] . ' - with SI ' . $policy_data['basic_cover_si'];
+                    // echo 'update policy';
+                }
+
+                log_message('error', json_encode($policy_data));
+                // dd($policy_data);
+                $this->employeePolicyModel->save($policy_data);
+                $emp_policy_id = $this->employeePolicyModel->getInsertID();
+                $this->myLogger->logme('error', $log_message);
+
+                $employeeRestController = new EmployeeRestController();
+                $employeeRestController->updatePremiumAmount($file['policy_id'], $value['emp_code'], $file['client_branch_id']);
+
+
+                //save email of self for send mail later
+                if (isset($notification) && $notification['enabled'] == 1 && $notification['mail_content'] != '') {
+                    if (strtolower($value['relationship']) == 'self' && $value['email_corporate'] != "") {
+                        $params['dataToInsert'] = $value; //holds employee master data
+                        $params['notification'] = $notification;
+                        $params['client_data'] = $client_details;
+                        $params['common'] = [
+                            'client_id' => $file['client_id'],
+                            'client_branch_id' => $file['client_branch_id'],
+                            'client_policy_id' => $file['policy_id'],
+                            'employee_policy_id' => $emp_policy_id ?? null,
+                            'employee_id' => $emp_id,
+                            'mail_type' => 'member_welcome_mail',
+                        ];
+                        $params['enrollment_open_date'] = $file['enrollment_open_date'] ?? null;
+                        $params['enrollment_close_date'] = $file['enrollment_close_date'] ?? null;
+
+                        //store email and mail content via helper to send notification
+                        $emp_emails[] = sendMailNotification::sendMailNotification('member_welcome_mail', $params);
+                    } else if ($policy_details['policy_type_id'] == 3 && $policy_details['is_addon'] == 3 && !in_array($row[1], $parent_policy_mail_sended_emp_code)) {
+
+                        $sefData = $this->employeeModel
+                            ->where('is_active', 1)
+                            ->whereIn('emp_status', ['draft', 'enrolled'])
+                            ->where('family_floater_key', 'self')
+                            ->where('emp_code', $row[1])
+                            ->where('client_id', $file['client_id'])
+                            ->where('client_branch_id', $file['client_branch_id'])
+                            ->where('email_corporate is not null')
+                            ->first();
+
+                        if (!empty($sefData)) {
+
+                            $value['email_corporate'] = $sefData['email_corporate'];
+                            $value['name'] = $sefData['name'];
+                            $value['mobile'] = $sefData['mobile'];
+
+                            $params['dataToInsert'] = $value; //holds employee master data
+                            $params['notification'] = $notification;
+                            $params['client_data'] = $client_details;
+                            $params['common'] = [
+                                'client_id' => $file['client_id'],
+                                'client_branch_id' => $file['client_branch_id'],
+                                'client_policy_id' => $file['policy_id'],
+                                'employee_policy_id' => $emp_policy_id ?? null,
+                                'employee_id' => $emp_id,
+                                'mail_type' => 'member_welcome_mail',
+                            ];
+                            $params['enrollment_open_date'] = $file['enrollment_open_date'] ?? null;
+                            $params['enrollment_close_date'] = $file['enrollment_close_date'] ?? null;
+
+                            //store email and mail content via helper to send notification
+                            $emp_emails[] = sendMailNotification::sendMailNotification('member_welcome_mail', $params);
+                            $parent_policy_mail_sended_emp_code[] = $row[1];
+                        }
+                    }
+                }
+            } // endof if row is empty check
+        } //end of for loop
+
+        // dd($emp_emails);
+
+        // for bulk mail queue job push  
+        if (!empty($emp_emails) && count($emp_emails) > 0) {
+
+            $emp_emails = array_chunk($emp_emails, 20);
+
+            foreach ($emp_emails as $key => $value) {
+                $job_details  = new Jobs();
+                $r = Jobs::addJob(['job_name' => 'bulk_mail', 'payload' => $value]);
             }
+        }
 
-            $this->fileModel->where('id', $file_id)->set(['status' => 'success','reason' => ''])->update();
-            $this->myLogger->logme("error",'{file_id} uploaded success',['file_id' => $file_id]);
+        $this->fileModel->where('id', $file_id)->set(['status' => 'success', 'reason' => ''])->update();
+        $this->myLogger->logme("error", '{file_id} uploaded success', ['file_id' => $file_id]);
 
-            $this->setPullNotification($this->getFileMetaDataByFileId($file_id,'success'));
+        $this->setPullNotification($this->getFileMetaDataByFileId($file_id, 'success'));
 
 
-            return true;
-    }//end of employeesEnrollmentInsert
+        return true;
+    } //end of employeesEnrollmentInsert
 
 }
\ No newline at end of file
diff --git a/app/Controllers/LoginController.php b/app/Controllers/LoginController.php
index 830fb02..eb3d98e 100755
--- a/app/Controllers/LoginController.php
+++ b/app/Controllers/LoginController.php
@@ -9,6 +9,7 @@ use Psr\Log\LoggerInterface;
 
 use App\Models\UserModel;
 use App\Models\AuthHistoryModel;
+use App\Libraries\AuthLogout;
 
 class LoginController extends BaseController
 {
@@ -54,25 +55,29 @@ class LoginController extends BaseController
                         $path = getenv('cookie.Path');
                         $domain = getenv('cookie.Domain');
                         $https = getenv('ccokie.secure');
-                        setcookie('session_data', json_encode($session_data), time() + 12 * 60 * 60, $path, $domain, $https, true);
+                        // setcookie('session_data', json_encode($session_data), time() + 12 * 60 * 60, $path, $domain, $https, true);
                         set_session_data($session_data);
 
+                         // Bind session to device
+                        set_session_data(['fingerprint' =>  hash('sha256',
+                            ($this->request->getUserAgent()->getAgentString() . '|' . ($this->request->getIPAddress()
+                        )))]);
                         log_message('error', 'Set The UserId : `'. $user->id .'` in Session');
                         log_message('error', 'User Login Sucessfully');
 
                         $this->getUserDeviceInfo($user->id, 'NhanceUser');
-                        return redirect()->to(base_url('/dashboard/view'));
+                        return AuthLogout::logout();
 
                     }else{
                         log_message('error', 'User Not Active');
                         session()->setFlashdata('error', 'User Not Active');
-                        return redirect()->to(base_url('login'));
+                        return AuthLogout::logout();
                     }
                 }else{
 
                     log_message('error', 'User Not Registered');
                     session()->setFlashdata('error', 'User Not Registered');
-                    return redirect()->to(base_url('login'));
+                    return AuthLogout::logout();
                 }
             }
 
@@ -94,14 +99,16 @@ class LoginController extends BaseController
         // setcookie('session_data', '', time() - 3600, $path);
         // return redirect()->to(base_url('login'));
 
-        $path = getenv('cookie.Path');
-        session()->destroy();
-        // setcookie('session_data', '', time() - 3600, $path);
-        $path = getenv('cookie.Path');
-        $domain = getenv('cookie.Domain');
-        $https = getenv('cookie.secure');
-        setcookie('session_data',null, time() -3600, $path, $domain, $https, true);
-        return redirect()->to(base_url('login'));
+        // $path = getenv('cookie.Path');
+        // session()->destroy();
+        // // setcookie('session_data', '', time() - 3600, $path);
+        // $path = getenv('cookie.Path');
+        // $domain = getenv('cookie.Domain');
+        // $https = getenv('cookie.secure');
+        // setcookie('session_data',null, time() -3600, $path, $domain, $https, true);
+        // return redirect()->to(base_url('login'));
+
+        return AuthLogout::logout();
     }
 
 
diff --git a/app/Controllers/MasterController.php b/app/Controllers/MasterController.php
index c1722ad..24527ad 100755
--- a/app/Controllers/MasterController.php
+++ b/app/Controllers/MasterController.php
@@ -37,6 +37,7 @@ use App\Models\SettingsModel;
 use App\Models\VehicleModel;
 
 use CodeIgniter\CLI\CLI;
+use CodeIgniter\CLI\BaseCommand;
 
 class MasterController extends AdminController
 {   
@@ -1741,6 +1742,7 @@ class MasterController extends AdminController
             'cache' => WRITEPATH . 'cache',
             'sample_import_excel' => ROOTPATH . 'public/sample_import_excel',
             'lead_files' => WRITEPATH . 'uploads/lead_files/',
+            'exports' => WRITEPATH . 'exports/',
         ];
 
         foreach ($folders as $folderName => $folderPath) {
@@ -1822,4 +1824,78 @@ class MasterController extends AdminController
         echo "################################################################\n\n";
     }
 
+
+     public function checkEnv()
+    {
+        $root = ROOTPATH;
+        
+        $sample_file_name = '.env.sample';
+        $sample_file_path = $root . $sample_file_name;
+        
+        $envFile     = $root . '.env';
+        // echo ($exampleFile);//die();
+         if (!file_exists($sample_file_path)) {
+            echo ("$sample_file_path file not found");
+            exit();
+        }
+
+        if (!file_exists($envFile)) {
+            echo('.env file not found');
+             exit();
+        }
+
+        $example = $this->parseEnv($sample_file_path);
+        $actual  = $this->parseEnv($envFile);
+
+        $missing = array_diff_key($example, $actual);
+        $extra   = array_diff_key($actual, $example);
+
+       CLI::write("#################### CHECKING ENV  ##############################\n");
+        if ($extra) {
+            CLI::write('⚠️  Extra ENV keys (not in .env.example)', 'yellow');
+            foreach (array_keys($extra) as $key) {
+                CLI::write("  - $key", 'yellow');
+            }
+        }
+
+        CLI::newLine();
+        if ($missing) {
+            CLI::error('❌ Missing ENV keys');
+            foreach (array_keys($missing) as $key) {
+                CLI::write("  - $key", 'red');
+            }
+        }
+
+         CLI::newLine();
+        if (!$missing && !$extra) {
+            CLI::write('✅ ENV configuration is clean', 'green');
+            return CLI::EXIT_SUCCESS;
+        }
+
+       CLI::write("#################### END OF CHECKING ENV ############################\n");
+
+
+    }
+
+    private function parseEnv(string $file): array
+    {
+        $lines = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+        $env   = [];
+
+        foreach ($lines as $line) {
+            $line = trim($line);
+
+            if ($line === '' || str_starts_with($line, '#')) {
+                continue;
+            }
+
+            if (strpos($line, '=') !== false) {
+                [$key] = explode('=', $line, 2);
+                $env[trim($key)] = true;
+            }
+        }
+
+        return $env;
+    }
+
 }
\ No newline at end of file
diff --git a/app/Filters/AuthMVC.php b/app/Filters/AuthMVC.php
index 0a9f7a6..e6c6948 100755
--- a/app/Filters/AuthMVC.php
+++ b/app/Filters/AuthMVC.php
@@ -5,12 +5,29 @@ use CodeIgniter\Filters\FilterInterface;
 use CodeIgniter\HTTP\RequestInterface;
 use CodeIgniter\HTTP\ResponseInterface;
 
+use App\Libraries\AuthLogout;
+
 class AuthMVC implements FilterInterface
 {
     public function before(RequestInterface $request, $arguments = null)
     {
-        if (!check_session() && !check_cookie()) {            
-          return redirect()->to(base_url('/login'));
+         if (!check_session()) 
+        {
+          return AuthLogout::logout();
+        }
+
+        // if (!check_cookie()) 
+        // {
+        //   return AuthLogout::logout();
+        // }
+
+        // Fingerprint validation
+        $fp = hash('sha256', 
+            $request->getUserAgent()->getAgentString() . '|' . $request->getIPAddress()
+        );
+
+        if (session()->get('fingerprint') !== $fp) {
+            return AuthLogout::logout();
         }
 
     }
diff --git a/app/Filters/Cors.php b/app/Filters/Cors.php
index c47f276..bb8d5b8 100644
--- a/app/Filters/Cors.php
+++ b/app/Filters/Cors.php
@@ -107,11 +107,11 @@ class Cors implements FilterInterface
             );
         }
 
-        $this->log('CORS filter initialized', [
-            'allowed_origins' => $this->allowedOrigins,
-            'allow_credentials' => $this->allowCredentials,
-            'allowed_methods' => $this->allowedMethods,
-        ]);
+        // $this->log('CORS filter initialized', [
+        //     'allowed_origins' => $this->allowedOrigins,
+        //     'allow_credentials' => $this->allowCredentials,
+        //     'allowed_methods' => $this->allowedMethods,
+        // ]);
     }
 
     /**
@@ -143,7 +143,7 @@ class Cors implements FilterInterface
 
         // If wildcard present in configuration, allow any origin
         if (in_array('*', $this->allowedOrigins, true)) {
-            $this->log('Origin allowed: wildcard match', ['origin' => $origin]);
+            // $this->log('Origin allowed: wildcard match', ['origin' => $origin]);
             return true;
         }
 
@@ -159,10 +159,10 @@ class Cors implements FilterInterface
             // 1. Exact match (including scheme and port)
             // Example: https://example.com matches https://example.com
             if (strcasecmp($allowed, $origin) === 0) {
-                $this->log('Origin allowed: exact match', [
-                    'origin' => $origin,
-                    'matched_rule' => $allowed
-                ]);
+                // $this->log('Origin allowed: exact match', [
+                //     'origin' => $origin,
+                //     'matched_rule' => $allowed
+                // ]);
                 return true;
             }
 
@@ -178,11 +178,11 @@ class Cors implements FilterInterface
                     
                     // Check if origin host ends with the allowed root domain
                     if ($originHost === $allowedRoot || str_ends_with($originHost, '.' . $allowedRoot)) {
-                        $this->log('Origin allowed: wildcard subdomain match', [
-                            'origin' => $origin,
-                            'matched_rule' => $allowed,
-                            'origin_host' => $originHost
-                        ]);
+                        // $this->log('Origin allowed: wildcard subdomain match', [
+                        //     'origin' => $origin,
+                        //     'matched_rule' => $allowed,
+                        //     'origin_host' => $originHost
+                        // ]);
                         return true;
                     }
                 }
@@ -191,11 +191,11 @@ class Cors implements FilterInterface
                 // Example: example.com matches both http://example.com and https://example.com
                 else {
                     if (strcasecmp($allowed, $originHost) === 0) {
-                        $this->log('Origin allowed: host match (scheme-less)', [
-                            'origin' => $origin,
-                            'matched_rule' => $allowed,
-                            'origin_host' => $originHost
-                        ]);
+                        // $this->log('Origin allowed: host match (scheme-less)', [
+                        //     'origin' => $origin,
+                        //     'matched_rule' => $allowed,
+                        //     'origin_host' => $originHost
+                        // ]);
                         return true;
                     }
                 }
@@ -320,11 +320,11 @@ class Cors implements FilterInterface
         // Preflight is sent by browsers before actual cross-origin requests
         // to check if the actual request is safe to send
         if ($method === 'OPTIONS') {
-            $this->log('Preflight request received', [
-                'origin' => $origin,
-                'method' => $method,
-                'uri' => (string) $request->getUri()
-            ]);
+            // $this->log('Preflight request received', [
+            //     'origin' => $origin,
+            //     'method' => $method,
+            //     'uri' => (string) $request->getUri()
+            // ]);
 
             // Validate origin - reject if not allowed
             if (empty($origin) || !$this->isOriginAllowed($origin)) {
@@ -346,10 +346,10 @@ class Cors implements FilterInterface
             $response->setStatusCode(204);
             $response->setBody('');
 
-            $this->log('Preflight approved', [
-                'origin' => $origin,
-                'allowed_methods' => $this->allowedMethods
-            ]);
+            // $this->log('Preflight approved', [
+            //     'origin' => $origin,
+            //     'allowed_methods' => $this->allowedMethods
+            // ]);
 
             return $response;
         }
@@ -392,10 +392,10 @@ class Cors implements FilterInterface
         // Add CORS headers to the response
         $this->addCorsHeaders($response, $request, $origin, false);
 
-        $this->log('CORS headers added to response', [
-            'origin' => $origin,
-            'status' => $response->getStatusCode()
-        ]);
+        // $this->log('CORS headers added to response', [
+        //     'origin' => $origin,
+        //     'status' => $response->getStatusCode()
+        // ]);
     }
 
     /**
diff --git a/app/Filters/GlobalPostFileUploadGuard.php b/app/Filters/GlobalPostFileUploadGuard.php
new file mode 100644
index 0000000..4cc82ba
--- /dev/null
+++ b/app/Filters/GlobalPostFileUploadGuard.php
@@ -0,0 +1,147 @@
+ ['jpg', 'jpeg'],
+        'image/png'       => ['png'],
+        'image/gif'       => ['gif'],
+        'image/webp'      => ['webp'],
+        'image/svg+xml'   => ['svg'],
+        'application/pdf' => ['pdf'],
+        'application/msword' => ['doc'],
+        'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => ['docx'],
+        'application/vnd.oasis.opendocument.text' => ['odt'],
+        'text/rtf' => ['rtf'],
+        'application/rtf' => ['rtf'],
+        'application/vnd.ms-excel' => ['xls'],
+        'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => ['xlsx'],
+        'application/vnd.oasis.opendocument.spreadsheet' => ['ods'],
+        'text/csv' => ['csv'],
+        'application/csv' => ['csv'],
+        'text/plain' => ['txt', 'csv'], 
+    ];
+
+    protected array $blockedExtensions = [
+        'php', 'phtml', 'pht', 'phar', 'php3', 'php4', 'php5', 'php7', 'php8', 'phps',
+        'cgi', 'fcgi', 'pl', 'py', 'rb', 'lua', 'tcl', 'go', 'rs', 'jar', 'class',
+        'exe', 'dll', 'com', 'bat', 'cmd', 'msi', 'vbs', 'ps1', 'scr',
+        'sh', 'bash', 'zsh', 'apk', 'app', 'deb', 'rpm', 'bin', 'run',
+        'js', 'mjs', 'jsp', 'asp', 'aspx', 'cer', 'swf',
+        'env', 'ini', 'user.ini', 'htaccess', 'htpasswd', 'conf', 'config', 'log', 'sql',
+        'zip', 'rar', '7z', 'tar', 'gz', 'bz2', 'xz', 'iso',
+        'lnk', 'url', 'reg', 'sys', 'drv', 'vxd', 'tmp', 'bak', 'old', 'backup', 'key', 'pem'
+    ];
+
+    public function before(RequestInterface $request, $arguments = null)
+    {
+        if ($request->getMethod() !== 'post') {
+            return;
+        }
+
+        $files = $request->getFiles();
+        if (empty($files)) {
+            return;
+        }
+
+        foreach ($files as $inputName => $fileData) {
+            $this->validateFileInput($fileData, $inputName);
+        }
+    }
+
+    private function validateFileInput($fileData, string $inputName): void
+    {
+        if (is_array($fileData)) {
+            foreach ($fileData as $file) {
+                $this->validateSingleFile($file, $inputName);
+            }
+        } else {
+            $this->validateSingleFile($fileData, $inputName);
+        }
+    }
+
+    private function validateSingleFile($file, string $inputName): void
+    {
+        $request = Services::request();
+        $clientIp = $request->getIPAddress();
+        $uri      = $request->getUri()->getPath();
+
+        if (!$file->isValid()) {
+            if ($file->getError() === UPLOAD_ERR_INI_SIZE || $file->getError() === UPLOAD_ERR_FORM_SIZE) {
+                $this->block("File exceeds server-side size limit", $clientIp, $uri, $inputName, $file->getClientName(), 'unknown', 'unknown', 0);
+            }
+            return; 
+        }
+
+        $originalName = $file->getClientName();
+        $extension    = strtolower($file->getExtension());
+        $mime         = $file->getMimeType(); 
+        $size         = $file->getSize();
+
+        // --- 1. Fixed Null Byte & Path Traversal Check ---
+        if (preg_match('/\0|[\/\\\]/', $originalName)) {
+            $this->block("Malicious filename characters", $clientIp, $uri, $inputName, $originalName, $mime, $extension, $size);
+        }
+
+        // --- 2. Double Extension Attack Check ---
+        if (preg_match('/\.(php|phtml|phar|exe|sh|bat|cmd|js|jsp|asp|aspx|py|pl)\./i', $originalName)) {
+            $this->block("Double extension attack", $clientIp, $uri, $inputName, $originalName, $mime, $extension, $size);
+        }
+
+        // --- 3. Forbidden Extension ---
+        if (in_array($extension, $this->blockedExtensions, true)) {
+            $this->block("Forbidden extension", $clientIp, $uri, $inputName, $originalName, $mime, $extension, $size);
+        }
+
+        // --- 4. File Size Limit ---
+        if ($size > $this->maxFileSize) {
+            $this->block("File too large", $clientIp, $uri, $inputName, $originalName, $mime, $extension, $size);
+        }
+
+        // --- 5. MIME Allow-list Check ---
+        if (!array_key_exists($mime, $this->allowedMimeMap)) {
+            $this->block("MIME type not allowed ($mime)", $clientIp, $uri, $inputName, $originalName, $mime, $extension, $size);
+        }
+
+        // --- 6. MIME-Extension Consistency ---
+        if (!in_array($extension, $this->allowedMimeMap[$mime], true)) {
+            $this->block("MIME-extension mismatch", $clientIp, $uri, $inputName, $originalName, $mime, $extension, $size);
+        }
+    }
+
+    private function block(string $reason, string $ip, string $uri, string $field, string $filename, string $mime, string $ext, int $size): void
+    {
+        log_message('critical',
+            '[UPLOAD_BLOCKED] {reason} | IP: {ip} | URI: {uri} | Field: {field} | File: {file} | MIME: {mime} | EXT: {ext} | SIZE: {size}',
+            ['reason'=>$reason, 'ip'=>$ip, 'uri'=>$uri, 'field'=>$field, 'file'=>$filename, 'mime'=>$mime, 'ext'=>$ext, 'size'=>$size]
+        );
+
+        $response = Services::response();
+        $response->setStatusCode(403)
+                 ->setJSON([
+                     'status'  => 'error',
+                     'message' => 'File upload rejected: Security policy violation.',
+                     'debug'   => (ENVIRONMENT === 'development') ? $reason : null
+                 ])
+                 ->send();
+        exit;
+    }
+
+    public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) {}
+}
\ No newline at end of file
diff --git a/app/Filters/SecurityInputFilter.php b/app/Filters/SecurityInputFilter.php
new file mode 100644
index 0000000..c23f790
--- /dev/null
+++ b/app/Filters/SecurityInputFilter.php
@@ -0,0 +1,130 @@
+/i',
+
+            // JavaScript execution vectors
+            '/javascript\s*:/i',
+            '/vbscript\s*:/i',
+            '/data\s*:\s*text\/html/i',
+
+            // Inline event handlers (strong signal)
+            '/on\w+\s*=\s*["\']?/i',
+
+            // Dangerous HTML tags
+            '/<\s*iframe\b/i',
+            '/<\s*object\b/i',
+            '/<\s*embed\b/i',
+            '/<\s*applet\b/i',
+            '/<\s*img\b/i',
+
+            // Image-based execution
+            '/<\s*img\b[^>]*on\w+/i',
+
+            // SVG-based execution (modern bypass)
+            '/<\s*svg\b/i',
+            '/<\s*math\b/i',
+
+            // Meta refresh redirect
+            '/<\s*meta\b[^>]*http-equiv\s*=\s*["\']?refresh/i',
+
+            // HTML injection via src/href
+            '/<\s*\w+\b[^>]*(src|href)\s*=\s*["\']?\s*(javascript|data)\s*:/i'
+    ];
+
+
+    public function before(RequestInterface $request, $arguments = null)
+    {
+        $logger   = Services::mylogger();
+        $response = Services::response();
+
+        // Collect all user-controlled input
+        $inputs = array_merge(
+            $request->getGet(),
+            $request->getPost()
+        );
+
+        if (empty($inputs)) {
+            return;
+        }
+
+        foreach ($inputs as $field => $value) {
+            if (is_array($value)) {
+                $value = json_encode($value);
+            }
+
+            // Step 1: Canonicalization (VERY IMPORTANT)
+            $canonical = $this->canonicalize($value);
+
+            // Step 2: Trim (hygiene)
+            $canonical = trim($canonical);
+
+            // Step 3: Detection (signal-only)
+            if ($this->detectXss($canonical)) {
+
+                // 🔐 Log intent, not data
+                $logger->logme('critical','SECURITY_BLOCKED_REQUEST - '. json_encode([
+                    'ip'        => $request->getIPAddress(),
+                    'method'    => $request->getMethod(),
+                    'uri'       => current_url(),
+                    'field'     => $field,
+                    'attack'    => 'XSS_PATTERN',
+                    'length'    => strlen($canonical),
+                    'hash'      => hash('sha256', $canonical),
+                ]));
+
+                // ⛔ Block request
+                return $response
+                    ->setStatusCode(403)
+                    ->setJSON([
+                        'status'  => 403,
+                        'error'   => 'Forbidden',
+                        'message' => 'Malicious input detected'
+                    ]);
+            }
+        }
+    }
+
+    public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
+    {
+        // no-op
+    }
+
+    /**
+     * Canonicalization prevents encoded bypass
+     */
+    private function canonicalize(string $value): string
+    {
+        $value = urldecode($value);
+        $value = html_entity_decode($value, ENT_QUOTES | ENT_HTML5, 'UTF-8');
+
+        // Remove invisible control characters
+        return preg_replace('/[\x00-\x1F\x7F]/u', '', $value);
+    }
+
+    private function detectXss(string $value): bool
+    {
+        foreach ($this->xssPatterns as $pattern) {
+            if (preg_match($pattern, $value)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/app/Helpers/excel_util_helper.php b/app/Helpers/excel_util_helper.php
index 37fc8e2..a6b6222 100755
--- a/app/Helpers/excel_util_helper.php
+++ b/app/Helpers/excel_util_helper.php
@@ -553,6 +553,47 @@ if (!function_exists('name_and_empid_check_in_db'))
     }
 }
 
+if (!function_exists('check_emp_code_duplication')) {
+    function check_emp_code_duplication($family_data, $actionArr)
+    {   
+        $employeeModel = new EmployeeModel();   
+        $row_ids = [];
+        $status = false;
+        $client_id = $actionArr['client_id'];
+        $policy_id = $actionArr['policy_id'];
+        $client_branch_id = $actionArr['client_branch_id'];
+        $current_action = $actionArr['action'];
+
+        foreach ($family_data as $rkey => $row) {
+
+            if ($current_action != 'dependent_addition' || (isset($row['temp']) && $row['temp']['source'] != 'db')) {
+                $res = $employeeModel
+                    ->join('client_policy cp', "employees.client_id = cp.client_id")
+                    ->join('employee_polices ep', "cp.id = ep.client_policy_id AND employees.id = ep.employee_id")
+                    ->where("cp.id", $policy_id)
+                    ->where("employees.client_id", $client_id)
+                    ->where("employees.client_branch_id", $client_branch_id)
+                    ->where("employees.is_active", 1)
+                    ->where("employees.emp_status", 'active')
+                    ->where("ep.is_active", 1)
+                    ->where("ep.status", 'active')
+                    ->where('TRIM(emp_code)', trim($row[1]))
+                    ->findAll();
+
+                if(count($res) > 0){
+                    $row_ids[] = $row[0];
+                }
+            }
+        }
+
+        if(!empty($row_ids)){
+            $status = true;
+        }
+
+        return ['status' => $status, 'row_ids' => $row_ids];
+    }
+}
+
 if (!function_exists('check_dependent_conflict')) 
 {
     function check_dependent_conflict($family_data,$policy_terms,$actionArr,$is_lgbtq)
diff --git a/app/Helpers/sendMailNotification.php b/app/Helpers/sendMailNotification.php
index 859cd08..ee9b31a 100755
--- a/app/Helpers/sendMailNotification.php
+++ b/app/Helpers/sendMailNotification.php
@@ -51,12 +51,23 @@ class sendMailNotification
             $nhance_logo = $_ENV['NHANCE_LOGO'];
             $client_logo = base_url() . "public/uploads/logo/" . $client_data['client_logo'];
 
+            $enrollment_open_date = !empty($params['enrollment_open_date'] ?? null)
+                ? change_date_format($params['enrollment_open_date'], 'Y-m-d', 'F d, Y')
+                : 'N/A';
+
+            $enrollment_close_date = !empty($params['enrollment_close_date'] ?? null)
+                ? change_date_format($params['enrollment_close_date'], 'Y-m-d', 'F d, Y')
+                : 'N/A';
+
             $mail_content = str_replace(["[[client_logo]]", "{{client_logo}}"], "Client Logo", $mail_content);
             $mail_content = str_replace(["[[nhance_logo]]", "{{nhance_logo}}"], "Nhance Logo", $mail_content);
             $mail_content = str_replace(["[[member_name]]", "{{member_name}}"], $employee_name, $mail_content);
             $mail_content = str_replace(["[[member_mobile]]", "{{member_mobile}}"], $employee_mobile_no, $mail_content);
             $mail_content = str_replace(["[[client_name]]", "{{client_name}}"], $client_data['client_name'], $mail_content);
 
+            $mail_content = str_replace(["[[enrollment_open_date]]", "{{enrollment_open_date}}"], $enrollment_open_date, $mail_content);
+            $mail_content = str_replace(["[[enrollment_close_date]]", "{{enrollment_close_date}}"], $enrollment_close_date, $mail_content);
+
             $mail_content = str_replace(["[[app_link]]", "{{app_link}}"], "Review Details", $mail_content);
             if ($dataToInsert['relationship'] == 'Self' && $mail != null || $mail != '') {
                 
@@ -1247,6 +1258,13 @@ class sendMailNotification
 
             $app_link = $_ENV['App_Url'];
             $nhance_logo = $_ENV['NHANCE_LOGO'];
+            $enrollment_open_date = !empty($params['enrollment_open_date'] ?? null)
+                ? date('F d, Y', strtotime(str_replace('/', '-', $params['enrollment_open_date'] ?? '')))
+                : date('F d, Y');
+
+            $enrollment_close_date = !empty($params['enrollment_close_date'] ?? null)
+                ? date('F d, Y', strtotime(str_replace('/', '-', $params['enrollment_close_date'] ?? '')))
+                : date('F d, Y', strtotime('+15 days'));
 
             $client_logo = base_url() . "public/uploads/logo/" . $client_data['client_logo'];
 
@@ -1256,6 +1274,9 @@ class sendMailNotification
             $mail_content = str_replace(["[[member_mobile]]", "{{member_mobile}}"], $mobile, $mail_content);
             $mail_content = str_replace(["[[client_name]]", "{{client_name}}"], $client_data['client_name'], $mail_content);
 
+            $mail_content = str_replace(["[[enrollment_open_date]]", "{{enrollment_open_date}}"], $enrollment_open_date, $mail_content);
+            $mail_content = str_replace(["[[enrollment_close_date]]", "{{enrollment_close_date}}"], $enrollment_close_date, $mail_content);
+
             $mail_content = str_replace(["[[app_link]]", "{{app_link}}"], "Review Details", $mail_content);
 
             if ($mail != null || $mail != '') {
diff --git a/app/Helpers/session_helper.php b/app/Helpers/session_helper.php
index 3d312d6..eb9eb9a 100755
--- a/app/Helpers/session_helper.php
+++ b/app/Helpers/session_helper.php
@@ -21,7 +21,7 @@ if(!function_exists('check_cookie')){
                         'userProfile' => $value['userProfile'],
                         'user_team'   => $user_team,
                     ];
-                    set_session_data($session_data);
+                    // set_session_data($session_data);
                     // $this->getUserDeviceInfo($user->id, 'NhanceUser');
                     // return redirect()->to(base_url('/dashboard/view'));
                     return true;
diff --git a/app/Helpers/utility_helper.php b/app/Helpers/utility_helper.php
index 5ddf424..e1b8a9b 100755
--- a/app/Helpers/utility_helper.php
+++ b/app/Helpers/utility_helper.php
@@ -556,7 +556,9 @@ if (!function_exists('change_date_format')) {
             if ($source_format !== null && $output_format !== null) {
                 $date = DateTime::createFromFormat($source_format, $date_str);
                 if (!$date) {
-                    throw new Exception("Invalid date string for source format: $source_format");
+                    // throw new Exception("Invalid date string for source format: $source_format");
+                    log_message('error', "❌ Date format error : Invalid date string | Params => date_str: {$date_str}, source_format: {$source_format}, output_format: {$output_format}");
+                    return null;
                 }
                 return $date->format($output_format);
             }
@@ -565,7 +567,9 @@ if (!function_exists('change_date_format')) {
             if ($source_format !== null && $output_format === null) {
                 $date = DateTime::createFromFormat($source_format, $date_str);
                 if (!$date) {
-                    throw new Exception("Invalid date string for source format: $source_format");
+                    // throw new Exception("Invalid date string for source format: $source_format");
+                    log_message('error', "❌ Date format error : Invalid date string | Params => date_str: {$date_str}, source_format: {$source_format}, output_format: {$output_format}");
+                    return null;
                 }
                 return $date->format('Y-m-d'); // MySQL default format
             }
@@ -580,10 +584,17 @@ if (!function_exists('change_date_format')) {
                 }
                 // If no format matches, throw an exception
                 $allowed_placeholders = implode(', ', $allowed_formats);
-                throw new Exception("Invalid date string format. Allowed formats: $allowed_placeholders");
+                // throw new Exception("Invalid date string format. Allowed formats: $allowed_placeholders");
+                log_message(
+                    'error',
+                    "❌ Date format error: Invalid date string. Allowed formats: {$allowed_placeholders} | Params => date_str: {$date_str}, source_format: {$source_format}, output_format: {$output_format}"
+                );
+                return null;
             }
         } catch (Exception $e) {
-            return "Error: " . $e->getMessage();
+            // return "Error: " . $e->getMessage();
+            log_message('error', "❌ Date format error: {$e->getMessage()} | Params => date_str: {$date_str}, source_format: {$source_format}, output_format: {$output_format}");
+            return null;
         }
 
         return null;
@@ -692,3 +703,56 @@ if (!function_exists('canSendOtp')) {
     }
 }
 
+if (!function_exists('getLatestGMCPolicy')) {
+
+    function getLatestGMCPolicy(array $empPolicy)
+    {
+        try{
+            $filtered = array_filter($empPolicy, function ($row) {
+                $type = is_object($row) ? $row->policy_type_id : $row['policy_type_id'];
+                return isset($type) && (int)$type === 2;
+            });
+
+            if (count($filtered) > 1) {
+
+                usort($filtered, function ($a, $b) {
+                    $dateA = is_object($a) ? $a->policy_end_date : $a['policy_end_date'];
+                    $dateB = is_object($b) ? $b->policy_end_date : $b['policy_end_date'];
+                    return strtotime($dateB) <=> strtotime($dateA);
+                });
+
+                $row = reset($filtered);
+                return is_object($row) ? ($row->ClientPolicyId ?? null) : ($row['ClientPolicyId'] ?? null);
+            }
+
+            return null;
+
+        }catch(\Exception $e){
+            log_message('error', 'Exception getLatestGMCPolicy :' . $e->getMessage());
+            return null;
+        }
+    }
+
+}
+
+if (!function_exists('validateExcelFile')) {
+
+    function validateExcelFile($file)
+    {
+        $allowed = [
+            'application/vnd.ms-excel',
+            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+            'application/vnd.oasis.opendocument.spreadsheet'
+        ];
+
+        // if ($file->getError() !== UPLOAD_ERR_OK) return 'Upload error';
+        // if ($file->getSize() > (16 * 1024 * 1024)) return 'File too large';
+        // if (!in_array($file->getClientMimeType(), $allowed, true)) return 'Invalid file type';
+        
+        if ($file->getError() !== UPLOAD_ERR_OK) return false;
+        if ($file->getSize() > (16 * 1024 * 1024)) return false;
+        if (!in_array($file->getClientMimeType(), $allowed, true)) return false;
+
+        return true;
+    }
+}
diff --git a/app/Libraries/AuthLogout.php b/app/Libraries/AuthLogout.php
new file mode 100644
index 0000000..cfb1005
--- /dev/null
+++ b/app/Libraries/AuthLogout.php
@@ -0,0 +1,42 @@
+regenerate(true);
+
+        // Destroy CI session
+        $session->destroy();
+
+        // Kill PHP session cookie safely
+        if (ini_get('session.use_cookies')) {
+            $params = session_get_cookie_params();
+
+            setcookie(
+                session_name(),   // DO NOT hardcode cookie name
+                '',
+                time() - 42000,
+                $params['path'],
+                $params['domain'],
+                $params['secure'],
+                $params['httponly']
+            );
+        }
+
+        session_write_close();
+
+        // Redirect with anti-cache headers
+        return redirect()->to(base_url('login'))
+            ->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
+            ->setHeader('Pragma', 'no-cache')
+            ->setHeader('Expires', 'Sat, 26 Jul 1997 05:00:00 GMT');
+    }
+}
diff --git a/app/Models/EmployeeModel.php b/app/Models/EmployeeModel.php
index 2cfc852..c5bd85b 100755
--- a/app/Models/EmployeeModel.php
+++ b/app/Models/EmployeeModel.php
@@ -159,14 +159,17 @@ class EmployeeModel extends Model
                             client_policy.policy_id as PolicyId,
                             client_policy.id as ClientPolicyId, 
                             client_policy.is_premium_summery, 
-                            CASE 
-                                WHEN client_policy.open_for_enrollment IS NULL THEN 0 
-                                ELSE client_policy.open_for_enrollment 
+                            CASE
+                                WHEN employee_polices.enrollment_open_date <= CURDATE()
+                                AND employee_polices.enrollment_close_date >= CURDATE()
+                                THEN 1
+                                ELSE 0
                             END AS OpenForEnrollment,
                             client_policy.disclaimer,
                             client_policy.policy_type_id , 
                             employee_polices.tpa_id as tpa_id , 
-                            employee_polices.rand_string as rand_string
+                            employee_polices.rand_string as rand_string,
+                            client_policy.policy_end_date
                         ', FALSE) // Select all columns from both tables
                         ->join('client_policy', 'client_policy.id = employee_polices.client_policy_id')
                         ->join('policy_type', 'policy_type.id = client_policy.policy_type_id')
diff --git a/app/Models/EmployeePolicyModel.php b/app/Models/EmployeePolicyModel.php
index d29c75f..306e6ee 100755
--- a/app/Models/EmployeePolicyModel.php
+++ b/app/Models/EmployeePolicyModel.php
@@ -35,7 +35,9 @@ class EmployeePolicyModel extends Model
         "claim_status",
         'ecard_sent_status',
         'payable_employee',
-        'file_id'
+        'file_id',
+        "enrollment_open_date",
+        "enrollment_close_date",
     ];
 
     // Callbacks
diff --git a/app/Models/FileModel.php b/app/Models/FileModel.php
index 5b27a7d..c61a23b 100755
--- a/app/Models/FileModel.php
+++ b/app/Models/FileModel.php
@@ -20,7 +20,10 @@ class FileModel extends Model
         "policy_id",
         "client_branch_id",
         "uploaded_by",
-        "updated_by"
+        "updated_by",
+        "enrollment_open_date",
+        "enrollment_close_date",
+        "hr_id",
     ];
 
 
diff --git a/app/Views/client_policy.php b/app/Views/client_policy.php
index b2f4917..0da8700 100755
--- a/app/Views/client_policy.php
+++ b/app/Views/client_policy.php
@@ -156,7 +156,7 @@ input:checked + .slider:before {
                     Client Branch
                     
                     Date
-                    Enrolment Status
+                    
                     Status
                     Action
                 
@@ -299,7 +299,8 @@ input:checked + .slider:before {
                                 
                              -->
-                            
+ + -
- - -
+ -
- - -
-