diff --git a/app/Config/Routes.php b/app/Config/Routes.php
index 13aff9ac..4f942872 100755
--- a/app/Config/Routes.php
+++ b/app/Config/Routes.php
@@ -214,6 +214,7 @@ $routes->group("/employee", ["filter" => "authMVC"], function ($routes) {
$routes->get("retail-endorsement-list", "EmployeeController::retailendorsementlist");
$routes->post("retail-endorsement-save", "EmployeeController::retailendorsementsave");
$routes->get("getTPADataVariationReport/(:num)", "EmployeeController::getTPADataVariationReport/$1");
+ $routes->get("bulkGenerateEcardAndStoreinS3", "EmployeeController::bulkGenerateEcardAndStoreinS3");
});
@@ -509,6 +510,8 @@ $routes->get('cli/sendZeptoMail', 'MasterController::testZeptoSMTP');
$routes->cli('cli/processjob', 'JobWorker::processJob');
$routes->cli('cli/processjobs', 'JobWorker::processJobs');
+$routes->cli('cli/bulkGenerateEcardAndStoreinS3', 'EmployeeController::bulkGenerateEcardAndStoreinS3');
+
$routes->get("processjob", "JobWorker::processJob");
$routes->cli('cli/new_gmail_token', 'MasterController::generateNewGmailAPIToken');
$routes->cli('cli/send_mail_cli', 'MasterController::testGmailAPIViaCLI');
diff --git a/app/Config/Services.php b/app/Config/Services.php
index 5f982877..73d75683 100755
--- a/app/Config/Services.php
+++ b/app/Config/Services.php
@@ -9,6 +9,7 @@ use App\Libraries\GmailAPI;
use App\Libraries\MyGoogleDrive;
use App\Libraries\RuleImportService;
use App\Libraries\DataServiceSqlite;
+use App\Libraries\S3Service;
use App\Controllers\Home;
/**
@@ -90,5 +91,14 @@ class Services extends BaseService
return new RuleImportService();
}
+
+ public static function getS3Service($getShared = true)
+ {
+ if ($getShared) {
+ return static::getSharedInstance('getS3Service');
+ }
+
+ return new S3Service();
+ }
}
diff --git a/app/Controllers/EmployeeController.php b/app/Controllers/EmployeeController.php
index 32217c91..fe377c2a 100755
--- a/app/Controllers/EmployeeController.php
+++ b/app/Controllers/EmployeeController.php
@@ -101,6 +101,14 @@ class EmployeeController extends AdminController
public function list()
{
+
+ // $s3 = \Config\Services::getS3Service();
+ // $file = WRITEPATH.'uploads/excel/inception.ods';
+ // print_rr($s3->exists('inception_1766475604.ods'));
+ // print_rr($s3->getPresignedUrl('inception_1766.ods'));
+ // print_rr($s3->upload($file));
+ // print_rr($s3->download('inception_1766475604.ods',__DIR__));
+ // die();
// $model = new UserModel();
$data = [];
$data['status'] = ['draft' => 'Draft', 'enrolled' => 'Enrolled', 'active' => 'Active', 'inactive' => 'In-Active', 'pending' => 'Pending'];
@@ -1429,7 +1437,10 @@ class EmployeeController extends AdminController
//E-CARD DOWNLOAD FUNCTION USING DOM PDF ( CURRENTLY USING THIS ) Dompdf
public function generateIDCardForEmployee($rand_string, $people = 0, $mode = 0)
{
- // dd($rand_string, $people);
+ $mode = (int)$mode;
+
+
+ // dd($rand_string, $people,$mode);
$this->myLogger->logme('error', 'generateIDCardForEmployee params .' . json_encode(["rand_string" => $rand_string, "people" => $people, "mode" => $mode]));
try {
$this->myLogger->logme('error', 'generateIDCardForEmployee function started.');
@@ -1438,7 +1449,7 @@ class EmployeeController extends AdminController
$this->myLogger->logme('error', 'Fetching employee code and client policy ID.');
$get_emp_code_and_client_policy_id = $this->employeePolicyModel
- ->select('employee_polices.client_policy_id, employees.emp_code, tpa.short_name,employees.client_id')
+ ->select('employee_polices.client_policy_id, employees.emp_code,employees.name, employee_polices.tpa_id,tpa.short_name,employees.client_id')
->join('client_policy', 'client_policy.id = employee_polices.client_policy_id')
->join('employees', 'employees.id = employee_polices.employee_id')
->join('tpa', 'tpa.id = client_policy.tpa_id')
@@ -1465,7 +1476,44 @@ class EmployeeController extends AdminController
$client_policy_id = $get_emp_code_and_client_policy_id['client_policy_id'];
$emp_code = $get_emp_code_and_client_policy_id['emp_code'];
$client_id = $get_emp_code_and_client_policy_id['client_id'];
-
+
+ //new step check in S3 if yes then fetch from S3 bucket
+ $s3_key = 'ecard_'.$get_emp_code_and_client_policy_id['name'].'('.$get_emp_code_and_client_policy_id['emp_code'].')'.'_'.$get_emp_code_and_client_policy_id['tpa_id'].'.pdf';
+ // echo $s3_key;die();
+ $s3 = \Config\Services::getS3Service();
+ if($s3->exists($s3_key) && $mode != 2) //2 => for bulk generate so skip s3 check and generate PDF
+ {
+ //get pre signed url & make it download
+ $s3_url = $s3->getPresignedUrl($s3_key );
+
+ $pdf = file_get_contents($s3_url['url']);
+ if ($mode == 1) {
+ // Inline view
+ return $this->response
+ ->setHeader('Content-Type', 'application/pdf')
+ ->setHeader('Content-Disposition', 'inline; filename="' . $s3_key . '"')
+ ->setBody($pdf);
+ } else if($mode == 0){
+ // echo 'Force download';//die();
+ return $this->response
+ ->setHeader('Content-Type', 'application/pdf')
+ ->setHeader('Content-Disposition', 'attachment; filename="' . $s3_key . '"')
+ ->setBody($pdf);
+ }
+ // exit();
+ }
+ else
+ {
+ if($mode !== 2)
+ {
+ $data['message'] = 'Inprogress... Comeback later! or Contact support';
+ return view('errors/404', $data);
+ }
+ }
+
+ //in else generate PDF and upload it in s3
+ // echo 'else';
+ // exit();
// Step 2: Fetch ECard data
$this->myLogger->logme('error', 'Fetching ECard data using client_policy_id: ' . $client_policy_id . ' and emp_code: ' . $emp_code);
$data = $this->employeePolicyModel->getECardDataUsingMd5($client_policy_id, $emp_code,$client_id);
@@ -1562,6 +1610,7 @@ class EmployeeController extends AdminController
}
// return $html;
+ // echo $html;die();
// DomPdf
$options = new Options();
$options->set('isRemoteEnabled', true);
@@ -1585,28 +1634,34 @@ class EmployeeController extends AdminController
$dompdf->addInfo("Title", "E-Card");
$filename = 'ecard_' . date('Y-m-d_H-i-s') . '.pdf';
-
+ $temp_local_path = WRITEPATH.'/tmp/'.$s3_key;
+ file_put_contents(($temp_local_path),$dompdf->output());
// if($mode == 1){
// $dompdf->stream($filename, ['Attachment' => false]); // Inline view
// }else{
// $dompdf->stream($filename, ['Attachment' => true]); // Force download
// }
+ $aws_upload_res = $s3->upload(($temp_local_path));
+ // print_rr($aws_upload_res);
+ // echo '
PDF generated and uploaded to S3 successfully.
';
+ unlink($temp_local_path);
- if ($mode == 1) {
- // Inline view
- return $this->response
- ->setHeader('Content-Type', 'application/pdf')
- ->setHeader('Content-Disposition', 'inline; filename="' . $filename . '"')
- ->setBody($dompdf->output());
- } else {
- // Force download
- return $this->response
- ->setHeader('Content-Type', 'application/pdf')
- ->setHeader('Content-Disposition', 'attachment; filename="' . $filename . '"')
- ->setBody($dompdf->output());
- }
+ // exit();
+ // if ($mode == 1) {
+ // // Inline view
+ // return $this->response
+ // ->setHeader('Content-Type', 'application/pdf')
+ // ->setHeader('Content-Disposition', 'inline; filename="' . $filename . '"')
+ // ->setBody($dompdf->output());
+ // } else {
+ // // Force download
+ // return $this->response
+ // ->setHeader('Content-Type', 'application/pdf')
+ // ->setHeader('Content-Disposition', 'attachment; filename="' . $filename . '"')
+ // ->setBody($dompdf->output());
+ // }
- $this->myLogger->logme('error', 'generateIDCardForEmployee function completed successfully.');
+ // $this->myLogger->logme('error', 'generateIDCardForEmployee function completed successfully.');
} catch (\Exception $e) {
$this->myLogger->logme('error', 'Exception occurred: ' . $e->getMessage());
@@ -3764,206 +3819,389 @@ class EmployeeController extends AdminController
array $notInTPA,
array $notInNhance,
array $reviewNeeded,
- string $filename = 'employee_review.xlsx'
-) {
+ string $filename = 'employee_review.xlsx')
+ {
- function setCell($sheet, int $col, int $row, $value)
-{
- $cell = Coordinate::stringFromColumnIndex($col) . $row;
- $sheet->setCellValue($cell, $value);
-}
+ function setCell($sheet, int $col, int $row, $value)
+ {
+ $cell = Coordinate::stringFromColumnIndex($col) . $row;
+ $sheet->setCellValue($cell, $value);
+ }
-$EXPORT_COLUMNS = [
+ $EXPORT_COLUMNS = [
- // Sheet 1 — Not in TPA
- 'not_in_tpa' => [
- 'emp_code' => 'Employee Code',
- 'name' => 'Employee Name',
- 'relationship' => 'Relation',
- 'dob' => 'Date of Birth',
- 'gender' => 'Gender',
- 'mobile' => 'Mobile No',
- 'email_corporate' => 'Corporate Email',
- 'policy_no' => 'Policy No',
- 'tpa_name' => 'TPA Name',
- 'change_event' => 'Change Event',
- ],
+ // Sheet 1 — Not in TPA
+ 'not_in_tpa' => [
+ 'emp_code' => 'Employee Code',
+ 'name' => 'Employee Name',
+ 'relationship' => 'Relation',
+ 'dob' => 'Date of Birth',
+ 'gender' => 'Gender',
+ 'mobile' => 'Mobile No',
+ 'email_corporate' => 'Corporate Email',
+ 'policy_no' => 'Policy No',
+ 'tpa_name' => 'TPA Name',
+ 'change_event' => 'Change Event',
+ ],
- // Sheet 2 — Not in Nhance
- 'not_in_nhance' => [
- 'emp_code' => 'Employee Code',
- 'name' => 'Employee Name',
- 'relation' => 'Relation',
- 'dob' => 'Date of Birth',
- 'gender' => 'Gender',
- 'age' => 'Age',
- 'tpa_id' => 'TPA Member ID',
- ],
+ // Sheet 2 — Not in Nhance
+ 'not_in_nhance' => [
+ 'emp_code' => 'Employee Code',
+ 'name' => 'Employee Name',
+ 'relation' => 'Relation',
+ 'dob' => 'Date of Birth',
+ 'gender' => 'Gender',
+ 'age' => 'Age',
+ 'tpa_id' => 'TPA Member ID',
+ ],
- // Sheet 3 — Review Needed (DB side)
- 'review_main' => [
- 'emp_code' => 'Employee Code',
- 'name' => 'Employee Name',
- 'relationship' => 'Relation',
- 'dob' => 'Date of Birth',
- 'gender' => 'Gender',
- 'policy_no' => 'Policy No',
- 'uhid' => 'UHID',
- 'change_event' => 'Change event'
- ],
+ // Sheet 3 — Review Needed (DB side)
+ 'review_main' => [
+ 'emp_code' => 'Employee Code',
+ 'name' => 'Employee Name',
+ 'relationship' => 'Relation',
+ 'dob' => 'Date of Birth',
+ 'gender' => 'Gender',
+ 'policy_no' => 'Policy No',
+ 'uhid' => 'UHID',
+ 'change_event' => 'Change event'
+ ],
- // Sheet 3 — Review Needed (TPA side)
- 'review_tpa' => [
- 'emp_code' => 'TPA Employee Code',
- 'name' => 'TPA Name',
- 'relation' => 'TPA Relation',
- 'dob' => 'TPA DOB',
- 'gender' => 'TPA Gender',
- 'tpa_id' => 'TPA Member ID',
- 'age' => 'TPA Age',
- ],
-];
+ // Sheet 3 — Review Needed (TPA side)
+ 'review_tpa' => [
+ 'emp_code' => 'TPA Employee Code',
+ 'name' => 'TPA Name',
+ 'relation' => 'TPA Relation',
+ 'dob' => 'TPA DOB',
+ 'gender' => 'TPA Gender',
+ 'tpa_id' => 'TPA Member ID',
+ 'age' => 'TPA Age',
+ ],
+ ];
- $spreadsheet = new Spreadsheet();
+ $spreadsheet = new Spreadsheet();
- /* =========================================================
- * SHEET 1 — NOT IN TPA
- * ========================================================= */
- $sheet1 = $spreadsheet->getActiveSheet();
- $sheet1->setTitle('Not in TPA');
+ /* =========================================================
+ * SHEET 1 — NOT IN TPA
+ * ========================================================= */
+ $sheet1 = $spreadsheet->getActiveSheet();
+ $sheet1->setTitle('Not in TPA');
- $cols = $EXPORT_COLUMNS['not_in_tpa'];
+ $cols = $EXPORT_COLUMNS['not_in_tpa'];
- $colNo = 1;
- foreach ($cols as $label) {
- setCell($sheet1, $colNo++, 1, $label);
- }
-
- $rowNo = 2;
- foreach ($notInTPA as $row) {
$colNo = 1;
- foreach ($cols as $key => $label) {
- setCell($sheet1, $colNo++, $rowNo, $row[$key] ?? '');
+ foreach ($cols as $label) {
+ setCell($sheet1, $colNo++, 1, $label);
}
- $rowNo++;
- }
- foreach (range(1, count($cols)) as $c) {
- $sheet1->getColumnDimension(Coordinate::stringFromColumnIndex($c))->setAutoSize(true);
- }
+ $rowNo = 2;
+ foreach ($notInTPA as $row) {
+ $colNo = 1;
+ foreach ($cols as $key => $label) {
+ setCell($sheet1, $colNo++, $rowNo, $row[$key] ?? '');
+ }
+ $rowNo++;
+ }
- /* =========================================================
- * SHEET 2 — NOT IN NHANCE
- * ========================================================= */
- $sheet2 = $spreadsheet->createSheet();
- $sheet2->setTitle('Not in Nhance');
+ foreach (range(1, count($cols)) as $c) {
+ $sheet1->getColumnDimension(Coordinate::stringFromColumnIndex($c))->setAutoSize(true);
+ }
- $cols = $EXPORT_COLUMNS['not_in_nhance'];
+ /* =========================================================
+ * SHEET 2 — NOT IN NHANCE
+ * ========================================================= */
+ $sheet2 = $spreadsheet->createSheet();
+ $sheet2->setTitle('Not in Nhance');
- $colNo = 1;
- foreach ($cols as $label) {
- setCell($sheet2, $colNo++, 1, $label);
- }
+ $cols = $EXPORT_COLUMNS['not_in_nhance'];
- $rowNo = 2;
- foreach ($notInNhance as $row) {
$colNo = 1;
- foreach ($cols as $key => $label) {
- setCell($sheet2, $colNo++, $rowNo, $row[$key] ?? '');
+ foreach ($cols as $label) {
+ setCell($sheet2, $colNo++, 1, $label);
}
- $rowNo++;
- }
- foreach (range(1, count($cols)) as $c) {
- $sheet2->getColumnDimension(Coordinate::stringFromColumnIndex($c))->setAutoSize(true);
- }
+ $rowNo = 2;
+ foreach ($notInNhance as $row) {
+ $colNo = 1;
+ foreach ($cols as $key => $label) {
+ setCell($sheet2, $colNo++, $rowNo, $row[$key] ?? '');
+ }
+ $rowNo++;
+ }
- /* =========================================================
- * SHEET 3 — REVIEW NEEDED
- * ========================================================= */
- $sheet3 = $spreadsheet->createSheet();
- $sheet3->setTitle('Review Needed');
+ foreach (range(1, count($cols)) as $c) {
+ $sheet2->getColumnDimension(Coordinate::stringFromColumnIndex($c))->setAutoSize(true);
+ }
- $mainCols = $EXPORT_COLUMNS['review_main'];
- $tpaCols = $EXPORT_COLUMNS['review_tpa'];
+ /* =========================================================
+ * SHEET 3 — REVIEW NEEDED
+ * ========================================================= */
+ $sheet3 = $spreadsheet->createSheet();
+ $sheet3->setTitle('Review Needed');
- // headers
- $colNo = 1;
- foreach ($mainCols as $label) {
- setCell($sheet3, $colNo++, 1, $label);
- }
- foreach ($tpaCols as $label) {
- setCell($sheet3, $colNo++, 1, $label);
- }
+ $mainCols = $EXPORT_COLUMNS['review_main'];
+ $tpaCols = $EXPORT_COLUMNS['review_tpa'];
- // rows
- $rowNo = 2;
- foreach ($reviewNeeded as $row) {
-
- // main (DB)
+ // headers
$colNo = 1;
- foreach ($mainCols as $key => $label) {
- setCell($sheet3, $colNo++, $rowNo, $row[$key] ?? '');
+ foreach ($mainCols as $label) {
+ setCell($sheet3, $colNo++, 1, $label);
+ }
+ foreach ($tpaCols as $label) {
+ setCell($sheet3, $colNo++, 1, $label);
}
- $tpaData = [];
- $notMatching = [];
+ // rows
+ $rowNo = 2;
+ foreach ($reviewNeeded as $row) {
- if (($row['match']['status'] ?? '') === 'matched') {
- $tpaData = $row['match']['tpa_record'] ?? [];
- $notMatching = $row['match']['not_matching'] ?? [];
- }
-
- // TPA
- foreach ($tpaCols as $key => $label) {
- setCell($sheet3, $colNo++, $rowNo, $tpaData[$key] ?? '');
- }
-
- // highlight mismatches
- foreach ($notMatching as $field) {
-
- if (isset($mainCols[$field])) {
- $idx = array_keys($mainCols);
- $pos = array_search($field, $idx);
- $cell = Coordinate::stringFromColumnIndex($pos + 1) . $rowNo;
- $sheet3->getStyle($cell)->getFill()
- ->setFillType(Fill::FILL_SOLID)
- ->getStartColor()->setARGB('FFFFFF00');
+ // main (DB)
+ $colNo = 1;
+ foreach ($mainCols as $key => $label) {
+ setCell($sheet3, $colNo++, $rowNo, $row[$key] ?? '');
}
- if (isset($tpaCols[$field])) {
- $idx = array_keys($tpaCols);
- $pos = array_search($field, $idx);
- $cell = Coordinate::stringFromColumnIndex(count($mainCols) + $pos + 1) . $rowNo;
- $sheet3->getStyle($cell)->getFill()
- ->setFillType(Fill::FILL_SOLID)
- ->getStartColor()->setARGB('FFFFFF00');
+ $tpaData = [];
+ $notMatching = [];
+
+ if (($row['match']['status'] ?? '') === 'matched') {
+ $tpaData = $row['match']['tpa_record'] ?? [];
+ $notMatching = $row['match']['not_matching'] ?? [];
}
+
+ // TPA
+ foreach ($tpaCols as $key => $label) {
+ setCell($sheet3, $colNo++, $rowNo, $tpaData[$key] ?? '');
+ }
+
+ // highlight mismatches
+ foreach ($notMatching as $field) {
+
+ if (isset($mainCols[$field])) {
+ $idx = array_keys($mainCols);
+ $pos = array_search($field, $idx);
+ $cell = Coordinate::stringFromColumnIndex($pos + 1) . $rowNo;
+ $sheet3->getStyle($cell)->getFill()
+ ->setFillType(Fill::FILL_SOLID)
+ ->getStartColor()->setARGB('FFFFFF00');
+ }
+
+ if (isset($tpaCols[$field])) {
+ $idx = array_keys($tpaCols);
+ $pos = array_search($field, $idx);
+ $cell = Coordinate::stringFromColumnIndex(count($mainCols) + $pos + 1) . $rowNo;
+ $sheet3->getStyle($cell)->getFill()
+ ->setFillType(Fill::FILL_SOLID)
+ ->getStartColor()->setARGB('FFFFFF00');
+ }
+ }
+
+ $rowNo++;
}
- $rowNo++;
+ foreach (range(1, count($mainCols) + count($tpaCols)) as $c) {
+ $sheet3->getColumnDimension(Coordinate::stringFromColumnIndex($c))->setAutoSize(true);
+ }
+
+ /* =========================================================
+ * OUTPUT
+ * ========================================================= */
+ $writer = new Xlsx($spreadsheet);
+
+ if (ob_get_length()) ob_end_clean();
+
+ header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
+ header('Content-Disposition: attachment; filename="' . $filename . '"');
+ header('Cache-Control: max-age=0');
+
+ $writer->save('php://output');
+ exit;
}
- foreach (range(1, count($mainCols) + count($tpaCols)) as $c) {
- $sheet3->getColumnDimension(Coordinate::stringFromColumnIndex($c))->setAutoSize(true);
+ public function bulkGenerateEcardAndStoreinS3(array $params = [])
+ {
+ /**
+ * ---------------------------
+ * 1. Detect mode + collect inputs
+ * ---------------------------
+ */
+
+ $client_policy_id = $params['client_policy_id'] ?? null;
+ $emp_code = $params['emp_code'] ?? null;
+ $emp_pk = $params['emp_pk'] ?? null;
+ $batch_size = $params['batch_size'] ?? null;
+ $batch_no = $params['batch_no'] ?? null;
+ $execution_mode = $params['execution_mode'] ?? 'sequential';//parallel
+ $total_batches = $params['total_batches'] ?? 0;//parallel
+
+ if (is_cli()) {
+ $mode = 'CLI';
+
+
+ } elseif (empty($params) && $this->request->getMethod() === 'get') {
+ $mode = 'WEB';
+
+ $client_policy_id = $this->request->getGet('client_policy_id');
+ $emp_code = $this->request->getGet('emp_code');
+ $emp_pk = $this->request->getGet('emp_pk');
+ $execution_mode = $this->request->getGet('execution_mode') ?? 'sequential';
+ $batch_size = (int) ($this->request->getGet('batch_size') ?? 100);
+ if($client_policy_id == null || empty($client_policy_id) || $client_policy_id == '')
+ {
+ return $this->respond(['status' => false, 'code' => 200, 'message' => 'client_policy_id is necessary'], 200);
+ }
+ /**
+ * ---------------------------
+ * 2. Calculate total records
+ * ---------------------------
+ */
+ $total = $this->employeePolicyModel
+ ->join('employees', 'employees.id = employee_polices.employee_id')
+ ->where('employees.emp_status', 'active')
+ ->where('employees.is_active', '1')
+ ->where("employee_polices.tpa_id IS NOT NULL AND employee_polices.tpa_id <> ''")
+ ->where('employee_polices.status', 'active')
+ ->where('employee_polices.is_active', '1')
+ ->where('employee_polices.client_policy_id', $client_policy_id)
+ ->countAllResults();
+
+ $total_batches = (int) ceil($total / $batch_size);
+ // echo $total_batches;die();
+
+
+
+ /**
+ * ---------------------------
+ * 3. Push JOB per batch
+ * ---------------------------
+ */
+ if ($execution_mode === 'parallel') {
+ for ($batch_no = 1; $batch_no <= $total_batches; $batch_no++) {
+ Jobs::addJob([
+ 'job_name' => 'bulkGenerateEcardAndStoreinS3',
+ 'payload' => [
+ 'client_policy_id' => $client_policy_id,
+ 'emp_code' => $emp_code,
+ 'emp_pk' => $emp_pk,
+ 'batch_size' => $batch_size,
+ 'batch_no' => $batch_no,
+ 'total_batches' => $total_batches,
+ 'execution_mode' => 'parallel',
+ ],
+ ]);
+ }
+ }
+
+ if ($execution_mode === 'sequential') {
+ Jobs::addJob([
+ 'job_name' => 'bulkGenerateEcardAndStoreinS3',
+ 'payload' => [
+ 'client_policy_id' => $client_policy_id,
+ 'batch_size' => $batch_size,
+ 'batch_no' => $batch_no ?? 1,
+ 'total_batches' => $total_batches,
+ 'execution_mode' => 'sequential',
+ ],
+ ]);
+ }
+
+ return $this->respond(['status' => true, 'code' => 200, 'message' => 'E-card generation started',
+ 'total' => $total,
+ 'batches' => $total_batches,], 200);
+ // return [
+ // 'status' => true,
+ // 'message' => 'E-card generation started',
+ // 'total' => $total,
+ // 'batches' => $total_batches,
+ // ];
+ }
+ //else {
+ // return true;
+ // }
+
+ /**
+ * ---------------------------
+ * 4. Build query (CLI execution)
+ * ---------------------------
+ */
+ $builder = $this->employeePolicyModel
+ ->select('
+ employee_polices.client_policy_id,
+ employees.emp_code,
+ tpa.short_name,
+ employees.client_id,
+ employee_polices.rand_string,
+ employees.id as emp_id
+ ')
+ ->join('client_policy', 'client_policy.id = employee_polices.client_policy_id')
+ ->join('employees', 'employees.id = employee_polices.employee_id')
+ ->join('tpa', 'tpa.id = client_policy.tpa_id')
+ ->where('employees.emp_status', 'active')
+ ->where('employees.is_active', '1')
+ ->where("employee_polices.tpa_id IS NOT NULL AND employee_polices.tpa_id <> ''")
+ ->where('employee_polices.status', 'active')
+ ->where('employee_polices.is_active', '1')
+ ->where('employee_polices.client_policy_id', $client_policy_id);
+
+ if (!empty($emp_code)) {
+ $builder->where('employees.emp_code', $emp_code);
+ }
+
+ if (!empty($emp_pk)) {
+ $builder->where('employees.id', $emp_pk);
+ }
+
+ /**
+ * ---------------------------
+ * 5. Apply batching (only if provided)
+ * ---------------------------
+ */
+ if (!empty($batch_size) && !empty($batch_no)) {
+ $offset = ($batch_no - 1) * $batch_size;
+ $builder->limit($batch_size, $offset);
+ }
+
+ $res = $builder->findAll();
+
+ /**
+ * ---------------------------
+ * 6. Process batch
+ * ---------------------------
+ */
+ foreach ($res as $row) {
+ $ecard_gen_res = $this->generateIDCardForEmployee(
+ $row['rand_string'],
+ 0,
+ 2 // skip S3 check, force regenerate
+ );
+
+ // print_rr([
+ // 'batch' => $batch_no,
+ // 'emp' => $row['emp_code'],
+ // 'res' => $ecard_gen_res,
+ // ]);
+
+ // echo date('Y-m-d H:i:s') . PHP_EOL;
+ }
+
+ if ($execution_mode === 'sequential' && $batch_no < $total_batches) {
+ Jobs::addJob([
+ 'job_name' => 'bulkGenerateEcardAndStoreinS3',
+ 'payload' => [
+ 'client_policy_id' => $client_policy_id,
+ 'batch_size' => $batch_size,
+ 'batch_no' => ($batch_no + 1),
+ 'total_batches' => $total_batches,
+ 'execution_mode' => 'sequential',
+ ],
+ ]);
+ }
+
+ // echo "BATCH {$batch_no} COMPLETED @ " . date('Y-m-d H:i:s') . PHP_EOL;
+ return array($batch_no);
}
- /* =========================================================
- * OUTPUT
- * ========================================================= */
- $writer = new Xlsx($spreadsheet);
-
- if (ob_get_length()) ob_end_clean();
-
- header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
- header('Content-Disposition: attachment; filename="' . $filename . '"');
- header('Cache-Control: max-age=0');
-
- $writer->save('php://output');
- exit;
-}
-
}
diff --git a/app/Controllers/EmployeeMultiEventServiceController.php b/app/Controllers/EmployeeMultiEventServiceController.php
index 782a189b..3c8846e9 100644
--- a/app/Controllers/EmployeeMultiEventServiceController.php
+++ b/app/Controllers/EmployeeMultiEventServiceController.php
@@ -1029,7 +1029,7 @@ class EmployeeMultiEventServiceController extends BaseController
//check physical file
if (!file_exists($file_name_with_path)) {
//file not found update status and reason
- $message = "Physcial file not found";
+ $message = "Physcial file not found - " . $file_name_with_path;
// 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();
@@ -1402,7 +1402,7 @@ class EmployeeMultiEventServiceController extends BaseController
//check physical file
if (!file_exists($file_name_with_path)) {
//file not found update status and reason
- $message = "Physcial file not found";
+ $message = "Physcial file not found - " . $file_name_with_path;
$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);
diff --git a/app/Controllers/JobWorker.php b/app/Controllers/JobWorker.php
index c32da5e6..4a52fc54 100755
--- a/app/Controllers/JobWorker.php
+++ b/app/Controllers/JobWorker.php
@@ -194,6 +194,10 @@ class JobWorker extends AdminController
'type' => 'CC', // Handler Category
'handler' => 'App\Controllers\MediAssistApiController',
],
+ 'bulkGenerateEcardAndStoreinS3' => [
+ 'type' => 'CC', // Handler Category
+ 'handler' => 'App\Controllers\EmployeeController',
+ ]
];
@@ -253,6 +257,8 @@ class JobWorker extends AdminController
// print_r($jobdata);
// echo 'listen';
// die();
+ // $jobdata = ['id' => 11954,'uuid' => '001700c2-8127-4d02-80b3-ea26e7603ccf'];
+ // dd($job);
$query = "
SELECT id, name, payload, uuid
FROM jobs
diff --git a/app/Libraries/S3Service.php b/app/Libraries/S3Service.php
new file mode 100644
index 00000000..872b13ab
--- /dev/null
+++ b/app/Libraries/S3Service.php
@@ -0,0 +1,268 @@
+bucket = getenv('AWS_BUCKET');
+ $this->region = getenv('AWS_DEFAULT_REGION');
+
+ $this->s3Client = new S3Client([
+ 'version' => 'latest',
+ 'region' => $this->region,
+ 'credentials' => [
+ 'key' => getenv('AWS_ACCESS_KEY_ID'),
+ 'secret' => getenv('AWS_SECRET_ACCESS_KEY'),
+ ],
+ ]);
+
+ $this->baseUrl = "https://{$this->bucket}.s3.{$this->region}.amazonaws.com/";
+ // echo $this->baseUrl;die();
+ }
+
+ /**
+ * Upload file to S3
+ *
+ * @param mixed $file File object or file path
+ * @param string $folder Folder path in S3 bucket (optional)
+ * @param string $fileName Custom file name (optional)
+ * @return array ['success' => bool, 'url' => string, 'key' => string, 'message' => string]
+ */
+ public function upload($file, string $folder = '', string $fileName = null): array
+ {
+ try {
+ // Handle CodeIgniter file upload object
+ if (is_object($file) && method_exists($file, 'isValid')) {
+ if (!$file->isValid()) {
+ return [
+ 'success' => false,
+ 'message' => 'Invalid file upload',
+ 'url' => null,
+ 'key' => null
+ ];
+ }
+ $filePath = $file->getTempName();
+ $originalName = $fileName ?? $file->getClientName();
+ } else {
+ // Handle file path string
+ $filePath = $file;
+ $originalName = $fileName ?? basename($file);
+ }
+
+ // Generate unique file name
+ $extension = pathinfo($originalName, PATHINFO_EXTENSION);
+ // $uniqueName = pathinfo($originalName, PATHINFO_FILENAME) . '_' . time() . '.' . $extension;
+ $uniqueName = pathinfo($originalName, PATHINFO_FILENAME) . '.' . $extension;
+
+ // Build S3 key (path)
+ $key = $folder ? rtrim($folder, '/') . '/' . $uniqueName : $uniqueName;
+
+ // Upload to S3
+ // NEW - Faster with streaming and proper content type
+ $finfo = finfo_open(FILEINFO_MIME_TYPE);
+ $mimeType = finfo_file($finfo, $filePath);
+ finfo_close($finfo);
+
+ $result = $this->s3Client->putObject([
+ 'Bucket' => $this->bucket,
+ 'Key' => $key,
+ 'Body' => fopen($filePath, 'rb'), // Stream instead of loading into memory
+ 'ContentType' => $mimeType,
+ // 'ACL' => 'public-read',
+ ]);
+
+ return [
+ 'success' => true,
+ 'url' => $this->baseUrl . $key,
+ 'key' => $key,
+ 'message' => 'File uploaded successfully'
+ ];
+
+ } catch (AwsException $e) {
+ log_message('error', 'S3 Upload Error: ' . $e->getMessage());
+ return [
+ 'success' => false,
+ 'message' => 'Upload failed: ' . $e->getMessage(),
+ 'url' => null,
+ 'key' => null
+ ];
+ }
+ }
+
+ /**
+ * Download file from S3
+ *
+ * @param string $key S3 object key (file path in bucket)
+ * @param string $savePath Local path to save the file (optional)
+ * @return array ['success' => bool, 'path' => string, 'content' => string, 'message' => string]
+ */
+ public function download(string $key, string $savePath = null): array
+ {
+ try {
+ $result = $this->s3Client->getObject([
+ 'Bucket' => $this->bucket,
+ 'Key' => $key,
+ ]);
+
+ $content = (string) $result['Body'];
+
+ // If save path is provided, save to local file
+ if ($savePath) {
+ $directory = dirname($savePath);
+ if (!is_dir($directory)) {
+ mkdir($directory, 0755, true);
+ }
+ file_put_contents($savePath, $content);
+
+ return [
+ 'success' => true,
+ 'path' => $savePath,
+ 'content' => $content,
+ 'message' => 'File downloaded successfully'
+ ];
+ }
+
+ return [
+ 'success' => true,
+ 'path' => null,
+ 'content' => $content,
+ 'message' => 'File content retrieved successfully'
+ ];
+
+ } catch (AwsException $e) {
+ log_message('error', 'S3 Download Error: ' . $e->getMessage());
+ return [
+ 'success' => false,
+ 'path' => null,
+ 'content' => null,
+ 'message' => 'Download failed: ' . $e->getMessage()
+ ];
+ }
+ }
+
+ /**
+ * Get a pre-signed URL for temporary access to a private file
+ *
+ * @param string $key S3 object key
+ * @param int $expiration Expiration time in minutes (default: 60)
+ * @return array ['success' => bool, 'url' => string, 'message' => string]
+ */
+ public function getPresignedUrl(string $key, int $expiration = 60): array
+ {
+ try {
+ $cmd = $this->s3Client->getCommand('GetObject', [
+ 'Bucket' => $this->bucket,
+ 'Key' => $key
+ ]);
+
+ $request = $this->s3Client->createPresignedRequest($cmd, "+{$expiration} minutes");
+ $presignedUrl = (string) $request->getUri();
+
+ return [
+ 'success' => true,
+ 'url' => $presignedUrl,
+ 'message' => 'Pre-signed URL generated successfully'
+ ];
+
+ } catch (AwsException $e) {
+ log_message('error', 'S3 Presigned URL Error: ' . $e->getMessage());
+ return [
+ 'success' => false,
+ 'url' => null,
+ 'message' => 'Failed to generate URL: ' . $e->getMessage()
+ ];
+ }
+ }
+
+ /**
+ * Delete file from S3
+ *
+ * @param string $key S3 object key
+ * @return array ['success' => bool, 'message' => string]
+ */
+ public function delete(string $key): array
+ {
+ try {
+ $this->s3Client->deleteObject([
+ 'Bucket' => $this->bucket,
+ 'Key' => $key,
+ ]);
+
+ return [
+ 'success' => true,
+ 'message' => 'File deleted successfully'
+ ];
+
+ } catch (AwsException $e) {
+ log_message('error', 'S3 Delete Error: ' . $e->getMessage());
+ return [
+ 'success' => false,
+ 'message' => 'Delete failed: ' . $e->getMessage()
+ ];
+ }
+ }
+
+ /**
+ * Check if file exists in S3
+ *
+ * @param string $key S3 object key
+ * @return bool
+ */
+ public function exists(string $key): bool
+ {
+ return $this->s3Client->doesObjectExist($this->bucket, $key);
+ }
+
+ /**
+ * List files in S3 bucket
+ *
+ * @param string $prefix Folder prefix (optional)
+ * @return array ['success' => bool, 'files' => array, 'message' => string]
+ */
+ public function listFiles(string $prefix = ''): array
+ {
+ try {
+ $result = $this->s3Client->listObjectsV2([
+ 'Bucket' => $this->bucket,
+ 'Prefix' => $prefix,
+ ]);
+
+ $files = [];
+ if (isset($result['Contents'])) {
+ foreach ($result['Contents'] as $object) {
+ $files[] = [
+ 'key' => $object['Key'],
+ 'size' => $object['Size'],
+ 'last_modified' => $object['LastModified']->format('Y-m-d H:i:s'),
+ 'url' => $this->baseUrl . $object['Key']
+ ];
+ }
+ }
+
+ return [
+ 'success' => true,
+ 'files' => $files,
+ 'message' => 'Files retrieved successfully'
+ ];
+
+ } catch (AwsException $e) {
+ log_message('error', 'S3 List Error: ' . $e->getMessage());
+ return [
+ 'success' => false,
+ 'files' => [],
+ 'message' => 'Failed to list files: ' . $e->getMessage()
+ ];
+ }
+ }
+}
\ No newline at end of file
diff --git a/composer.json b/composer.json
index e86456ca..0aed2a9b 100755
--- a/composer.json
+++ b/composer.json
@@ -14,6 +14,7 @@
"ext-intl": "*",
"ext-json": "*",
"ext-mbstring": "*",
+ "aws/aws-sdk-php": "^3.369",
"botman/botman": "^2.8",
"botman/driver-web": "^1.5",
"dompdf/dompdf": "^2.0",
@@ -72,7 +73,7 @@
]
},
"config": {
- "optimize-autoloader": true,
+ "optimize-autoloader": false,
"preferred-install": "dist",
"sort-packages": true,
"process-timeout": 900