diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 60be1178..e88bbc81 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/ApiServiceController.php b/app/Controllers/ApiServiceController.php index 5f8f17e4..e1858c95 100644 --- a/app/Controllers/ApiServiceController.php +++ b/app/Controllers/ApiServiceController.php @@ -92,13 +92,25 @@ class ApiServiceController extends BaseController } + // $employee_policy = $this->employeePolicyModel + // ->select('employees.*, employee_polices.tpa_id , employee_polices.rand_string , employee_polices.uhid as uhid , client_policy.tpa_id as tpa_primary_id ') + // ->join('employees', 'employee_polices.employee_id = employees.id', 'left') + // ->join('client_policy', 'employee_polices.client_policy_id = client_policy.id', 'left') + // ->where('employee_polices.employee_id',$id) + // ->where('employee_polices.client_policy_id',$client_policy_id) + // ->where('employee_polices.is_active', 1 )->findAll(); + $employee_policy = $this->employeePolicyModel ->select('employees.*, employee_polices.tpa_id , employee_polices.rand_string , employee_polices.uhid as uhid , client_policy.tpa_id as tpa_primary_id ') ->join('employees', 'employee_polices.employee_id = employees.id', 'left') ->join('client_policy', 'employee_polices.client_policy_id = client_policy.id', 'left') - ->where('employee_polices.employee_id',$id) - ->where('employee_polices.client_policy_id',$client_policy_id) - ->where('employee_polices.is_active', 1 )->findAll(); + ->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) + ->where('employee_polices.status', 'active') + ->where('employees.emp_status', 'active') + ->findAll(); if(count($employee_policy) > 0) diff --git a/app/Controllers/ClientController.php b/app/Controllers/ClientController.php index 039f6f99..89069011 100755 --- a/app/Controllers/ClientController.php +++ b/app/Controllers/ClientController.php @@ -2726,7 +2726,9 @@ class ClientController extends AdminController $search_term = 'GMC'; } else if (preg_match($gpa_pattern, $subject) || $policy_type_id == 6 || $policy_type_id == 7) { $search_term = 'GPA'; - } else { + } else if($policy_type_id == 72){ + $search_term = 'GMC'; + }else { $search_term = ""; } @@ -2736,7 +2738,7 @@ class ClientController extends AdminController if ($search_term === 'GPA' || $policy_type_id == 6 || $policy_type_id == 7) { $premiumData = $this->policyPremium1Model->where(['client_id' => $record['client_id'], 'client_policy_id' => $client_policy_id, 'is_active' => 1])->findAll(); - } else if ($search_term === 'GMC') { + } else if ($search_term === 'GMC' || $policy_type_id == 72) { $premiumData = $this->policyPremium2Model->where(['client_id' => $record['client_id'], 'client_policy_id' => $client_policy_id, 'is_active' => 1])->findAll(); @@ -2766,7 +2768,7 @@ class ClientController extends AdminController // echo '
';
         // echo $family_floater;
 
