diff --git a/app/Controllers/PlanController.php b/app/Controllers/PlanController.php index 0358490..7ab9177 100644 --- a/app/Controllers/PlanController.php +++ b/app/Controllers/PlanController.php @@ -112,8 +112,9 @@ class PlanController extends ResourceController $a1Data = $this->planStatusModel->select('plan_id')->where('a1_id',$user_id)->where('a1_action','Approval')->where('is_active',1)->findAll(); $a2Data = $this->planStatusModel->select('plan_id')->where('a2_id',$user_id)->where('a2_action','Approval')->where('is_active',1)->findAll(); $a3Data = $this->planStatusModel->select('plan_id')->where('a3_id',$user_id)->where('a3_action','Approval')->where('is_active',1)->findAll(); + $a4Data = $this->planStatusModel->select('plan_id')->where('a4_id',$user_id)->where('a4_action','Approval')->where('is_active',1)->findAll(); - $mergedArray = array_merge($a1Data, $a2Data, $a3Data); + $mergedArray = array_merge($a1Data, $a2Data, $a3Data, $a4Data); $planIds = array_unique(array_column($mergedArray, "plan_id")); $plans = []; if (count($planIds)) { @@ -514,6 +515,12 @@ class PlanController extends ResourceController sendPlanUpdationMail($planId); } + // Send mail to agent if plan status is 3 + $plan = $this->planModel->where('plan_id', $planId)->where('status', 3)->first(); + if ($plan) { + send_email_agent(env('ORG_id'), $planId); + } + return $this->respond(['status' => 'success', 'plan_id' => $planId]); } catch (\Exception $e) { @@ -775,15 +782,27 @@ class PlanController extends ResourceController $status = true; } + //approver 4 + $a4Data = $this->planStatusModel->where('plan_id',$plan_id)->where('a4_id',$user_id)->where('a4_action','Approval')->where('is_active',1)->findAll(); + if($a4Data){ + $this->planStatusModel->set(['is_a4_action_done'=>1,'a4_action_done_on'=>date('Y-m-d H:i:s'),'a4_reject_reason'=>null,'a4_action_done_by'=>$actionDoneBy]) + ->where('plan_id',$plan_id) + ->where('a4_id',$user_id) + ->where('a4_action','Approval') + ->where('is_active',1) + ->update(); + $status = true; + } + //response if($status) { - //update pdf content - $this->generatePlanPdf($plan_id); - //update plan status updatePlanStatus($plan_id); + + //update pdf content + $this->generatePlanPdf($plan_id); //send approval mail sendPlanApprovalOrRejectMail($plan_id,'A'); @@ -791,6 +810,13 @@ class PlanController extends ResourceController //send parallel or Sequential mail sendPlanCreationMail($plan_id, 'send_mail_to_only_approver'); + // Send mail to agent if plan status is 3 + $plan = $this->planModel->where('plan_id', $plan_id)->where('status', 3)->first(); + if ($plan) { + send_email_agent(env('ORG_id'), $plan_id); + } + + return $this->respond(['status' => 200, 'message' => 'success' ]); }else{ return $this->respond(['status' => 404, 'message' => 'failed' ]); @@ -859,6 +885,18 @@ class PlanController extends ResourceController $status = true; } + //approver 4 + $a4Data = $this->planStatusModel->where('plan_id',$plan_id)->where('a4_id',$user_id)->where('a4_action','Approval')->where('is_active',1)->findAll(); + if($a4Data){ + $this->planStatusModel->set(['is_a4_action_done'=>0, 'a4_reject_reason'=>$reason, 'a4_action_done_on'=>date('Y-m-d H:i:s'),'a4_action_done_by'=>$actionDoneBy]) + ->where('plan_id',$plan_id) + ->where('a4_id',$user_id) + ->where('a4_action','Approval') + ->where('is_active',1) + ->update(); + $status = true; + } + //response if($status) @@ -1240,6 +1278,11 @@ class PlanController extends ResourceController $userId = $plan['user_id'] ?? $plan['traveller_id']; + //current plan status + $status = getCurrentPlanStatus($planId); + + $plan['status_details'] = $status; + //get user data $plan['user_data'] = $this->userModel->where('user_id', $userId)->first(); $plan['view'] = $view; @@ -1433,15 +1476,21 @@ class PlanController extends ResourceController public function url() { + return $this->generatePlanPdf(57, true); + die; + + updatePlanStatus(57); die; + palnStatusHandler(57, false); die; + + echo '
';
-        sendPlanCreationMail(35);
-        print_r(getPlanApproverAction(35)); die;
+        // sendPlanCreationMail(39);
+        print_r(getPlanApproverAction(52)); die;
 
         // echo '
';
         // print_r(getAllowedClassForUser(2,4)['hotel']); die;
 
-        return $this->generatePlanPdf(53, true);
-        die;
+        
 
         return send_email_agent(env('ORG_id') , 62);
         return updatePlanStatus(62);
diff --git a/app/Controllers/UserController.php b/app/Controllers/UserController.php
index ad32be0..1cb2bd3 100644
--- a/app/Controllers/UserController.php
+++ b/app/Controllers/UserController.php
@@ -728,7 +728,7 @@ public function userUpload()
     $insertUsers     = [];
 
     $dbHeaders = ['first_name','last_name','email','mobile_no','password','role_id','employee_code','group_id',
-    'first_approver_email','second_approver_email','third_approver_email','exceptional_approver_email'];
+    'first_approver_email','second_approver_email','third_approver_email','fourth_approver_email'];
 
     $rolesList = $this->userModel->getRolesList();
 
@@ -781,9 +781,9 @@ public function userUpload()
         }
 
 
