diff --git a/app/Config/Acl.php b/app/Config/Acl.php index 80f7a2bd..af8b94f3 100644 --- a/app/Config/Acl.php +++ b/app/Config/Acl.php @@ -17,6 +17,7 @@ class Acl '#^/getVerifiedPosUserData#' => ['public' => true], '#^/swagger#' => ['roles' => [ADMIN_ROLE_ID]], '#^/getEmployeeActiveOrInactivePolicy#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]], + '#^/bulkEcardDownloadAsZip#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]], '#^/sheet#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]], '#^/sendextraparam#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]], '#^/test/testingquerys#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]], diff --git a/app/Config/Filters.php b/app/Config/Filters.php index 6c031ae7..b219e60e 100755 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -69,7 +69,7 @@ class Filters extends BaseConfig 'before' => [ 'HttpRequestLog' => ['except' => 'cli/*'], 'Cors', - 'AclFilter' => ['except' => ['login', 'logout', 'auth/*', 'oauth2callback','claim-form-download', 'claims-feedback-form', 'autobookstackLogin','employeeRest/*','processjob','getCommission']], + 'AclFilter' => ['except' => ['login', 'logout', 'auth/*', 'oauth2callback','claim-form-download', 'claims-feedback-form', 'autobookstackLogin','employeeRest/*','processjob','getCommission','downloadEmployeeEcardZip']], 'SecurityInputFilter' => ['except' => ['/client/notification/create','/ticket/crud_mail_template/*','test_mail','leads/sendMail'] ], 'GlobalPostFileUploadGuard' // 'csrf', diff --git a/app/Config/Routes.php b/app/Config/Routes.php index efde3147..0600dbb8 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -87,6 +87,7 @@ $routes->get('claim-form-download/(:any)', 'TicketController::downloadClaimForm/ $routes->get('downloadClaimFile/(:any)', 'TicketController::downloadClaimFile/$1'); $routes->match (['get','post'],"claims-feedback-form/(:any)/(:any)", "TicketController::viewClaimFeedbackForm/$1/$2"); $routes->match (['get','post'],"claims-feedback-form/(:any)", "TicketController::viewClaimFeedbackForm/$1"); +$routes->get('downloadEmployeeEcardZip/(:any)', 'EmployeeController::downloadEmployeeEcardZip/$1'); @@ -706,6 +707,7 @@ $routes->group("employeeRest", ["filter" => ['GlobalPostFileUploadGuard', 'ratel $routes->get("downloadSampleExcel/(:any)", "EmployeeController::downloadSampleExcelFile/$1"); }); +$routes->post("bulkEcardDownloadAsZip", "EmployeeRestController::bulkEcardDownloadAsZip"); $routes->get("hrFileDownload", "EmployeeRestController::hrFileDownload"); $routes->post("hrFileList", "EmployeeRestController::hrFileList"); $routes->get("getEmployeeActiveOrInactivePolicy", "EmployeeRestController::getEmployeeActiveOrInactivePolicy"); diff --git a/app/Controllers/EmployeeController.php b/app/Controllers/EmployeeController.php index 4e7ddef7..01664e76 100755 --- a/app/Controllers/EmployeeController.php +++ b/app/Controllers/EmployeeController.php @@ -41,6 +41,7 @@ use App\Controllers\EmployeeServiceController; use App\Controllers\EmpDataServiceController; use App\Models\LeadsModel; use App\Models\ThzMasterModel; +use App\Models\UserActivityHistoryModel; use CodeIgniter\API\ResponseTrait; use PhpOffice\PhpSpreadsheet\Spreadsheet; @@ -78,6 +79,7 @@ class EmployeeController extends AdminController protected $userModel; protected $partnerEndorsementRequestModel; protected $LevelContactModel; + protected $UserActivityHistoryModel; public function __construct() { @@ -102,6 +104,7 @@ class EmployeeController extends AdminController $this->userModel = new userModel(); $this->partnerEndorsementRequestModel = new PartnerEndorsementRequestModel(); $this->LevelContactModel = new LevelContactModel(); + $this->UserActivityHistoryModel = new UserActivityHistoryModel(); } public function list() @@ -4862,8 +4865,133 @@ class EmployeeController extends AdminController return $mail_response; } - public function downloadZip(){ + + public function bulkEcardDownloadAsZipFromS3New($params) + { + try { + + $limit = $params['limit'] ?? 100; + $last_id = $params['last_id'] ?? 0; + $zip_id = $params['zip_id']; + + $employee_data = $this->employeePolicyModel->getEmployeeDataWithPolicyUsingClientPolicyIdOrEmployeePolicyIds($params, $limit, $last_id); + + if (empty($employee_data)) { + // No more records, move to Zipping phase + return Jobs::addJob(['job_name' => 'getEmployeeEcardFromTmpFolderAndZipToS3', 'payload' => $params]); + } + + $tempPath = FCPATH . 'tmp/' . $params['folder_name'] . '/'; + if (!is_dir($tempPath)) mkdir($tempPath, 0777, true); + + $s3 = \Config\Services::getS3Service(); + $current_last_id = $last_id; + $pdf_count = 0; + + foreach ($employee_data as $emp) { + $current_last_id = $emp['emp_policy_id']; + + + $s3_key = 'ecard_' . $emp['name'] . '(' . $emp['emp_code'] . ')' . '_' . $emp['tpa_id'] . '.pdf'; + $s3_key = $this->sanitizeFilePart($s3_key); + + if ($s3->exists($s3_key)) { + $s3_url = $s3->getPresignedUrl($s3_key); + $pdf_content = file_get_contents($s3_url['url']); + + if ($pdf_content !== false) { + file_put_contents($tempPath . $s3_key, $pdf_content); + $pdf_count++; + } + } + } + + // Check if we need more batches + $params['last_id'] = $current_last_id; + $params['pdf_count'] = $pdf_count; + $params['batch_no'] = ($params['batch_no'] ?? 1) + 1; + + if (count($employee_data) == $limit) { + return Jobs::addJob(['job_name' => 'bulkEcardDownloadAsZipFromS3', 'payload' => $params]); + } else { + return Jobs::addJob(['job_name' => 'getEmployeeEcardFromTmpFolderAndZipToS3', 'payload' => $params]); + } + + } catch (\Throwable $e) { + $this->logAndNotifyError($e, $params); + } + } + + public function getEmployeeEcardFromTmpFolderAndZipToS3New($params) + { + try { + $zipService = new \App\Libraries\ZipService(); + $source = FCPATH . 'tmp/' . $params['folder_name']; + $zipName = $params['folder_name'] . '.zip'; + $s3_dest_key = 'exports/zips/' . $zipName; + + // 1. Create Zip and Upload + $result = $zipService->zipAndUploadS3($source, $s3_dest_key); + + if ($result['status']) { + // 2. IMPORTANT: Update the Activity Record with the S3 Key + $history = $this->UserActivityHistoryModel->find($params['zip_id']); + $misc = json_decode($history['misc_data'], true); + $misc['status'] = 'completed'; + $misc['s3_key'] = $s3_dest_key; + + $this->UserActivityHistoryModel->update($params['zip_id'], [ + 'misc_data' => json_encode($misc) + ]); + + $params['url'] = base_url('downloadEmployeeEcardZip/' . md5($params['zip_id'])); + } + + // 3. Cleanup local files + $this->recursiveRemoveDir($source); + + // 4. Email HR + return $this->sendMailToHrWithZipAttachments($params); + + } catch (\Throwable $e) { + $this->logAndNotifyError($e, $params); + } + } + + public function downloadEmployeeEcardZip($md5Id) + { + // Search by MD5 of ID + $data = $this->UserActivityHistoryModel->where('MD5(CAST(id AS CHAR))', $md5Id)->first(); + + if (!$data) return "File link expired or invalid."; + + $misc = json_decode($data['misc_data'], true); + $s3Key = $misc['s3_key'] ?? null; + + if (!$s3Key) return "File is still processing or failed to generate."; + + $s3 = \Config\Services::getS3Service(); + $presigned = $s3->getPresignedUrl($s3Key, 15); // 15 mins expiry + + return redirect()->to($presigned['url']); + } + + private function logAndNotifyError($e, $params) + { + $this->myLogger->logme('error', "[ECARD_ZIP]: " . $e->getMessage()); + $params['url'] = null; // Forces "Failed" email + $this->sendMailToHrWithZipAttachments($params); + } + + private function recursiveRemoveDir($dir) + { + if (!is_dir($dir)) return; + $files = array_diff(scandir($dir), array('.', '..')); + foreach ($files as $file) { + (is_dir("$dir/$file")) ? $this->recursiveRemoveDir("$dir/$file") : unlink("$dir/$file"); + } + return rmdir($dir); } } diff --git a/app/Controllers/EmployeeRestController.php b/app/Controllers/EmployeeRestController.php index fb17d59a..6d91d543 100755 --- a/app/Controllers/EmployeeRestController.php +++ b/app/Controllers/EmployeeRestController.php @@ -63,6 +63,7 @@ use App\Models\ClaimFilesModel; use App\Models\PolicyTransactionModel; use App\Models\TicketMailTemplateModel; use App\Models\TpaApiSeviceModel; +use App\Models\UserActivityHistoryModel; use Composer\Pcre\Preg; use Kreait\Firebase\Factory; use Kreait\Firebase\Messaging\CloudMessage; @@ -106,6 +107,7 @@ class EmployeeRestController extends AdminController protected $ticketMailTemplateModel; protected $employeeRetailPolicy; protected $batchFileModel; + protected $UserActivityHistoryModel; public function __construct() @@ -141,6 +143,7 @@ class EmployeeRestController extends AdminController $this->hrFileUploadModel = new HrFileUploadModel(); $this->ticketMailTemplateModel = new TicketMailTemplateModel(); $this->batchFileModel = new BatchFileModel(); + $this->UserActivityHistoryModel = new UserActivityHistoryModel(); } @@ -5648,5 +5651,55 @@ class EmployeeRestController extends AdminController } + public function bulkEcardDownloadAsZipNew() + { + $received_data = $this->request->getJSON(true) ?? []; + + if (empty($received_data['client_policy_id']) && empty($received_data['emp_policy_ids'])) { + return $this->respond(['status' => false, 'message' => 'client_policy_id or employee_policy_ids is required'], 400); + } + + if (empty($received_data['hr_id'])) { + return $this->respond(['status' => false, 'message' => 'hr_id is required'], 400); + } + + $employee_data = $this->employeePolicyModel->getEmployeeDataWithPolicyUsingClientPolicyIdOrEmployeePolicyIds($received_data, 1); + + if (empty($employee_data)) { + return $this->respond(['status' => false, 'message' => 'No employee data found'], 404); + } + + // Define naming convention + $folderName = 'bulk_ecards_' . ($employee_data[0]['client_short_name'] ?? 'export') . '_' . date('Ymd_His'); + + $insert_data = [ + 'user_id' => $received_data['hr_id'], + 'user_type' => 'hr', + 'activity' => 'download_employees_ecard_zip', + 'misc_data' => json_encode([ + 'folder_name' => $folderName, + 'status' => 'pending', + 's3_key' => null + ]) + ]; + + $zip_id = $this->UserActivityHistoryModel->insert($insert_data); + + $payload = array_merge($received_data, [ + 'zip_id' => $zip_id, + 'folder_name' => $folderName, + 'batch_no' => 1, + 'last_id' => 0, + 'limit' => 100 + ]); + + // Dispatch job + Jobs::addJob(['job_name' => 'bulkEcardDownloadAsZipFromS3', 'payload' => $payload]); + + return $this->respond([ + 'status' => true, + 'message' => 'Process started. You will receive an email with the download link shortly.' + ], 200); + } } diff --git a/app/Models/EmployeePolicyModel.php b/app/Models/EmployeePolicyModel.php index 908d1698..8171df0c 100755 --- a/app/Models/EmployeePolicyModel.php +++ b/app/Models/EmployeePolicyModel.php @@ -2260,9 +2260,12 @@ class EmployeePolicyModel extends Model employees.id as emp_id, tpa.short_name, employee_polices.tpa_id, - client_policy.policy_no + client_policy.policy_no, + clients.client_name as client_name, + clients.short_name as client_short_name ') ->join('client_policy', 'client_policy.id = employee_polices.client_policy_id') + ->join('clients', 'clients.id = client_policy.client_id') ->join('employees', 'employees.id = employee_polices.employee_id') ->join('tpa', 'tpa.id = client_policy.tpa_id') ->where([