-        if ($search_term === 'GMC') {
+        if ($search_term === 'GMC'  || $policy_type_id == 72 ) {
 
             // $resultss = [];
             $resultss = $results;
@@ -3400,6 +3402,7 @@ class ClientController extends AdminController
                 [
                     'Status' => true,
                     'code' => 200,
+                    'policy_type_id' => $record['policy_type_id'],
                     'data' => $record['policy_terms'],
                     'policy_addon' => $record['is_addon'],
                     'emp_count_by_policy' => $emp_count_by_policy
@@ -4225,34 +4228,41 @@ class ClientController extends AdminController
         $client_policy_id = $this->request->getPost("client_policy_id");
         $policy_terms = $this->request->getPost("policy_terms");
         $policy_terms = json_decode($policy_terms, true);
-
-        $data = [];
-
-        foreach ($policy_terms as $key => $value) {
-
-            if (str_ends_with($key, '_display')) {
-
-                $original_key = substr($key, 0, -8);
-
-                $newKey = implode(' ', array_map('ucfirst', explode('_', $original_key)));
-
-                $data['enrollment_display_key'][$newKey] = $policy_terms[$original_key] ?? " ";
-            } else {
-
-                $data[$key] = $value;
-            }
-        }
-
-        if (!empty($data)) {
-            $policy_terms['is_payable_employee']['self'] = 0;
-            $policy_terms = json_encode($data);
-        }
-
-
         $record = $this->clientPolicyModel->where('id', $client_policy_id)->first();
+        // print_r($policy_terms); die;
+
+        if(empty($policy_terms)){
+            return $this->respond(['status' => false, 'code' => 404, 'message' => 'Policy terms data could not be empty', 'formdata' => $this->request->getPost()], 200);
+        }
 
         if ($record) {
 
+            $data = [];
+
+            foreach ($policy_terms as $key => $value) {
+
+                if (str_ends_with($key, '_display')) {
+
+                    $original_key = substr($key, 0, -8);
+
+                    $newKey = implode(' ', array_map('ucfirst', explode('_', $original_key)));
+
+                    $data['enrollment_display_key'][$newKey] = $policy_terms[$original_key] ?? " ";
+                } else {
+
+                    $data[$key] = $value;
+                }
+            }
+
+            if($record['policy_type_id'] == 72){
+                $data['enrollment_display_key'] = $this->otherPolicyTermsDisplayKeyConstruct($policy_terms);
+            }
+
+            if (!empty($data)) {
+                $policy_terms['is_payable_employee']['self'] = 0;
+                $policy_terms = json_encode($data);
+            }
+
             $update = $this->clientPolicyModel->where('id', $client_policy_id)->set('policy_terms',  $policy_terms)->update();
 
             if ($update) {
@@ -4260,12 +4270,34 @@ class ClientController extends AdminController
             } else {
                 return $this->respond(['status' => false, 'code' => 404, 'message' => 'Failed to update data', 'formdata' => $this->request->getPost()], 200);
             }
+
         } else {
 
             return $this->respond(['status' => false, 'code' => 404, 'message' => 'Failed to store data. The client policy does not exist', 'formdata' => $this->request->getPost()], 200);
         }
     }
 
+    public function otherPolicyTermsDisplayKeyConstruct($data)
+    {
+        $labels = $data['special_condition_label'] ?? [];
+        $values = $data['special_condition_input'] ?? [];
+
+        $special_conditions = [];
+
+        foreach ($labels as $i => $label) {
+            $value = $values[$i] ?? '';
+
+            // skip if label or value is empty
+            if (trim($label) === '' || trim($value) === '') {
+                continue;
+            }
+
+            $special_conditions[$label] = $value;
+        }
+
+        return $special_conditions;
+    }
+
     public function checkPolicyType($policy_type_id, $client_branch_id, $client_id)
     {
 
@@ -5971,8 +6003,8 @@ class ClientController extends AdminController
         // ---------- EMP SERVICE CONTROLLER --------------------------------------------------------------------------------
 
         $empServiceController = new EmployeeServiceController();
-        // $res = $empServiceController->excelFileFormatValidation(['file_id' => '1126']);
-        // $res = $empServiceController->excelFileDataValidation(['file_id' => '865']);
+        // $res = $empServiceController->excelFileFormatValidation(['file_id' => '1248']);
+        // $res = $empServiceController->excelFileDataValidation(['file_id' => '1248']);
         // $res = $empServiceController->employeesOnboardPreprocess(['file_id' => 1183]);
         // $res = $empServiceController->employeesOnboardPreprocess(['file_id' => 1169]);
         // $res = $empServiceController->employeesOnboardProcess(['file_id' => 835]);
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/app/Views/faq_list.php b/app/Views/faq_list.php index e725b7e3..9a4d6d8c 100644 --- a/app/Views/faq_list.php +++ b/app/Views/faq_list.php @@ -3,6 +3,33 @@ position: absolute; } .dataTables_length label {height: 21px !important;} + +.custom-dropdown-menu { + display: none; + position: absolute; + background-color: #ffffff !important; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 0.25rem; + padding: 0.5rem 0; + min-width: 10rem; + z-index: 9999; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); +} + +.custom-dropdown-menu .dropdown-item { + display: block !important; + width: 100% !important; + padding: 0.5rem 1rem !important; + color: #212529 !important; + text-decoration: none !important; + background-color: transparent !important; +} + +.custom-dropdown-menu .dropdown-item:hover { + background-color: #f8f9fa !important; + color: #16181b !important; + cursor: pointer !important; +} @@ -16,13 +43,15 @@ S.No. Category Question - Answer + Status Action - + $row) { ?> @@ -36,11 +65,11 @@ ? htmlspecialchars(substr($question, 0, 50)) . "..." : htmlspecialchars($question); ?> - 50) ? htmlspecialchars(substr($answer, 0, 50)) . "..." : htmlspecialchars($answer); - ?> + ?> --> @@ -62,12 +91,7 @@ - - - - + @@ -353,4 +377,93 @@ }); + diff --git a/app/Views/frontend_content_list.php b/app/Views/frontend_content_list.php index f0df3b93..ce3db484 100644 --- a/app/Views/frontend_content_list.php +++ b/app/Views/frontend_content_list.php @@ -3,6 +3,32 @@ position: absolute; } .dataTables_length label {height: 21px !important;} +.custom-dropdown-menu { + display: none; + position: absolute; + background-color: #ffffff !important; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 0.25rem; + padding: 0.5rem 0; + min-width: 10rem; + z-index: 9999; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); +} + +.custom-dropdown-menu .dropdown-item { + display: block !important; + width: 100% !important; + padding: 0.5rem 1rem !important; + color: #212529 !important; + text-decoration: none !important; + background-color: transparent !important; +} + +.custom-dropdown-menu .dropdown-item:hover { + background-color: #f8f9fa !important; + color: #16181b !important; + cursor: pointer !important; +} @@ -23,7 +49,7 @@ - + $row) { ?> @@ -51,12 +77,7 @@ - - - - + @@ -503,4 +524,93 @@ } + diff --git a/app/Views/other_policy_terms.php b/app/Views/other_policy_terms.php index 16166973..5174a53c 100755 --- a/app/Views/other_policy_terms.php +++ b/app/Views/other_policy_terms.php @@ -72,6 +72,11 @@ margin-left: 30px; width: 689px; } + + .other-speciial-condition{ + margin-left: 150px; + width: 564px; + } \ No newline at end of file diff --git a/app/Views/policy_grid.php b/app/Views/policy_grid.php index 4db9f219..af786b4b 100755 --- a/app/Views/policy_grid.php +++ b/app/Views/policy_grid.php @@ -3522,7 +3522,7 @@ function hideShowPolicyPremium(policy_type_string, unique_id = null) individual = $('#individual_' + unique_id); } - if (policy_type_string == 'GMC') { + if (policy_type_string == 'GMC' || policy_type_string == 'OPD') { premium_type.show(); individual.prop('checked', true) } else { diff --git a/app/Views/pos_list.php b/app/Views/pos_list.php index c6b08022..2c1c1af5 100644 --- a/app/Views/pos_list.php +++ b/app/Views/pos_list.php @@ -3,6 +3,32 @@ position: absolute; } .dataTables_length label {height: 21px !important;} +.custom-dropdown-menu { + display: none; + position: absolute; + background-color: #ffffff !important; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 0.25rem; + padding: 0.5rem 0; + min-width: 10rem; + z-index: 9999; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); +} + +.custom-dropdown-menu .dropdown-item { + display: block !important; + width: 100% !important; + padding: 0.5rem 1rem !important; + color: #212529 !important; + text-decoration: none !important; + background-color: transparent !important; +} + +.custom-dropdown-menu .dropdown-item:hover { + background-color: #f8f9fa !important; + color: #16181b !important; + cursor: pointer !important; +} @@ -24,7 +50,7 @@ - + $row) { ?> @@ -54,12 +80,7 @@ - - - - No data available - - + @@ -480,5 +501,94 @@ + + 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