-        if (!empty($user['exceptional_approver_email']) && !filter_var($user['exceptional_approver_email'], FILTER_VALIDATE_EMAIL)) {
+        if (!empty($user['fourth_approver_email']) && !filter_var($user['fourth_approver_email'], FILTER_VALIDATE_EMAIL)) {
             $fail++;
-            $failedUsers[] = ['data'  => $user['first_name'].' '.$user['last_name'], 'reason' => 'Invalid exceptional_approver_email format' ];
+            $failedUsers[] = ['data'  => $user['first_name'].' '.$user['last_name'], 'reason' => 'Invalid fourth_approver_email format' ];
             continue;
         }
 
@@ -799,7 +799,7 @@ public function userUpload()
         $user['first_approver_email'] = filter_var($user['first_approver_email'], FILTER_SANITIZE_EMAIL);
         $user['second_approver_email'] = filter_var($user['second_approver_email'], FILTER_SANITIZE_EMAIL);
         $user['third_approver_email'] = filter_var($user['third_approver_email'], FILTER_SANITIZE_EMAIL);
-        $user['exceptional_approver_email'] = filter_var($user['exceptional_approver_email'], FILTER_SANITIZE_EMAIL);
+        $user['fourth_approver_email'] = filter_var($user['fourth_approver_email'], FILTER_SANITIZE_EMAIL);
         $user['role_id'] = $rolesList[$role] ?? 4;
         $user['group_id'] = $groupsList[$group] ?? null;
         $user['org_id'] = env('ORG_id');
@@ -841,7 +841,7 @@ public function userUpload()
     $this->userModel->updateApprover('first', $insertedIds);
     $this->userModel->updateApprover('second', $insertedIds);
     $this->userModel->updateApprover('third', $insertedIds);
-    $this->userModel->updateApprover('exceptional', $insertedIds);
+    $this->userModel->updateApprover('fourth', $insertedIds);
 
 
     return $this->response->setJSON([
diff --git a/app/Helpers/common_helper.php b/app/Helpers/common_helper.php
index b234c3e..7cfd57e 100644
--- a/app/Helpers/common_helper.php
+++ b/app/Helpers/common_helper.php
@@ -77,7 +77,6 @@ if (!function_exists('getUserPlanCreationRestrictionStatus')) {
     }
 }
 
-
 if (!function_exists('isDataChanged')) {
     function isDataChanged($model, $id, array $newData): bool
     {
@@ -208,9 +207,17 @@ function getDelegatedPlans($org_id, $id)
                                   ->where('created_on >=', $startDate)
                                   ->where('created_on <=', $endDate)
                                   ->findAll();
+
+        $a4Data = $planStatusModel->select('plan_id,a4_id as user_id')
+                                  ->where('a4_id',$userId)
+                                  ->where('a4_action','Approval')
+                                  ->where('is_active',1)
+                                  ->where('created_on >=', $startDate)
+                                  ->where('created_on <=', $endDate)
+                                  ->findAll();
         
        // Merge results (each record has plan_id + user_id)
-       $merged = array_merge($a1Data, $a2Data, $a3Data);
+       $merged = array_merge($a1Data, $a2Data, $a3Data, $a4Data);
 
        // Merge into final array
        $allPlanData = array_merge($allPlanData, $merged);
@@ -218,9 +225,9 @@ function getDelegatedPlans($org_id, $id)
     }
    
     //get already approved data in delegated flow
-    $a1 = $planStatusModel->select('plan_id,a1_id as user_id')->where('a1_action_done_by',$id)->where('a1_action','Approval')->where('is_active',1)->findAll();
-    $a2 = $planStatusModel->select('plan_id,a2_id as user_id')->where('a2_action_done_by',$id)->where('a2_action','Approval')->where('is_active',1)->findAll();
-    $a3 = $planStatusModel->select('plan_id,a3_id as user_id')->where('a3_action_done_by',$id)->where('a3_action','Approval')->where('is_active',1)->findAll();
+    // $a1 = $planStatusModel->select('plan_id,a1_id as user_id')->where('a1_action_done_by',$id)->where('a1_action','Approval')->where('is_active',1)->findAll();
+    // $a2 = $planStatusModel->select('plan_id,a2_id as user_id')->where('a2_action_done_by',$id)->where('a2_action','Approval')->where('is_active',1)->findAll();
+    // $a3 = $planStatusModel->select('plan_id,a3_id as user_id')->where('a3_action_done_by',$id)->where('a3_action','Approval')->where('is_active',1)->findAll();
 
     //need to discuss with sir
     // $mergedApprovedArray = array_merge($a1, $a2, $a3);
@@ -299,172 +306,92 @@ if (!function_exists('format_date_for_client')) {
     }
 }
 
-
-
-// if (!function_exists('palnStatusHandler')) {
-//     function palnStatusHandler($plan_id, $service_id, $action)
-//     {
-
-        
-//         $planModel = new PlanModel();
-//         $planStatusModel = new PlanStatusModel();
-//         $userModel = new UserModel();
-//         $groupModel = new GroupModel();
-//         $policyModel = new PolicyModel();
-//         $policyDetailsModel = new PolicyDetailsModel();
-
-//         if($action == 'DEL')
-//         {
-//             // Delete status
-//             $planStatusModel->set(['is_active' => 0])->where('plan_id',$plan_id)->where('service_id',$service_id)->where('is_active',1)->update();
-//             return true;
-//         }
-
-//         if($action == 'ADD')
-//         {
-//             //check already created
-//             $status = $planStatusModel->where('plan_id',$plan_id)->where('service_id',$service_id)->where('is_active',1)->first();
-//             if ($status) { return false; }
-//         }
-        
-
-//        // Fetch plan data
-//         $planData = $planModel->where('plan_id', $plan_id)->first();
-//             if (!$planData) { return false; }
-//             $userId = $planData['user_id'] ?? $planData['traveller_id'];
-
-//         // Fetch user data
-//         $userData = $userModel->where('user_id', $userId)->first();
-//             if (!$userData) { return false; }
-//             $groupId = $userData['group_id'];
-//             $a1Id = $userData['first_approver'];
-//             $a2Id = $userData['second_approver'];
-//             $a3Id = $userData['third_approver'];
-
-//         // Fetch group data
-//         $groupData = $groupModel->where('group_id', $groupId)->first();
-//             if (!$groupData) { return false; }
-//             $policyId = ($planData['trip_type'] == 1) ? $groupData['domestic_policy_id'] : $groupData['international_policy_id'];
-
-//         // Fetch policy service data
-//         $policyServiceData = $policyDetailsModel->where('policy_id', $policyId)->where('service_id', $service_id)->first();
-//             if (!$policyServiceData) {return false; }
-//             $policyA1Action = $policyServiceData['a1_action'];
-//             $policyA2Action = $policyServiceData['a2_action'];
-//             $policyA3Action = $policyServiceData['a3_action'];
-//             $policyParallelAction = $policyServiceData['parallel_process_from'];
-        
-
-//         if($action == 'ADD')
-//         {
-//             $data['plan_id'] = $plan_id;
-//             $data['service_id'] = $service_id;
-//             $data['a1_id'] = $a1Id;
-//             $data['a1_action'] = $policyA1Action;
-//             $data['a2_id'] = $a2Id;
-//             $data['a2_action'] = $policyA2Action;
-//             $data['a3_id'] = $a3Id;
-//             $data['a3_action'] = $policyA3Action;
-//             $data['parallel_process_from'] = $policyParallelAction;
-//             // Insert Status
-//             $planStatusModel->insert($data);
-//         }
-
-  
-//     }
-// }
-
-
-    if (!function_exists('isValidUploadedFile')) {
-        function isValidUploadedFile($file): bool
-        {
-            return $file && $file->isValid();
-        }
-    }
-
-    if (!function_exists('isAllowedExtension')) {
-        function isAllowedExtension($file, array $allowedExtensions = [] ): bool
-        {
-            $ext = strtolower($file->getClientExtension());
-
-            $result = in_array($ext, $allowedExtensions);
-
-            $result = empty($allowedExtensions) ? true : $result ;
-
-            return $result;
-        }
-    }
-
-
-    if (!function_exists('isExcelNotEmpty')) {
-        function isExcelNotEmpty(array $sheetData): bool
-        {
-            return !empty($sheetData) && count($sheetData) >= 2;
-        }
-    }
-
-    if(!function_exists('createDirectoryWith0777Permission')){
-
-        function createDirectoryWith0777Permission( $uploadDir)
-        {
-            if (!is_dir($uploadDir)) {
-                mkdir($uploadDir, 0777, true); // recursive creation with full permission
-            }
-
-        }
-
-    }
-
-
-
-
-    function getAllowedClassForUser($trip_type,$user_id)
+if (!function_exists('isValidUploadedFile')) {
+    function isValidUploadedFile($file): bool
     {
+        return $file && $file->isValid();
+    }
+}
 
-        $userModel = new UserModel();
-        $groupModel = new GroupModel();
-        $policyDetailsModel = new PolicyDetailsModel();
-        $policyDetailsModel = new PolicyDetailsModel();
+if (!function_exists('isAllowedExtension')) {
+    function isAllowedExtension($file, array $allowedExtensions = [] ): bool
+    {
+        $ext = strtolower($file->getClientExtension());
 
-        $user = $userModel->where('user_id', $user_id)->first();
-        $groupData = $groupModel->find($user['group_id']);
-       
-        if($groupData)
-        {
-            if($trip_type == 1) { $policyId = $groupData['domestic_policy_id'];}else{ $policyId = $groupData['international_policy_id'];}
-            if($policyId != null)
-            {
-                $allowedFlightClass = $policyDetailsModel->select('c_policy_details.class, m_dropdown.dropdown_value as allowed_class')
-                                    ->join('m_dropdown', 'dropdown_key = c_policy_details.class AND dropdown = "flight_class"', 'left')
-                                     ->where('policy_id',$policyId)
-                                     ->where('service_id',1)
-                                     ->first();
-                $data['flight'] = $allowedFlightClass['allowed_class'];
+        $result = in_array($ext, $allowedExtensions);
 
-                $allowedTrainClass = $policyDetailsModel->select('c_policy_details.class, m_dropdown.dropdown_value as allowed_class')
-                                     ->join('m_dropdown', 'dropdown_key = c_policy_details.class AND dropdown = "train_class"', 'left')
-                                      ->where('policy_id',$policyId)
-                                      ->where('service_id',2)
-                                      ->first();
-                $data['train'] = $allowedTrainClass['allowed_class'];
+        $result = empty($allowedExtensions) ? true : $result ;
 
-                $allowedHotelClass = $policyDetailsModel->select('c_policy_details.class, m_dropdown.dropdown_value as allowed_class')
-                                      ->join('m_dropdown', 'dropdown_key = c_policy_details.class AND dropdown = "hotel_class"', 'left')
-                                       ->where('policy_id',$policyId)
-                                       ->where('service_id',5)
-                                       ->first();
-                $data['hotel'] = $allowedHotelClass['allowed_class'];
-            }
+        return $result;
+    }
+}
 
+if (!function_exists('isExcelNotEmpty')) {
+    function isExcelNotEmpty(array $sheetData): bool
+    {
+        return !empty($sheetData) && count($sheetData) >= 2;
+    }
+}
 
-           return $data;
+if(!function_exists('createDirectoryWith0777Permission')){
 
+    function createDirectoryWith0777Permission( $uploadDir)
+    {
+        if (!is_dir($uploadDir)) {
+            mkdir($uploadDir, 0777, true); // recursive creation with full permission
         }
-       
-       
 
     }
 
+}
+
+function getAllowedClassForUser($trip_type,$user_id)
+{
+
+    $userModel = new UserModel();
+    $groupModel = new GroupModel();
+    $policyDetailsModel = new PolicyDetailsModel();
+    $policyDetailsModel = new PolicyDetailsModel();
+
+    $user = $userModel->where('user_id', $user_id)->first();
+    $groupData = $groupModel->find($user['group_id']);
+    
+    if($groupData)
+    {
+        if($trip_type == 1) { $policyId = $groupData['domestic_policy_id'];}else{ $policyId = $groupData['international_policy_id'];}
+        if($policyId != null)
+        {
+            $allowedFlightClass = $policyDetailsModel->select('c_policy_details.class, m_dropdown.dropdown_value as allowed_class')
+                                ->join('m_dropdown', 'dropdown_key = c_policy_details.class AND dropdown = "flight_class"', 'left')
+                                    ->where('policy_id',$policyId)
+                                    ->where('service_id',1)
+                                    ->first();
+            $data['flight'] = $allowedFlightClass['allowed_class'];
+
+            $allowedTrainClass = $policyDetailsModel->select('c_policy_details.class, m_dropdown.dropdown_value as allowed_class')
+                                    ->join('m_dropdown', 'dropdown_key = c_policy_details.class AND dropdown = "train_class"', 'left')
+                                    ->where('policy_id',$policyId)
+                                    ->where('service_id',2)
+                                    ->first();
+            $data['train'] = $allowedTrainClass['allowed_class'];
+
+            $allowedHotelClass = $policyDetailsModel->select('c_policy_details.class, m_dropdown.dropdown_value as allowed_class')
+                                    ->join('m_dropdown', 'dropdown_key = c_policy_details.class AND dropdown = "hotel_class"', 'left')
+                                    ->where('policy_id',$policyId)
+                                    ->where('service_id',5)
+                                    ->first();
+            $data['hotel'] = $allowedHotelClass['allowed_class'];
+        }
+
+
+        return $data;
+
+    }
+    
+    
+
+}
+
 
 
 
diff --git a/app/Helpers/mail_helper.php b/app/Helpers/mail_helper.php
index 28294ab..03229d0 100644
--- a/app/Helpers/mail_helper.php
+++ b/app/Helpers/mail_helper.php
@@ -70,7 +70,11 @@ if (!function_exists('sendPlanCreationMail')) {
                 {
                     sendPlanCreationMail($planId , 'send_mail_to_only_approver');
                 }
-                if($parallelProcessValue == 3)
+                if($parallelProcessValue == 3 && ($value['action_key'] == 'a1_action' || $value['action_key'] == 'a2_action') )
+                {
+                    sendPlanCreationMail($planId , 'send_mail_to_only_approver');
+                }
+                if($parallelProcessValue == 4 && ($value['action_key'] == 'a1_action' || $value['action_key'] == 'a2_action' || $value['action_key'] == 'a3_action'))
                 {
                     sendPlanCreationMail($planId , 'send_mail_to_only_approver');
                 }
@@ -142,6 +146,10 @@ if (!function_exists('sendPlanApprovalOrRejectMail')) {
             if (isset($value['a3_status'])) {
                 $statusHtml .= '
  • Approver 3: ' . $value['a3_status'] . '
  • '; } + + if (isset($value['a4_status'])) { + $statusHtml .= '
  • Approver 4: ' . $value['a4_status'] . '
  • '; + } } $statusHtml .= ''; $userData['status_details'] = $statusHtml; @@ -217,7 +225,11 @@ if (!function_exists('sendPlanUpdationMail')) { { sendPlanCreationMail($planId , 'send_mail_to_only_approver'); } - if($parallelProcessValue == 3) + if($parallelProcessValue == 3 && ($value['action_key'] == 'a1_action' || $value['action_key'] == 'a2_action') ) + { + sendPlanCreationMail($planId , 'send_mail_to_only_approver'); + } + if($parallelProcessValue == 4 && ($value['action_key'] == 'a1_action' || $value['action_key'] == 'a2_action' || $value['action_key'] == 'a3_action')) { sendPlanCreationMail($planId , 'send_mail_to_only_approver'); } @@ -268,30 +280,82 @@ if (!function_exists('sendUserCreationMail')) { $html = $templateData['body_html']; $toEmailId = $mailData['email']; - $email = \Config\Services::email(); - $email->initialize([ - 'protocol' => 'smtp', - 'SMTPHost' => $orgData['mail_host'], - 'SMTPUser' => $orgData['mail_user_name'], - 'SMTPPass' => $orgData['mail_password'], - 'SMTPPort' => (int)$orgData['mail_port'], - 'mailType' => 'html' - ]); - $email->setFrom($orgData['sender_email'], $orgData['name']); - $email->setTo($toEmailId); - $email->setSubject($subject); - $email->setMessage($html); + + // Set up ZeptoMail API request + $endpoint = "https://api.zeptomail.com/v1.1/email"; + $apiKey = env('ZOHO_API_KEY'); + $sender = env('ZOHO_SENDER_MAIL'); + + $payload = [ + "from" => [ + "address" => $sender, + "name" => $orgData['name'] ?? "TripApprovalTool" + ], + "to" => [ + ["email_address" => ["address" => $toEmailId]] + ], + "subject" => $subject, + "htmlbody" => $html, + ]; + + $headers = [ + "Content-Type: application/json", + "Authorization: Zoho-enczapikey " . $apiKey + ]; + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $endpoint); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + + if (curl_errno($ch)) { + $error_msg = curl_error($ch); + log_message('error', "[EMAIL ERROR] Curl failed: {$error_msg}"); + return ['status' => 'failed', 'code' => 500, 'message' => 'Curl error', 'error' => $error_msg]; + } + + curl_close($ch); + + $resp = json_decode($response, true); + + if ($httpCode === 200 && isset($resp['request_id'])) { + log_message('info', "[EMAIL SENT] To: {$toEmailId}, Template: {$mailData['template']}"); + return ['status' => 'success', 'code' => 200, 'message' => 'Email sent successfully', 'data' => $toEmailId]; + } else { + log_message('error', "[EMAIL FAILED] HTTP: {$httpCode}, Response: {$response}"); + return ['status' => 'failed', 'code' => $httpCode, 'message' => 'Email sending failed', 'response' => $response]; + } + + + // $email = \Config\Services::email(); + // $email->initialize([ + // 'protocol' => 'smtp', + // 'SMTPHost' => $orgData['mail_host'], + // 'SMTPUser' => $orgData['mail_user_name'], + // 'SMTPPass' => $orgData['mail_password'], + // 'SMTPPort' => (int)$orgData['mail_port'], + // 'mailType' => 'html' + // ]); + // $email->setFrom($orgData['sender_email'], $orgData['name']); + // $email->setTo($toEmailId); + // $email->setSubject($subject); + // $email->setMessage($html); - if ($email->send()) { + // if ($email->send()) { - log_message('debug', 'Email Success to ' . $toEmailId); - return ['status' => 'success', 'code' => 200, 'message' => 'Email Sent Successfully...', 'data' => $toEmailId]; - } else { - log_message('debug', 'Email sending failed: ' . $email->printDebugger(['headers'])); - return ['status' => 'failed', 'code' => 404, 'message' => 'Email Sent Failed...', 'data' => $toEmailId]; - } + // log_message('debug', 'Email Success to ' . $toEmailId); + // return ['status' => 'success', 'code' => 200, 'message' => 'Email Sent Successfully...', 'data' => $toEmailId]; + // } else { + // log_message('debug', 'Email sending failed: ' . $email->printDebugger(['headers'])); + // return ['status' => 'failed', 'code' => 404, 'message' => 'Email Sent Failed...', 'data' => $toEmailId]; + // } @@ -690,15 +754,7 @@ if (!function_exists('send_email_agent')) { return false; } - $email = \Config\Services::email(); - $email->initialize([ - 'protocol' => 'smtp', - 'SMTPHost' => $orgData['mail_host'], - 'SMTPUser' => $orgData['mail_user_name'], - 'SMTPPass' => $orgData['mail_password'], - 'SMTPPort' => (int)$orgData['mail_port'], - 'mailType' => 'html' - ]); + foreach ($userData as $key => $value) { $jsonString = $value['agent_supported_service_ids']; @@ -727,24 +783,101 @@ if (!function_exists('send_email_agent')) { $subject = $templateData['subject']; $html = $templateData['body_html']; - //trigger_email_to agent - $email->setFrom($orgData['sender_email'], $orgData['name']); - $email->setTo($value['email']); - $email->setSubject($subject); - $email->setMessage($html); - - if(!empty($planData)){ - $email->attach($planData['pdf_file_path']); + + // Set up ZeptoMail API request + $endpoint = "https://api.zeptomail.com/v1.1/email"; + $apiKey = env('ZOHO_API_KEY'); + $sender = env('ZOHO_SENDER_MAIL'); + + $attachments = []; + + $filePath = WRITEPATH . 'pdf/trips/trip_' . $planData['plan_id'] . '.pdf'; + if (!empty($filePath) && file_exists($filePath) && is_readable($filePath)) { + $attachments[] = [ + "content" => base64_encode(file_get_contents($filePath)), + "mime_type" => "application/pdf", + "name" => basename($filePath) + ]; } - if ($email->send()) { - - log_message('debug', 'Email Success to agent plan_id = ' .$plan_id.'email = ' . $value['email']); - - } else { - log_message('debug', 'Email sending failed: agent plan_id = ' .$plan_id.'email = ' . $value['email'].'error = '.$email->printDebugger(['headers'])); - + $payload = [ + "from" => [ + "address" => $sender, + "name" => $orgData['name'] ?? "TripApprovalTool" + ], + "to" => [ + ["email_address" => ["address" => $value['email']]] + ], + "subject" => $templateData['subject'], + "htmlbody" => $templateData['body_html'], + ]; + + if (!empty($attachments)) { + $payload["attachments"] = $attachments; } + + $headers = [ + "Content-Type: application/json", + "Authorization: Zoho-enczapikey " . $apiKey + ]; + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $endpoint); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + + if (curl_errno($ch)) { + $error_msg = curl_error($ch); + log_message('error', "[EMAIL ERROR] Curl failed: {$error_msg}"); + return ['status' => 'failed', 'code' => 500, 'message' => 'Curl error', 'error' => $error_msg]; + } + + curl_close($ch); + + $resp = json_decode($response, true); + + if ($httpCode === 200 && isset($resp['request_id'])) { + log_message('debug', 'Email Success to agent plan_id = ' .$plan_id.'email = ' . $value['email']); + } else { + log_message('error', "[EMAIL FAILED] plan_id = {$plan_id}, email = {$value['email']}, HTTP: {$httpCode}, Response: {$response}"); + } + + + + + // $email = \Config\Services::email(); + // $email->initialize([ + // 'protocol' => 'smtp', + // 'SMTPHost' => $orgData['mail_host'], + // 'SMTPUser' => $orgData['mail_user_name'], + // 'SMTPPass' => $orgData['mail_password'], + // 'SMTPPort' => (int)$orgData['mail_port'], + // 'mailType' => 'html' + // ]); + + // //trigger_email_to agent + // $email->setFrom($orgData['sender_email'], $orgData['name']); + // $email->setTo($value['email']); + // $email->setSubject($subject); + // $email->setMessage($html); + + // if(!empty($planData)){ + // $email->attach($planData['pdf_file_path']); + // } + + // if ($email->send()) { + + // log_message('debug', 'Email Success to agent plan_id = ' .$plan_id.'email = ' . $value['email']); + + // } else { + // log_message('debug', 'Email sending failed: agent plan_id = ' .$plan_id.'email = ' . $value['email'].'error = '.$email->printDebugger(['headers'])); + + // } } } diff --git a/app/Helpers/status_helper.php b/app/Helpers/status_helper.php index d265e9d..a72823f 100644 --- a/app/Helpers/status_helper.php +++ b/app/Helpers/status_helper.php @@ -53,6 +53,7 @@ if (!function_exists('palnStatusHandler')) { $a1Id = $userData['first_approver']; $a2Id = $userData['second_approver']; $a3Id = $userData['third_approver']; + $a4Id = $userData['fourth_approver']; $groupData = $groupModel->where('group_id', $groupId)->first(); if (!$groupData) { @@ -110,25 +111,29 @@ if (!function_exists('palnStatusHandler')) { log_message('error', "Policy service details not found for service_id: {$topPriorityService['service_id']}, policy_id: {$policyId}"); return false; } - + // dd($policyServiceDetails); $isExceptional = $planData['exceptional_plan_reason'] !== null && $planData['exceptional_plan_reason'] !== ''; + // dd($isExceptional); if ($isExceptional) { $policyA1Action = $policyServiceDetails['a1_exceptional_action']; $policyA2Action = $policyServiceDetails['a2_exceptional_action']; $policyA3Action = $policyServiceDetails['a3_exceptional_action']; + $policyA4Action = $policyServiceDetails['a4_exceptional_action']; $policyParallelAction = $policyServiceDetails['exceptional_parallel_process_from']; } else if ($is_data_edited) { $policyA1Action = $policyServiceDetails['a1_amendment_action']; $policyA2Action = $policyServiceDetails['a2_amendment_action']; $policyA3Action = $policyServiceDetails['a3_amendment_action']; + $policyA4Action = $policyServiceDetails['a4_amendment_action']; $policyParallelAction = $policyServiceDetails['amendment_parallel_process_from']; } else { $policyA1Action = $policyServiceDetails['a1_action']; $policyA2Action = $policyServiceDetails['a2_action']; $policyA3Action = $policyServiceDetails['a3_action']; + $policyA4Action = 'None'; $policyParallelAction = $policyServiceDetails['parallel_process_from']; } @@ -145,12 +150,18 @@ if (!function_exists('palnStatusHandler')) { 'a3_id' => $a3Id, 'a3_action' => $policyA3Action, 'is_a3_action_done' => ($policyA3Action == 'None') ? 1 : 0, + 'a4_id' => $a4Id, + 'a4_action' => $policyA4Action, + 'is_a4_action_done' => ($policyA4Action == 'None') ? 1 : 0, 'parallel_process_from' => $policyParallelAction ]; + // dd($data); + if ($is_data_edited == false) { log_message('info', "Creating new plan status for plan_id: {$plan_id}"); $planStatusModel->insert($data); + echo $planStatusModel->db->getLastQuery(); } else { $oldStatusData = $planStatusModel->where('plan_id', $plan_id)->where('is_active', 1)->first(); if ($oldStatusData) { @@ -345,17 +356,25 @@ if (!function_exists('updatePlanStatus')) { $a3ApproveCount = count($a3); } + $a4 = $planStatusModel->where('plan_id',$plan_id)->where('a4_action','Approval')->where('is_active',1)->findAll(); + $a4ApproveSum = 0; + $a4ApproveCount = 0; + if(count($a4)) + { + $a4ApproveSum = array_sum(array_column($a4, 'is_a4_action_done')); + $a4ApproveCount = count($a4); + } + + + $count = ( $a1ApproveCount + $a2ApproveCount + $a3ApproveCount + $a4ApproveCount); + $sum = ( $a1ApproveSum + $a2ApproveSum + $a3ApproveSum + $a4ApproveSum); - $count = ( $a1ApproveCount + $a2ApproveCount + $a3ApproveCount); - $sum = ( $a1ApproveSum + $a2ApproveSum + $a3ApproveSum); - if($count == $sum) { // Approved $planModel->set(['status'=>3])->where('plan_id',$plan_id)->update(); - //send main to agent - send_email_agent(env('ORG_id') , $plan_id); + }else if($count != $sum && $sum > 0) { //Partially Approved @@ -466,6 +485,34 @@ if (!function_exists('getCurrentPlanStatus')) { } } + $a4 = $planStatusModel->where('plan_id',$plan_id)->where('a4_action','Approval')->where('is_active',1)->findAll(); + if(count($a4)) + { + $user4 = $userModel->where('user_id', $a4[0]['a4_action_done_by'])->first(); + if(!$user4){ + $user4 = $userModel->where('user_id', $a4[0]['a4_id'])->first(); + } + $hasRejectReason = !empty(array_filter($a4, fn($row) => !empty($row['a4_reject_reason']))); + if($user4) + { + $userId = $user4['user_id']; + + $a4ApproveSum = array_sum(array_column($a4, 'is_a4_action_done')); + $a4ApproveCount = count($a4); + + $a4Status['a4_id'] = $userId; + if($a4ApproveSum == $a4ApproveCount) + { + $a4Status['a4_status'] = 'Plan approved by '.$user4['first_name'].' '.$user4['last_name']; + }else if($hasRejectReason){ + $a4Status['a4_status'] = 'Plan rejected by '.$user4['first_name'].' '.$user4['last_name'].', Reason-'.$a4[0]['a4_reject_reason']; + }else{ + $a4Status['a4_status'] = 'Plan approval pending from '.$user4['first_name'].' '.$user4['last_name']; + } + array_push($currentStatus,$a4Status); + } + } + return $currentStatus; @@ -473,6 +520,7 @@ if (!function_exists('getCurrentPlanStatus')) { } if (!function_exists('getPlanApproverAction')) { + // initially written code without parallel , sequential // function getPlanApproverAction($plan_id , ) // { @@ -578,33 +626,129 @@ if (!function_exists('getPlanApproverAction')) { // } + // 3 level of parallel , sequential + // function getPlanApproverAction($plan_id) + // { + // $planStatusModel = new PlanStatusModel(); + // $userModel = new UserModel(); + // $result = ['approver_data' => []]; + // $serviceIds = []; + + // // A1, A2, A3 - handle all same way + // $approverAction = [ + // ['key' => 'a1', 'approver' => 1], + // ['key' => 'a2', 'approver' => 2], + // ['key' => 'a3', 'approver' => 3], + // ]; + + // foreach ($approverAction as $stage) { + // $field = $stage['key']; + // $approverNumber = $stage['approver']; + // $actionField = "{$field}_action"; + // $idField = "{$field}_id"; + // $doneField = "is_{$field}_action_done"; + + // $record = $planStatusModel->where('plan_id', $plan_id) + // ->whereIn($actionField, ['Approval', 'Notification', 'None']) + // ->where('is_active', 1) + // ->first(); + + // if ($record) { + // $user = $userModel->where('user_id', $record[$idField])->first(); + // if ($user) { + // $result['approver_data'][] = [ + // 'approver' => $approverNumber, + // 'user_id' => $record[$idField], + // 'email' => $user['email'], + // 'action' => $record[$actionField], + // 'is_action_done' => $record[$doneField], + // 'where_key' => $idField, + // 'action_key' => $actionField, + // 'action_done_key' => $doneField, + // ]; + // } + // } + // } + + // // Get parallel process value + // $statusData = $planStatusModel->where('plan_id', $plan_id)->where('is_active', 1)->first(); + // $result['parallel_process_from'] = $statusData['parallel_process_from'] ?? null; + + // $parallelFrom = (int) $result['parallel_process_from']; + + // foreach ($result['approver_data'] as $key => &$approver) { + // $approver['status'] = 'pending'; // default + + // if ($parallelFrom === 1) { + // // All parallel + // $approver['status'] = 'active'; + // } elseif ($parallelFrom === 2) { + // if ($approver['approver'] === 1) { + // $approver['status'] = 'active'; + // } elseif (in_array($approver['approver'], [2, 3])) { + // // Check if approver 1 is done + // $a1Done = false; + // foreach ($result['approver_data'] as $a) { + // if ($a['approver'] === 1 && $a['is_action_done']) { + // $a1Done = true; + // break; + // } + // } + // $approver['status'] = $a1Done ? 'active' : 'waiting'; + // } + // } elseif ($parallelFrom === 3) { + // // Sequential: 1 -> 2 -> 3 + // $a1Done = false; + // $a2Done = false; + + // foreach ($result['approver_data'] as $a) { + // if ($a['approver'] === 1 && $a['is_action_done']) $a1Done = true; + // if ($a['approver'] === 2 && $a['is_action_done']) $a2Done = true; + // } + + // if ($approver['approver'] === 1) { + // $approver['status'] = 'active'; + // } elseif ($approver['approver'] === 2) { + // $approver['status'] = $a1Done ? 'active' : 'waiting'; + // } elseif ($approver['approver'] === 3) { + // $approver['status'] = ($a1Done && $a2Done) ? 'active' : 'waiting'; + // } + // } + // } + // unset($approver); // best practice when using & reference in foreach + + + // return $result; + // } + + + // latest 4 level of parallel , sequential function getPlanApproverAction($plan_id) { $planStatusModel = new PlanStatusModel(); $userModel = new UserModel(); $result = ['approver_data' => []]; - $serviceIds = []; - - // A1, A2, A3 - handle all same way + $approverAction = [ ['key' => 'a1', 'approver' => 1], ['key' => 'a2', 'approver' => 2], ['key' => 'a3', 'approver' => 3], + ['key' => 'a4', 'approver' => 4], ]; - + foreach ($approverAction as $stage) { $field = $stage['key']; $approverNumber = $stage['approver']; $actionField = "{$field}_action"; $idField = "{$field}_id"; $doneField = "is_{$field}_action_done"; - + $record = $planStatusModel->where('plan_id', $plan_id) - ->whereIn($actionField, ['Approval', 'Notification', 'None']) - ->where('is_active', 1) - ->first(); - + ->whereIn($actionField, ['Approval', 'Notification', 'None']) + ->where('is_active', 1) + ->first(); + if ($record) { $user = $userModel->where('user_id', $record[$idField])->first(); if ($user) { @@ -621,58 +765,64 @@ if (!function_exists('getPlanApproverAction')) { } } } - - // Get parallel process value + $statusData = $planStatusModel->where('plan_id', $plan_id)->where('is_active', 1)->first(); $result['parallel_process_from'] = $statusData['parallel_process_from'] ?? null; - $parallelFrom = (int) $result['parallel_process_from']; - foreach ($result['approver_data'] as $key => &$approver) { + foreach ($result['approver_data'] as &$approver) { $approver['status'] = 'pending'; // default + // Flags + $a1Done = $a2Done = $a3Done = false; + foreach ($result['approver_data'] as $a) { + if ($a['approver'] === 1 && $a['is_action_done']) $a1Done = true; + if ($a['approver'] === 2 && $a['is_action_done']) $a2Done = true; + if ($a['approver'] === 3 && $a['is_action_done']) $a3Done = true; + } + if ($parallelFrom === 1) { - // All parallel + // All approvers active $approver['status'] = 'active'; + } elseif ($parallelFrom === 2) { if ($approver['approver'] === 1) { $approver['status'] = 'active'; - } elseif (in_array($approver['approver'], [2, 3])) { - // Check if approver 1 is done - $a1Done = false; - foreach ($result['approver_data'] as $a) { - if ($a['approver'] === 1 && $a['is_action_done']) { - $a1Done = true; - break; - } - } + } elseif (in_array($approver['approver'], [2, 3, 4])) { $approver['status'] = $a1Done ? 'active' : 'waiting'; } - } elseif ($parallelFrom === 3) { - // Sequential: 1 -> 2 -> 3 - $a1Done = false; - $a2Done = false; - foreach ($result['approver_data'] as $a) { - if ($a['approver'] === 1 && $a['is_action_done']) $a1Done = true; - if ($a['approver'] === 2 && $a['is_action_done']) $a2Done = true; + } elseif ($parallelFrom === 3) { + if ($approver['approver'] === 1) { + $approver['status'] = 'active'; + } elseif ($approver['approver'] === 2) { + $approver['status'] = $a1Done ? 'active' : 'waiting'; + } elseif (in_array($approver['approver'], [3, 4])) { + $approver['status'] = ($a1Done && $a2Done) ? 'active' : 'waiting'; } + } elseif ($parallelFrom === 4) { if ($approver['approver'] === 1) { $approver['status'] = 'active'; } elseif ($approver['approver'] === 2) { $approver['status'] = $a1Done ? 'active' : 'waiting'; } elseif ($approver['approver'] === 3) { $approver['status'] = ($a1Done && $a2Done) ? 'active' : 'waiting'; + } elseif ($approver['approver'] === 4) { + $approver['status'] = ($a1Done && $a2Done && $a3Done) ? 'active' : 'waiting'; } + } else { + $approver['status'] = 'pending'; // fallback } } - unset($approver); // best practice when using & reference in foreach + unset($approver); // clean reference - return $result; } + + + } @@ -735,6 +885,23 @@ if (!function_exists('getApproverCurrentAction')) { } } + $a4 = $planStatusModel->where('plan_id',$plan_id)->where('a4_id',$user_id)->where('a4_action','Approval')->where('is_active',1)->findAll(); + if(count($a4)) + { + $hasRejectReason = !empty(array_filter($a4, fn($row) => !empty($row['a4_reject_reason']))); + $a4ApproveSum = array_sum(array_column($a4, 'is_a4_action_done')); + $a4ApproveCount = count($a4); + + if($a4ApproveSum == $a4ApproveCount) + { + return 'Approved'; + }else if($hasRejectReason){ + return 'Rejected'; + }else{ + return 'Approval pending'; + } + } + } } diff --git a/app/Models/PlanModel.php b/app/Models/PlanModel.php index 90fe2fb..18ea1a4 100644 --- a/app/Models/PlanModel.php +++ b/app/Models/PlanModel.php @@ -46,7 +46,8 @@ class PlanModel extends Model IB.dropdown_value as is_billable_value, POT.dropdown_value as purpose_of_travel_value, FD.dropdown_value as functional_department_value, - Dep.name as cost_center_value' + Dep.name as cost_center_value, + Forex.forex_id' ) ->join('m_users U', 'U.user_id = m_plan.user_id ', 'left') ->join('m_users C', 'C.user_id = m_plan.created_by ', 'left') @@ -57,6 +58,7 @@ class PlanModel extends Model ->join('m_dropdown POT', 'POT.dropdown_key = m_plan.purpose_of_travel AND POT.dropdown = "plan_purpose_of_travel"', 'left') ->join('m_dropdown FD', 'FD.dropdown_key = m_plan.functional_department AND FD.dropdown = "plan_functional_department"', 'left') ->join('m_department Dep', 'Dep.department_id = m_plan.cost_center_id ', 'left') + ->join('c_forex Forex', 'Forex.plan_id = m_plan.plan_id ', 'left') ->where('m_plan.is_active', 1)->where('m_plan.org_id', $org_id); if($getBy == 'ALL' || $getBy == null) diff --git a/app/Models/PlanStatusModel.php b/app/Models/PlanStatusModel.php index f168ded..5233fb3 100644 --- a/app/Models/PlanStatusModel.php +++ b/app/Models/PlanStatusModel.php @@ -15,6 +15,7 @@ class PlanStatusModel extends Model 'a1_id', 'a1_action', 'is_a1_action_done', 'a1_reject_reason', 'a1_action_done_on','a1_action_done_by', 'a2_id', 'a2_action', 'is_a2_action_done', 'a2_reject_reason', 'a2_action_done_on','a2_action_done_by', 'a3_id', 'a3_action', 'is_a3_action_done', 'a3_reject_reason', 'a3_action_done_on','a3_action_done_by', + 'a4_id', 'a4_action', 'is_a4_action_done', 'a4_reject_reason', 'a4_action_done_on','a4_action_done_by', 'parallel_process_from', 'is_active', 'created_on', 'created_by' diff --git a/app/Models/PolicyDetailsModel.php b/app/Models/PolicyDetailsModel.php index 4652c2a..d0b855a 100644 --- a/app/Models/PolicyDetailsModel.php +++ b/app/Models/PolicyDetailsModel.php @@ -29,6 +29,7 @@ class PolicyDetailsModel extends Model 'a1_amendment_action', 'a2_amendment_action', 'a3_amendment_action', + 'a4_amendment_action', 'amendment_parallel_process_from', 'is_active', 'created_on', diff --git a/app/Models/UserModel.php b/app/Models/UserModel.php index 3c7ed00..5a617fa 100644 --- a/app/Models/UserModel.php +++ b/app/Models/UserModel.php @@ -10,7 +10,7 @@ class UserModel extends Model protected $primaryKey = 'user_id'; // Primary key // Fields that can be mass assigned - protected $allowedFields = ['first_name','last_name','password','email','mobile_no','alternate_mobile_no','date_of_birth','address','gender','postal_code','country_code','employee_code','role_id','department_id','group_id','first_approver','first_approver_email','second_approver','second_approver_email','third_approver','third_approver_email','exceptional_approver','exceptional_approver_email','user_type','passport_number','place_of_issue','passport_document','passport_firstname','passport_middlename','passport_lastname','nationality','date_of_issue','date_of_expiry','created_on','created_by','updated_on','updated_by','is_active','org_id', 'temp_password', 'forex_pre_paid_card_number', 'emergency_contact_number', 'd_seat_preference', 'd_meal_preference', 'i_seat_preference', 'i_meal_preference', 'agent_supported_service_ids', 'd_additonalInfo', 'i_additonalInfo', 'forex_expiry_date', 'delegated_to_user_id', 'delegation_start_date', 'delegation_end_date','last_login_at','company_name']; + protected $allowedFields = ['first_name','last_name','password','email','mobile_no','alternate_mobile_no','date_of_birth','address','gender','postal_code','country_code','employee_code','role_id','department_id','group_id','first_approver','first_approver_email','second_approver','second_approver_email','third_approver','third_approver_email','fourth_approver','fourth_approver_email','user_type','passport_number','place_of_issue','passport_document','passport_firstname','passport_middlename','passport_lastname','nationality','date_of_issue','date_of_expiry','created_on','created_by','updated_on','updated_by','is_active','org_id', 'temp_password', 'forex_pre_paid_card_number', 'emergency_contact_number', 'd_seat_preference', 'd_meal_preference', 'i_seat_preference', 'i_meal_preference', 'agent_supported_service_ids', 'd_additonalInfo', 'i_additonalInfo', 'forex_expiry_date', 'delegated_to_user_id', 'delegation_start_date', 'delegation_end_date','last_login_at','company_name']; // Specify the return type of the results protected $returnType = 'array'; @@ -91,10 +91,9 @@ public function updateApprover(string $approverType, array $insertedIds) 'first' => ['column' => 'first_approver', 'email' => 'first_approver_email'], 'second' => ['column' => 'second_approver', 'email' => 'second_approver_email'], 'third' => ['column' => 'third_approver', 'email' => 'third_approver_email'], - 'exceptional' => ['column' => 'exceptional_approver', 'email' => 'exceptional_approver_email'] + 'fourth' => ['column' => 'fourth_approver', 'email' => 'fourth_approver_email'] ]; - $column = $validTypes[$approverType]['column']; $emailCol = $validTypes[$approverType]['email']; diff --git a/app/Views/pdf.php b/app/Views/pdf.php index d883991..006f386 100644 --- a/app/Views/pdf.php +++ b/app/Views/pdf.php @@ -174,6 +174,7 @@ +
    @@ -340,6 +341,43 @@
    +Trip Status:'; + $statusHtml .= ''; + + echo $statusHtml; +} ?> + + @@ -412,7 +450,6 @@
    Class
    -
    style="color: #960000;" >
    allowed for @@ -518,13 +555,6 @@
    Hotel Name

    - -
    Category
    -
    - style="color: #960000;" >
    - allowed for -
    -
    Checkin Date & Time
    @@ -533,6 +563,13 @@
    Checkout Date & Time
    + +
    Category
    +
    + style="color: #960000;" >
    + allowed for +
    +