db = db_connect(); $this->EndorsementModel = new EndorsementModel(); $this->PolicyModel = new PolicyModel(); $this->QuotationModel = new QuotationModel(); $this->EnquiryModel = new EnquiryModel(); $this->StaffModel = new StaffModel(); } public function EndorsementList() { try { $id = $this->request->getGet('id'); // endorsement id $manager_id = $this->request->getGet('manager_id'); $agent_id = $this->request->getGet('agent_id'); $policy_number = $this->request->getGet('policy_number'); $from_date = $this->request->getGet('from_date'); $to_date = $this->request->getGet('to_date'); $endorsement_type = $this->request->getGet('endorsement_type'); $insurer_id = $this->request->getGet('insurer_id'); $status = $this->request->getGet('status'); $verification = $this->request->getGet('verification'); $search = $this->request->getGet('search'); $builder = $this->EndorsementModel ->select('partner_endorsement_request.*, CASE WHEN partner_endorsement_request.policy_start_date = "0000-00-00" OR YEAR(partner_endorsement_request.policy_start_date) < 2000 THEN NULL ELSE DATE_FORMAT(partner_endorsement_request.policy_start_date, "%Y-%m-%d") END as policy_start_date, CASE WHEN partner_endorsement_request.policy_end_date = "0000-00-00" OR YEAR(partner_endorsement_request.policy_end_date) < 2000 THEN NULL ELSE DATE_FORMAT(partner_endorsement_request.policy_end_date, "%Y-%m-%d") END as policy_end_date, i.name as insurer_name, i.short_name as insurer_short_name, ib.branch_name as insurer_branch, c.client_name, c.phone as client_phone, c.email as client_email, partner_endorsement_request.agent_id, pa.agent_code as agent_code, pa.name as agent_name, pp.enquiry_id, etm.endorsement_type as endorsement_type_value, PB.name as broker_name, pm.value as payment_mode_value') ->join('insurers i', 'i.id = partner_endorsement_request.insurer_id', 'left') ->join('insurer_branch ib', 'ib.id = partner_endorsement_request.insurer_branch_id', 'left') ->join('clients c', 'c.id = partner_endorsement_request.client_id', 'left') ->join('partner_agent pa', 'pa.id = partner_endorsement_request.agent_id', 'left') ->join('partner_policy pp', 'pp.policy_number = partner_endorsement_request.policy_number', 'left') ->join('partner_enquiry pe', 'pe.id = pp.enquiry_id', 'left') ->join('partner_endorsement_type_master etm', 'etm.id = partner_endorsement_request.endorsement_type', 'left') ->join('partner_brokers PB', 'PB.id = partner_endorsement_request.broker_id', 'left') ->join('partner_payment_mode_master pm', 'pm.id = partner_endorsement_request.payment_mode_id', 'left') ->where('partner_endorsement_request.is_active', 1); // If ID is provided, fetch single record if (!empty($id)) { $builder->where('partner_endorsement_request.id', $id); $record = $builder->get()->getRowArray(); if (!$record) { return $this->respond(['status' => 'failed','code' => 404,'data' => 'Not Found'], 404); } return $this->respond(['status' => 'success','code' => 200,'data' => $record ], 200); } // Apply filters if (!empty($manager_id)) { $builder->where('partner_endorsement_request.manager_id', $manager_id); } if (!empty($agent_id)) { $builder->where('partner_endorsement_request.agent_id', $agent_id); } if (!empty($policy_number)) { $builder->where('partner_endorsement_request.policy_number', $policy_number); } if (!empty($from_date) && !empty($to_date)) { $builder->where('partner_endorsement_request.created_at >=', $from_date . ' 00:00:00') ->where('partner_endorsement_request.created_at <=', $to_date . ' 23:59:59'); } if (!empty($endorsement_type) && $endorsement_type != 'All') { $builder->where('partner_endorsement_request.endorsement_type', $endorsement_type); } if (!empty($insurer_id)) { $builder->where('partner_endorsement_request.insurer_id', $insurer_id); } if (!empty($status) && $status != 'All') { $builder->where('partner_endorsement_request.status', $status); } if (!empty($verification) && $verification != 'All') { if ($verification == 'Verified') { $builder->where('partner_endorsement_request.is_data_accuracy_checked', 1); } elseif ($verification == 'To Verify') { $builder->where('partner_endorsement_request.is_data_accuracy_checked', 0); } } $data = $builder->get()->getResultArray(); foreach ($data as $key => $row) { $data[$key]['created_at'] = date('d-m-Y h:i A', strtotime($row['created_at'])); $data[$key]['updated_at'] = date('d-m-Y h:i A', strtotime($row['updated_at'])); // ✅ NULL-safe date formatting $data[$key]['policy_start_date'] = (!empty($row['policy_start_date']) && $row['policy_start_date'] !== '0000-00-00') ? date('d-m-Y', strtotime($row['policy_start_date'])) : null; $data[$key]['policy_end_date'] = (!empty($row['policy_end_date']) && $row['policy_end_date'] !== '0000-00-00') ? date('d-m-Y', strtotime($row['policy_end_date'])) : null; } return $this->respond(['status' => 'success','code' => 200,'data' => $data], 200); } catch (\Exception $e) { return $this->respond(['status' => 'failed','code' => 500,'data' => $e->getMessage()], 500); } } public function createEndorsement() { try { $reqData = $this->request->getPost(); // Basic validation if (empty($reqData['policy_from']) || empty($reqData['policy_number']) || empty($reqData['endorsement_type']) ) { return $this->respond(['status' => 'failed','code' => 400,'data' => 'policy_from, policy_number, endorsement_type are required' ], 400); } $policy = null; // INTERNAL POLICY FLOW if ($reqData['policy_from'] === 'Internal') { $policy = $this->PolicyModel ->select('partner_policy.*, Q.insurer_id, Q.insurer_branch_id, Q.payment_mode_id, E.name as insured_name, E.mobile as client_mobile, E.email as client_email, E.reg_no, E.broker_id') ->join('partner_quotation Q', 'Q.id = partner_policy.quotation_id AND Q.status = "Accepted"', 'left') ->join('partner_enquiry E', 'E.id = partner_policy.enquiry_id', 'left') ->where('partner_policy.policy_number', $reqData['policy_number']) ->first(); if (empty($policy)) { return $this->respond(['status' => 'failed','code' => 404,'data' => 'Internal policy not found'], 404); } } //FILE UPLOAD $uploadedFileName = endorsement_upload_original($this->request->getFile('endorsement_file_name')); // PREPARE DATA if ($reqData['policy_from'] === 'Internal') { // Take values from DB $endorsementData = [ 'policy_from' => 'Internal', 'policy_number' => $policy['policy_number'], 'client_policy_id' => $policy['client_policy_id'] ?? null, 'insurer_id' => $policy['insurer_id'] ?? null, 'insurer_branch_id' => $policy['insurer_branch_id'] ?? null, 'policy_start_date' => $policy['start_date'] ?? null, 'policy_end_date' => $policy['end_date'] ?? null, 'reg_no' => $policy['reg_no'] ?? null, 'broker_id' => $policy['broker_id'] ?? null, 'insured_name' => $policy['insured_name'] ?? null, 'payment_mode_id' => $reqData['payment_mode_id'] ?? $policy['payment_mode_id'] ?? null, ]; } else { // use values from Request $endorsementData = [ 'policy_from' => 'External', 'policy_number' => $reqData['policy_number'], 'insurer_id' => $reqData['insurer_id'] ?? null, 'insurer_branch_id' => $reqData['insurer_branch_id'] ?? null, 'policy_start_date' => format_date_for_database($reqData['policy_start_date'] ?? null), 'policy_end_date' => format_date_for_database($reqData['policy_end_date'] ?? null), 'reg_no' => $reqData['reg_no'] ?? null, 'broker_id' => $reqData['broker_id'] ?? null, 'insured_name' => $reqData['insured_name'] ?? null, 'payment_mode_id' => $reqData['payment_mode_id'] ?? null, ]; } // Common fields $endorsementData += [ 'manager_id' => $reqData['manager_id'] ?? null, 'agent_id' => $reqData['agent_id'] ?? null, 'endorsement_type' => $reqData['endorsement_type'], 'endorsement_description' => $reqData['endorsement_description'], 'endorsement_no' => $reqData['endorsement_no'] ?? null, 'contact_person' => $reqData['contact_person'] ?? null, 'pending_days' => $reqData['pending_days'] ?? null, 'financia_or_non_financial' => $reqData['financia_or_non_financial'] ?? null, 'endorsement_premium' => $reqData['endorsement_premium'] ?? null, 'commission_amount' => $reqData['commission_amount'] ?? null, 'created_by' => $reqData['created_by'] ?? null, 'status' => 'Open', 'endorsement_file_name' => $uploadedFileName, 'is_active' => 1 ]; if (!$this->EndorsementModel->insert($endorsementData)) { return $this->respond(['status' => 'failed','code' => 422, 'data' => $this->EndorsementModel->errors() ], 422); } return $this->respond(['status' => 'success','code' => 200,'data' => ['endorsement_id' => $this->EndorsementModel->getInsertID()]], 200); } catch (\Exception $e) { return $this->respond(['status' => 'failed','code' => 500,'data' => $e->getMessage()], 500); } } public function updateEndorsement() { try { $endorsementId = $this->request->getPost('id'); if (!$endorsementId) { return $this->respond(['status' => 'failed', 'code' => 400, 'data' => 'id is required'], 400);} $reqData = $this->request->getPost(); // Fetch existing record $endorsement = $this->EndorsementModel->find((int)$endorsementId); if (!$endorsement) { return $this->respond([ 'status' => 'failed', 'code' => 404,'data' => 'Endorsement not found' ], 404); } // FILE UPLOAD $uploadedOriginalCompletionFile = endorsement_upload_original($this->request->getFile('endorsement_file_name')) ?? $endorsement['endorsement_file_name']; // FILE REVISED UPLOAD $uploadedRevisedCompletionFile = endorsement_upload_completion($this->request->getFile('endorsement_completion_file')) ?? $endorsement['endorsement_completion_file']; /* * COMMON UPDATE FIELDS * Keep update mapping explicit so fields sent by frontend are not silently ignored. */ $updateData = []; // Update only if provided (avoid null overwrite) if (isset($reqData['policy_from'])) { $updateData['policy_from'] = $reqData['policy_from']; } if (isset($reqData['policy_number'])) { $updateData['policy_number'] = $reqData['policy_number']; } if (isset($reqData['manager_id'])) { $updateData['manager_id'] = $reqData['manager_id']; } if (isset($reqData['agent_id'])) { $updateData['agent_id'] = $reqData['agent_id']; } if (isset($reqData['endorsement_type'])) { $updateData['endorsement_type'] = $reqData['endorsement_type']; } if (isset($reqData['endorsement_description'])) { $updateData['endorsement_description'] = $reqData['endorsement_description']; } if (isset($reqData['endorsement_no'])) { $updateData['endorsement_no'] = $reqData['endorsement_no']; } if (isset($reqData['status'])) { $updateData['status'] = $reqData['status']; } if (isset($reqData['contact_person'])) { $updateData['contact_person'] = $reqData['contact_person']; } if (isset($reqData['financia_or_non_financial'])) { $updateData['financia_or_non_financial'] = $reqData['financia_or_non_financial']; } if (isset($reqData['endorsement_premium'])) { $updateData['endorsement_premium'] = $reqData['endorsement_premium']; } if (isset($reqData['commission_amount'])) { $updateData['commission_amount'] = $reqData['commission_amount']; } if (isset($reqData['pending_days'])) { $updateData['pending_days'] = $reqData['pending_days']; } // Always update both files (new or existing) $updateData['endorsement_file_name'] = $uploadedOriginalCompletionFile; $updateData['endorsement_completion_file'] = $uploadedRevisedCompletionFile; // ✅ fixed variable /* * External Policy Editable Fields * Use incoming policy_from first (if provided), fallback to stored value. * This prevents missing updates when stored value casing differs (external/External). */ $effectivePolicyFrom = $reqData['policy_from'] ?? $endorsement['policy_from'] ?? ''; if (strcasecmp(trim((string)$effectivePolicyFrom), 'External') === 0) { if (isset($reqData['insurer_id'])) { $updateData['insurer_id'] = $reqData['insurer_id'] ?? null; } if (isset($reqData['insurer_branch_id'])) { $updateData['insurer_branch_id'] = $reqData['insurer_branch_id'] ?? null; } if (isset($reqData['policy_start_date'])) { $updateData['policy_start_date'] = format_date_for_database($reqData['policy_start_date'] ?? null); } if (isset($reqData['policy_end_date'])) { $updateData['policy_end_date'] = format_date_for_database($reqData['policy_end_date'] ?? null); } if (isset($reqData['insured_name'])) { $updateData['insured_name'] = $reqData['insured_name'] ?? null; } if (isset($reqData['reg_no'])) { $updateData['reg_no'] = $reqData['reg_no'] ?? null; } if (isset($reqData['broker_id'])) { $updateData['broker_id'] = $reqData['broker_id'] ?? null; } if (isset($reqData['payment_mode_id'])) { $updateData['payment_mode_id'] = $reqData['payment_mode_id']; } } $updateData['updated_by'] = $reqData['updated_by'] ?? null; if (!empty($updateData['updated_by'])) { $staff = $this->StaffModel ->select('role_id') ->where('id', $updateData['updated_by']) ->first(); if (!empty($staff) && $staff['role_id'] == 4) { $updateData['is_data_accuracy_checked'] = 1; $updateData['status'] = "Closed" ; } } /** * =========================== * UPDATE * =========================== */ if (!$this->EndorsementModel->update($endorsementId, $updateData)) { return $this->respond([ 'status' => 'failed', 'code' => 422, 'data' => $this->EndorsementModel->errors() ], 422); } return $this->respond([ 'status' => 'success', 'code' => 200, 'data' => [ 'endorsement_id' => $endorsementId, 'message' => 'Endorsement updated successfully' ] ], 200); } catch (\Exception $e) { return $this->respond([ 'status' => 'failed', 'code' => 500, 'data' => $e->getMessage() ], 500); } } public function deleteEndorsement() { try { $id = $this->request->getGet('id'); // check if EndorsementModel exists $file = $this->EndorsementModel->find((int)$id); if (!$file) { return $this->respond(['status' => 'failed','code' => 200, 'data' => 'Endorsement not found'], 200); } // update status $this->EndorsementModel->update($id, ['is_active' => 0]); return $this->respond([ 'status' => 'success', 'code' => 200,'data' => "Endorsement Deleted"], 200); } catch (\Exception $e) { return $this->respond(['status' => 'failed','code' => 500,'data' => $e->getMessage()], 500); } } // public function createEndorsement() // { // try { // $reqData = $this->request->getPost(); // // Validate required fields // if (empty($reqData['policy_number']) || empty($reqData['endorsement_type']) || empty($reqData['endorsement_description'])) { // return $this->respond(['status' => 'failed','code' => 400,'data' => 'policy_number, endorsement_type and endorsement_description are required' ], 200); // } // // Fetch policy details // $policy = $this->PolicyModel->select('partner_policy.*, Q.insurer_id, Q.insurer_branch_id, E.name as client_name, E.mobile as client_mobile, E.email as client_email, E.reg_no, E.broker_id') // ->join('partner_quotation Q', 'Q.id = partner_policy.quotation_id AND Q.status = "Accepted"', 'left') // ->join('partner_enquiry E', 'E.id = partner_policy.enquiry_id', 'left') // ->where('partner_policy.policy_number', $reqData['policy_number']) // ->first(); // if (empty($policy) && $reqData['policy_from'] == 'Internal') { // return $this->respond(['status' => 'failed','code' => 404,'data' => 'Policy not found'], 200); // } // $uploadFile = $this->request->getFile('endorsement_file_name'); // $uploadedFileName = null; // if ($uploadFile && $uploadFile->isValid()) { // $uploadPath = WRITEPATH . 'uploads/endorsement/'; // if (!is_dir($uploadPath)) { // mkdir($uploadPath, 0777, true); // } // $uploadedFileName = time() . '_' . $uploadFile->getRandomName(); // $uploadFile->move($uploadPath, $uploadedFileName); // } // // Prepare endorsement data // $endorsementData = [ // 'policy_from' => $reqData['policy_from'], // 'policy_number' => $policy['policy_number'] ?? $reqData['policy_number'], // 'client_policy_id' => $policy['client_policy_id'] ?? null, // 'insurer_id' => $policy['insurer_id'] ?? null, // 'insurer_branch_id' => $policy['insurer_branch_id'] ?? null, // 'client_id' => $policy['client_id'] ?? null, // 'agent_id' => $policy['agent_id'] ?? null, // 'policy_start_date' => $policy['start_date'] ?? null, // 'policy_end_date' => $policy['end_date'] ?? null, // 'reg_no' => $policy['reg_no'] ?? null, // 'broker_id' => $policy['broker_id'] ?? null, // 'insured_name' => $policy['insured_name'] ?? null, // 'commission_amount' => $reqData['agent_id'] ?? null, // 'manager_id' => $reqData['manager_id'] ?? null, // 'endorsement_type' => $reqData['endorsement_type'], // 'endorsement_description'=> $reqData['endorsement_description'], // 'endorsement_no' => $reqData['endorsement_no'] ?? null, // 'created_by' => $reqData['created_by'] ?? null, // 'status' => 'Open', // 'endorsement_file_name' => $uploadedFileName, // 'is_active' => 1 // ]; // if (!$this->EndorsementModel->insert($endorsementData)) { // return $this->respond([ 'status' => 'failed', 'code' => 422, 'data' => $this->EndorsementModel->errors()], 422); // } // return $this->respond([ 'status' => 'success', 'code' => 200, 'data' => ['endorsement_id' => $this->EndorsementModel->getInsertID()] ], 200); // } catch (\Exception $e) { // return $this->respond([ 'status' => 'failed', 'code' => 500, 'data' => $e->getMessage() ], 500); // } // } // public function updateEndorsement() // { // try { // $endorsementId = $this->request->getPost('id'); // if (!$endorsementId) { // return $this->respond([ 'status' => 'failed', 'code' => 400, 'data' => 'endorsementId is required' ], 200); // } // $reqData = $this->request->getPost(); // // Fetch existing record // $endorsement = $this->EndorsementModel->find((int)$endorsementId); // if (empty($endorsement)) { // return $this->respond([ 'status' => 'failed', 'code' => 404, 'data' => 'Endorsement not found' ], 200); // } // // Handle upload (endorsement completion file) // $uploadFile = $this->request->getFile('endorsement_completion_file'); // $uploadedCompletionFile = $endorsement['endorsement_completion_file']; // keep old if not replaced // if ($uploadFile && $uploadFile->isValid()) { // $uploadPath = WRITEPATH . 'uploads/endorsement/'; // if (!is_dir($uploadPath)) { // mkdir($uploadPath, 0777, true); // } // $uploadedCompletionFile = time() . '_' . $uploadFile->getRandomName(); // $uploadFile->move($uploadPath, $uploadedCompletionFile); // } // // Prepare data to update // $updateData = [ // 'endorsement_type' => $reqData['endorsement_type'] ?? $endorsement['endorsement_type'], // 'endorsement_description' => $reqData['endorsement_description'] ?? $endorsement['endorsement_description'], // 'endorsement_no' => $reqData['endorsement_no'] ?? $endorsement['endorsement_no'], // 'status' => $reqData['status'] , // 'endorsement_completion_file' => $uploadedCompletionFile, // 'contact_person' => $reqData['contact_person'] , // 'financia_or_non_financial' => $reqData['financia_or_non_financial'] , // 'endorsement_premium' => $reqData['endorsement_premium'] , // 'pending_days' => $reqData['pending_days'] , // 'updated_by' => $reqData['updated_by'] ?? null, // ]; // if (!$this->EndorsementModel->update($endorsementId, $updateData)) { // return $this->respond([ // 'status' => 'failed', // 'code' => 422, // 'data' => $this->EndorsementModel->errors() // ], 422); // } // return $this->respond([ // 'status' => 'success', // 'code' => 200, // 'data' => ['endorsement_id' => $endorsementId, 'message' => 'Endorsement updated successfully'] // ], 200); // } catch (\Exception $e) { // return $this->respond([ // 'status' => 'failed', // 'code' => 500, // 'data' => $e->getMessage() // ], 500); // } // } public function downloadEndorsementCompletionFile() { try { $id = $this->request->getGet('id'); $type = $this->request->getGet('type'); // 'completion' or 'original' $fileType = (!$type || $type === 'original') ? 'original' : $type; $storageDriver = config('Storage')->driver ?? 'local'; $storageBucket = config('Storage')->s3Bucket ?? ''; $s3LogCtx = [ 'endorsement_id' => (int) $id, 'driver' => $storageDriver, 'bucket' => $storageBucket, 'action' => 'download', 'request_type' => $type, 'file_type' => $fileType, ]; log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][START] downloadEndorsementCompletionFile started | ' . json_encode($s3LogCtx, JSON_UNESCAPED_SLASHES)); if (!$id) { log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][FAILED] endorsement id missing | ' . json_encode($s3LogCtx, JSON_UNESCAPED_SLASHES)); return $this->respond(['status' => 'failed', 'code' => 400, 'data' => 'ID is required'], 200); } // Fetch record from DB $fileRecord = $this->EndorsementModel->find((int)$id); log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][RESOLVE] endorsement record resolved | ' . json_encode(array_merge($s3LogCtx, [ 'record_found' => $fileRecord !== null, ]), JSON_UNESCAPED_SLASHES)); if (!$fileRecord) { log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][FAILED] endorsement record not found in DB | ' . json_encode($s3LogCtx, JSON_UNESCAPED_SLASHES)); return $this->respond(['status' => 'failed', 'code' => 404, 'data' => 'File not found'], 200); } // $filePath = WRITEPATH . 'uploads/endorsement/' . $fileRecord['endorsement_file_name']; // ✅ If type is null/empty → original (default) // ✅ If type = 'completion' → endorsement_pdf/ subfolder if (!$type || $type === 'original') { $fileName = $fileRecord['endorsement_file_name'] ?? null; $subPath = ''; } else if ($type === 'completion') { $fileName = $fileRecord['endorsement_completion_file'] ?? null; $subPath = 'endorsement_pdf/'; } else { $fileName = null; $subPath = ''; } log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][RESOLVE] endorsement file name resolved | ' . json_encode(array_merge($s3LogCtx, [ 'file_name' => $fileName, 'sub_folder' => endorsement_subfolder_for_type($fileType), 'original_file_name' => $fileRecord['endorsement_file_name'] ?? null, 'completion_file_name' => $fileRecord['endorsement_completion_file'] ?? null, ]), JSON_UNESCAPED_SLASHES)); if (!$fileName) { log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][FAILED] no file uploaded yet for requested type | ' . json_encode($s3LogCtx, JSON_UNESCAPED_SLASHES)); return $this->respond(['status' => 'failed', 'code' => 404, 'data' => 'No file uploaded yet'], 200); } log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][EXISTS] checking endorsement file in storage | ' . json_encode(array_merge($s3LogCtx, [ 'module' => 'endorsement', 'sub_folder' => endorsement_subfolder_for_type($fileType), 'file_name' => $fileName, ]), JSON_UNESCAPED_SLASHES)); $exists = endorsement_exists_by_type($fileName, $fileType); log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][EXISTS] endorsement file exists check complete | ' . json_encode(array_merge($s3LogCtx, [ 'file_name' => $fileName, 'exists' => $exists, ]), JSON_UNESCAPED_SLASHES)); if (!$exists) { log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][FAILED] endorsement file missing in storage | ' . json_encode(array_merge($s3LogCtx, [ 'file_name' => $fileName, ]), JSON_UNESCAPED_SLASHES)); return $this->respond(['status' => 'failed', 'code' => 404, 'data' => 'File missing on server'], 200); } log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][DOWNLOAD] streaming endorsement file from storage | ' . json_encode(array_merge($s3LogCtx, [ 'file_name' => $fileName, 'inline' => false, 'sub_folder' => endorsement_subfolder_for_type($fileType), ]), JSON_UNESCAPED_SLASHES)); $response = endorsement_download_by_type($fileName, $fileType); log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][END] endorsement download response ready | ' . json_encode(array_merge($s3LogCtx, [ 'file_name' => $fileName, ]), JSON_UNESCAPED_SLASHES)); return $response; } catch (\Exception $e) { log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][FAILED] downloadEndorsementCompletionFile fatal error | ' . json_encode([ 'endorsement_id' => (int) ($this->request->getGet('id') ?? 0), 'error' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine(), ], JSON_UNESCAPED_SLASHES)); return $this->respond(['status' => 'failed', 'code' => 500, 'message' => $e->getMessage()], 500); } } public function EndorsementFilePathGOWTHAM() { try { $endorsementId = $this->request->getGet('endorsement_id'); if (!$endorsementId) { return $this->respond(['status' => 'failed','code' => 400,'data' => 'endorsement_id is required'], 200); } // Fetch record from DB $fileRecord = $this->EndorsementModel->where('is_active', 1)->find((int)$endorsementId); if (!$fileRecord || empty($fileRecord['endorsement_file_name'])) { return $this->respond([ 'status' => 'failed','code' => 404,'data' => 'File not found in database'], 200); } $filePath = WRITEPATH . "uploads/endorsement/" . $fileRecord['endorsement_file_name']; $publicUrl = base_url("uploads/endorsement/" . $fileRecord['endorsement_file_name']); if (!file_exists($filePath)) { return $this->respond(['status' => 'failed','code' => 404,'data' => 'File missing on server'], 200); } // return $this->respond(['status' => 'success', 'code' => 200, 'data' => $publicUrl ], 200); // Detect the file mime type $mime = mime_content_type($filePath); // Stream file to browser / Flutter return $this->response ->setHeader('Content-Type', $mime) ->setHeader('Content-Disposition', 'inline; filename="' . $fileRecord['endorsement_file_name'] . '"') ->setBody(file_get_contents($filePath)); } catch (\Exception $e) { return $this->respond(['status' => 'failed','code' => 500,'message' => $e->getMessage() ], 500); } } public function EndorsementFilePath() { try { $endorsementId = $this->request->getGet('endorsement_id'); $storageDriver = config('Storage')->driver ?? 'local'; $storageBucket = config('Storage')->s3Bucket ?? ''; $s3LogCtx = [ 'endorsement_id' => (int) $endorsementId, 'driver' => $storageDriver, 'bucket' => $storageBucket, 'action' => 'inline_view', ]; log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][START] EndorsementFilePath started | ' . json_encode($s3LogCtx, JSON_UNESCAPED_SLASHES)); if (!$endorsementId) { log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][FAILED] endorsement_id missing | ' . json_encode($s3LogCtx, JSON_UNESCAPED_SLASHES)); return $this->respond(['status' => 'failed', 'code' => 400, 'data' => 'endorsement_id is required'], 200); } // Fetch record from DB $fileRecord = $this->EndorsementModel->where('is_active', 1)->find((int)$endorsementId); log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][RESOLVE] endorsement record resolved | ' . json_encode(array_merge($s3LogCtx, [ 'record_found' => $fileRecord !== null, ]), JSON_UNESCAPED_SLASHES)); if (!$fileRecord) { log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][FAILED] endorsement record not found in DB | ' . json_encode($s3LogCtx, JSON_UNESCAPED_SLASHES)); return $this->respond(['status' => 'failed', 'code' => 404, 'data' => 'File not found in database'], 200); } // ✅ STEP 1: Check completion file first $completionFile = $fileRecord['endorsement_completion_file'] ?? null; $originalFile = $fileRecord['endorsement_file_name'] ?? null; if (!empty($completionFile)) { $fileName = $completionFile; $fileType = 'completion'; } elseif (!empty($originalFile)) { $fileName = $originalFile; $fileType = 'original'; } else { log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][FAILED] no original or completion file in DB | ' . json_encode(array_merge($s3LogCtx, [ 'original_file_name' => $originalFile, 'completion_file_name' => $completionFile, ]), JSON_UNESCAPED_SLASHES)); return $this->respond(['status' => 'failed', 'code' => 404, 'data' => 'No file uploaded yet'], 200); } $s3LogCtx['file_type'] = $fileType; $s3LogCtx['file_name'] = $fileName; log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][RESOLVE] endorsement file name resolved | ' . json_encode(array_merge($s3LogCtx, [ 'sub_folder' => endorsement_subfolder_for_type($fileType), 'original_file_name' => $originalFile, 'completion_file_name' => $completionFile, 'selected_source' => $fileType, ]), JSON_UNESCAPED_SLASHES)); log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][EXISTS] checking endorsement file in storage | ' . json_encode(array_merge($s3LogCtx, [ 'module' => 'endorsement', 'sub_folder' => endorsement_subfolder_for_type($fileType), ]), JSON_UNESCAPED_SLASHES)); $exists = endorsement_exists_by_type($fileName, $fileType); log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][EXISTS] endorsement file exists check complete | ' . json_encode(array_merge($s3LogCtx, [ 'exists' => $exists, ]), JSON_UNESCAPED_SLASHES)); if (!$exists) { log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][FAILED] endorsement file missing in storage | ' . json_encode($s3LogCtx, JSON_UNESCAPED_SLASHES)); return $this->respond(['status' => 'failed', 'code' => 404, 'data' => 'File missing on server'], 200); } log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][DOWNLOAD] streaming endorsement file inline from storage | ' . json_encode(array_merge($s3LogCtx, [ 'inline' => true, 'sub_folder' => endorsement_subfolder_for_type($fileType), ]), JSON_UNESCAPED_SLASHES)); $response = endorsement_download_by_type($fileName, $fileType, true); log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][END] endorsement inline view response ready | ' . json_encode($s3LogCtx, JSON_UNESCAPED_SLASHES)); return $response; } catch (\Exception $e) { log_message('error', '[S3_FILE_GET][ENDORSEMENT_READ][FAILED] EndorsementFilePath fatal error | ' . json_encode([ 'endorsement_id' => (int) ($this->request->getGet('endorsement_id') ?? 0), 'error' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine(), ], JSON_UNESCAPED_SLASHES)); return $this->respond(['status' => 'failed', 'code' => 500, 'message' => $e->getMessage()], 500); } } public function uploadEndorsementFile() { try { $data = $this->request->getPost(); // ✅ Validate required POST fields first if (empty($data['id']) || empty($data['updated_by'])) { return $this->respond(['status' => 'failed', 'code' => 400, 'data' => 'Missing required fields'], 400); } $allowedTypes = ['application/pdf']; $endorsementPdf = $this->request->getFile('endorsement_completion_file'); // ✅ Check file existence and validity BEFORE accessing its properties if (!$endorsementPdf || !$endorsementPdf->isValid()) { return $this->respond(['status' => 'failed', 'code' => 400, 'data' => 'No valid file received'], 400); } // ✅ MIME validation only after confirming file exists if (!in_array($endorsementPdf->getMimeType(), $allowedTypes)) { return $this->respond(['status' => 'failed', 'code' => 400, 'data' => 'Only PDF files are allowed'], 400); } // ✅ Fetch existing record to get old file name BEFORE uploading $existingRecord = $this->EndorsementModel->find($data['id']); $oldFileName = $existingRecord['endorsement_completion_file'] ?? null; $pdfFileName = endorsement_upload_completion($endorsementPdf); if (!$pdfFileName || !endorsement_exists_by_type($pdfFileName, 'completion')) { return $this->respond(['status' => 'failed', 'code' => 400, 'data' => 'File upload failed'], 400); } // ✅ Update DB with new file name $updateData = [ 'endorsement_completion_file' => $pdfFileName, 'updated_by' => $data['updated_by'], ]; $updated = $this->EndorsementModel->update($data['id'], $updateData); // ✅ DB update failed → delete the newly uploaded file to avoid orphan files if (!$updated) { endorsement_delete_completion($pdfFileName); log_message('error', 'DB update failed for endorsement ID: ' . $data['id'] . '. New file removed.'); return $this->respond(['status' => 'failed', 'code' => 500, 'data' => 'DB update failed, file not saved'], 500); } // ✅ DB success → NOW safe to delete old file if ($oldFileName) { if (!endorsement_delete_completion($oldFileName)) { log_message('warning', 'DB updated but failed to delete old file: ' . $oldFileName); } else { log_message('info', 'Old file deleted after successful DB update: ' . $oldFileName); } } log_message('info', 'Endorsement PDF uploaded successfully. ID: ' . $data['id'] . ', File: ' . $pdfFileName); return $this->respond(['status' => 'success', 'code' => 200, 'data' => $data['id']], 200); } catch (\Exception $e) { log_message('error', 'uploadEndorsementFile error: ' . $e->getMessage()); return $this->respond(['status' => 'failed', 'code' => 500, 'data' => $e->getMessage()], 500); } } }