diff --git a/app/Config/Routes.php b/app/Config/Routes.php index dd64744..79a2a93 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -146,8 +146,10 @@ $routes->group('api', ['filter' => ["jwtAuth:1,2,3,4,agent","appSignature"] ], f $routes->get('policy/commissionPayoutReport', 'PolicyController::commissionPayoutReport'); $routes->get('policy/commissionPayoutReportExport', 'PolicyController::commissionPayoutReportExport'); //claims + $routes->get('claim/claimStatusList', 'ClaimController::claimStatusList'); $routes->get('claim/ClaimList', 'ClaimController::ClaimList'); $routes->post('claim/createClaim', 'ClaimController::createClaim'); + $routes->post('claim/updateClaim', 'ClaimController::updateClaim'); //endorsement $routes->get('endorsement/endorsementList', 'EndorsementController::endorsementList'); diff --git a/app/Controllers/ClaimController.php b/app/Controllers/ClaimController.php index a6cf982..7e6297d 100644 --- a/app/Controllers/ClaimController.php +++ b/app/Controllers/ClaimController.php @@ -3,6 +3,7 @@ namespace App\Controllers; use App\Models\ClaimModel; +use App\Models\ClaimFilesModel; use App\Models\PolicyModel; use App\Models\EnquiryModel; use App\Models\QuotationModel; @@ -13,188 +14,458 @@ class ClaimController extends ResourceController { protected $db; protected $ClaimModel; + protected $ClaimFilesModel; protected $PolicyModel; protected $QuotationModel; protected $EnquiryModel; protected $ClaimStatusModel; + private const CLAIM_UPLOAD_DIR = 'uploads/claims/'; + private const CLAIM_TICKET_TYPE = 8; + public function __construct() { $this->db = db_connect(); $this->ClaimModel = new ClaimModel(); + $this->ClaimFilesModel = new ClaimFilesModel(); $this->PolicyModel = new PolicyModel(); $this->QuotationModel = new QuotationModel(); $this->EnquiryModel = new EnquiryModel(); $this->ClaimStatusModel = new ClaimStatusModel(); } - // Get all tickets - public function ClaimList() + public function claimStatusList() { try { + $data = $this->ClaimStatusModel + ->select('id, claim_status, allowed_status, ticket_type, trigger_type') + ->where('ticket_type', self::CLAIM_TICKET_TYPE) + ->where('is_active', 1) + ->orderBy('id', 'ASC') + ->findAll(); - $id = $this->request->getGet('id'); // claim id - $manager_id = $this->request->getGet('manager_id'); - $agent_id = $this->request->getGet('agent_id'); - $policy_number = $this->request->getGet('policy_number'); - $claim_type_id = $this->request->getGet('claim_type_id'); // partner_claim_type_master.id - $claim_status_id = $this->request->getGet('claim_status_id'); // ticket_claim_status.id - $insurer_id = $this->request->getGet('insurer_id'); // insurers.id - $from_date = $this->request->getGet('from_date'); - $to_date = $this->request->getGet('to_date'); - - - $builder = $this->db->table('ticket_master tm') - ->select('tm.*, - i.name as insurer_name, - i.short_name as insurer_short_name, - c.client_name, c.phone as client_phone, c.email as client_email, - pct.claim_type as claim_type_value, - pa.name as agent_name, - tcs.claim_status as claim_status_value, - pp.start_date as policy_start_date , pp.end_date as policy_end_date, - v.vehicle_no as reg_no') - ->join('insurers i', 'i.id = tm.insurer_id', 'left') - ->join('clients c', 'c.id = tm.client_id', 'left') - ->join('partner_claim_type_master pct', 'pct.id = tm.claim_type', 'left') - ->join('partner_agent pa', 'pa.id = tm.agent_id', 'left') - ->join('ticket_claim_status tcs', 'tcs.id = tm.claim_status_id AND tcs.ticket_type = 8', 'left') - ->join('partner_policy pp', 'pp.policy_number = tm.policy_no', 'left') - ->join('vehicle v', 'v.id = tm.vehicle_id', 'left') - ->where('tm.ticket_type_id', 8); - - // If ID is provided, fetch single record - if (!empty($id)) { - $builder->where('tm.id', $id); - $ticket = $builder->get()->getRowArray(); - - if (!$ticket) { - return $this->respond(['status' => 'failed', 'code' => 404, 'data' => 'Not Found'], 404); - } - - return $this->respond(['status' => 'success', 'code' => 200, 'data' => $ticket], 200); - } - - // Apply filters - if (!empty($manager_id)) { - $builder->where('tm.manager_id', $manager_id); - } - - if (!empty($agent_id)) { - $builder->where('tm.agent_id', $agent_id); - } - - if (!empty($policy_number)) { - $builder->where('tm.policy_no', $policy_number); - } - - if (!empty($claim_type_id)) { - $builder->where('tm.claim_type', $claim_type_id); - } - - if (!empty($claim_status_id)) { - $builder->where('tm.claim_status_id', $claim_status_id); - } - - if (!empty($insurer_id)) { - $builder->where('tm.insurer_id', $insurer_id); - } - - if (!empty($from_date) && !empty($to_date)) { - $builder->where('tm.created_at >=', $from_date . ' 00:00:00') - ->where('tm.created_at <=', $to_date . ' 23:59:59'); - } - - $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'])); - } - 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 ClaimList() + { + try { + $id = $this->request->getGet('id'); + $manager_id = $this->request->getGet('manager_id'); + $agent_id = $this->request->getGet('agent_id'); + $policy_number = $this->request->getGet('policy_number'); + $claim_type_id = $this->request->getGet('claim_type_id'); + $claim_status_id = $this->request->getGet('claim_status_id'); + $insurer_id = $this->request->getGet('insurer_id'); + $from_date = $this->request->getGet('from_date'); + $to_date = $this->request->getGet('to_date'); + $builder = $this->db->table('partner_claims pc') + ->select('pc.*, + i.name as insurer_name, + i.short_name as insurer_short_name, + pct.claim_type as claim_type_value, + pa.name as agent_name, + tcs.claim_status as claim_status_value, + pp.start_date as policy_start_date, + pp.end_date as policy_end_date, + v.vehicle_no as reg_no') + ->join('insurers i', 'i.id = pc.insurer_id', 'left') + ->join('partner_claim_type_master pct', 'pct.id = pc.claim_type', 'left') + ->join('partner_agent pa', 'pa.id = pc.agent_id', 'left') + ->join('ticket_claim_status tcs', 'tcs.id = pc.claim_status_id AND tcs.ticket_type = ' . self::CLAIM_TICKET_TYPE, 'left') + ->join('partner_policy pp', 'pp.id = pc.policy_id', 'left') + ->join('vehicle v', 'v.id = pp.vehicle_id', 'left') + ->where('pc.is_active', 1); + + if (!empty($id)) { + $builder->where('pc.id', $id); + $claim = $builder->get()->getRowArray(); + + if (!$claim) { + return $this->respond(['status' => 'failed', 'code' => 404, 'data' => 'Not Found'], 404); + } + + $claim = $this->formatClaimRow($claim); + $claim['files'] = $this->getClaimFiles((int) $claim['id']); + + return $this->respond(['status' => 'success', 'code' => 200, 'data' => $claim], 200); + } + + if (!empty($manager_id)) { + $builder->where('pc.manager_id', $manager_id); + } + + if (!empty($agent_id)) { + $builder->where('pc.agent_id', $agent_id); + } + + if (!empty($policy_number)) { + $builder->where('pc.policy_no', $policy_number); + } + + if (!empty($claim_type_id)) { + $builder->where('pc.claim_type', $claim_type_id); + } + + if (!empty($claim_status_id)) { + $builder->where('pc.claim_status_id', $claim_status_id); + } + + if (!empty($insurer_id)) { + $builder->where('pc.insurer_id', $insurer_id); + } + + if (!empty($from_date) && !empty($to_date)) { + $builder->where('pc.created_at >=', $from_date . ' 00:00:00') + ->where('pc.created_at <=', $to_date . ' 23:59:59'); + } + + $data = $builder->orderBy('pc.id', 'DESC')->get()->getResultArray(); + $filesByClaim = $this->getClaimFilesGrouped(array_column($data, 'id')); + + foreach ($data as $key => $row) { + $data[$key] = $this->formatClaimRow($row); + $data[$key]['files'] = $filesByClaim[$row['id']] ?? []; + } + + return $this->respond(['status' => 'success', 'code' => 200, 'data' => $data], 200); + } catch (\Exception $e) { + return $this->respond(['status' => 'failed', 'code' => 500, 'data' => $e->getMessage()], 500); + } + } - // Create new ticket public function createClaim() { try { $reqData = $this->request->getPost(); - // Validate required fields - if (empty($reqData['policy_number']) || empty($reqData['claim_description'] || empty($reqData['claim_type']))) { - return $this->respond(['status' => 'failed','code' => 400, 'data' => 'policy_number and claim_description and claim_type are required'], 200); - } - - // Fetch policy details from partner_policy - $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') - ->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)) { + if (empty($reqData['policy_number']) || empty($reqData['claim_description']) || empty($reqData['claim_type'])) { return $this->respond([ 'status' => 'failed', - 'code' => 404, - 'data' => 'Policy not found' - ], 200); + 'code' => 400, + 'data' => 'policy_number, claim_description and claim_type are required', + ], 400); } - $uploadFile = $this->request->getFile('claim_file_name'); - $uploadedFileName = null; + $policy = $this->PolicyModel + ->select('partner_policy.*, Q.insurer_id, E.mobile as client_mobile, E.email as client_email') + ->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 ($uploadFile && $uploadFile->isValid()) { - $uploadPath = WRITEPATH . 'uploads/claims/'; - if (!is_dir($uploadPath)) { - mkdir($uploadPath, 0777, true); - } - $uploadedFileName = time() . '_' . $uploadFile->getRandomName(); - $uploadFile->move($uploadPath, $uploadedFileName); + if (empty($policy)) { + return $this->respond(['status' => 'failed', 'code' => 404, 'data' => 'Policy not found'], 404); } + $status = $this->ClaimStatusModel + ->where('ticket_type', self::CLAIM_TICKET_TYPE) + ->where('is_active', 1) + ->orderBy('id', 'ASC') + ->first(); - $status = $this->ClaimStatusModel->where('ticket_type', 8)->first(); + if (empty($status)) { + return $this->respond(['status' => 'failed', 'code' => 404, 'data' => 'Default claim status not found'], 404); + } - // Prepare claim data for ticket_master $claimData = [ - 'ticket_type_id' => 8, - 'claim_status_id' => $status['id'], - 'policy_no' => $policy['policy_number'], - 'client_policy_id' => $policy['client_policy_id'], - 'insurer_id' => $policy['insurer_id'], - 'client_id' => $policy['client_id'] ?? null, - 'agent_id' => $policy['agent_id'] ?? null, - 'manager_id' => $policy['manager_id'] ?? null, - 'vehicle_id' => $policy['vehicle_id'] ?? null, - 'insured_name' => $policy['insured_name'] ?? null, - 'emp_name' => $policy['client_name'] ?? null, - 'emp_mobile' => $policy['client_mobile'] ?? null, - 'emp_mail' => $policy['client_email'] ?? null, - 'emp_personal_mail'=> $policy['client_email'] ?? null, - 'claim_type' => $reqData['claim_type'], - 'claim_description'=> $reqData['claim_description'], - 'created_by' => $reqData['created_by'] ?? null, - 'claim_file_name' => $uploadedFileName, + 'claim_status_id' => $reqData['claim_status_id'] ?? $status['id'], + 'policy_id' => $policy['id'], + 'policy_no' => $policy['policy_number'], + 'insurer_id' => $policy['insurer_id'] ?? null, + 'insured_name' => $reqData['insured_name'] ?? $policy['insured_name'] ?? null, + 'mobile' => $reqData['mobile'] ?? $policy['client_mobile'] ?? null, + 'mail' => $reqData['mail'] ?? $policy['client_email'] ?? null, + 'manager_id' => $policy['manager_id'] ?? $reqData['manager_id'] ?? null, + 'agent_id' => $policy['agent_id'] ?? $reqData['agent_id'] ?? null, + 'claim_type' => $reqData['claim_type'], + 'date_of_incident' => format_date_for_database($reqData['date_of_incident'] ?? null), + 'place_of_incident' => $reqData['place_of_incident'] ?? null, + 'claim_description' => $reqData['claim_description'], + 'spot_surveyor_name' => $reqData['spot_surveyor_name'] ?? null, + 'spot_surveyor_contact' => $reqData['spot_surveyor_contact'] ?? null, + 'workshop_surveyor_name' => $reqData['workshop_surveyor_name'] ?? null, + 'workshop_surveyor_contact'=> $reqData['workshop_surveyor_contact'] ?? null, + 'is_active' => 1, + 'created_by' => $reqData['created_by'] ?? null, ]; - // Insert claim + $this->db->transStart(); + if (!$this->ClaimModel->insert($claimData)) { - return $this->respond(['status' => 'failed','code' => 422,'data' => $this->ClaimModel->errors()], 422); + $this->db->transRollback(); + return $this->respond(['status' => 'failed', 'code' => 422, 'data' => $this->ClaimModel->errors()], 422); } - return $this->respond(['status' => 'success','code' => 200,'data' => ['claim_id' => $this->ClaimModel->getInsertID()]], 200); + $claimId = (int) $this->ClaimModel->getInsertID(); + $fileResult = $this->saveClaimFiles($claimId, $reqData['created_by'] ?? null); + if ($fileResult['attempted'] > 0 && empty($fileResult['saved'])) { + $this->db->transRollback(); + return $this->respond([ + 'status' => 'failed', + 'code' => 422, + 'data' => !empty($fileResult['errors']) ? $fileResult['errors'] : 'Failed to upload claim files', + ], 422); + } + + if ($this->db->transStatus() === false) { + return $this->respond(['status' => 'failed', 'code' => 500, 'data' => 'Failed to create claim'], 500); + } + + $this->db->transComplete(); + + return $this->respond([ + 'status' => 'success', + 'code' => 200, + 'data' => [ + 'claim_id' => $claimId, + 'uploaded_files' => $fileResult['saved'], + 'files' => $this->getClaimFiles($claimId), + ], + ], 200); } catch (\Exception $e) { - return $this->respond(['status' => 'failed','code' => 500,'data' => $e->getMessage()], 500); + return $this->respond(['status' => 'failed', 'code' => 500, 'data' => $e->getMessage()], 500); } } + public function updateClaim() + { + try { + $claimId = $this->request->getPost('id'); - + if (empty($claimId)) { + return $this->respond(['status' => 'failed', 'code' => 400, 'data' => 'id is required'], 400); + } + + $reqData = $this->request->getPost(); + $claim = $this->ClaimModel->where('is_active', 1)->find((int) $claimId); + + if (!$claim) { + return $this->respond(['status' => 'failed', 'code' => 404, 'data' => 'Claim not found'], 404); + } + + $updateData = []; + $allowedUpdateFields = [ + 'claim_status_id', + 'insurer_id', + 'policy_id', + 'policy_no', + 'insured_name', + 'mobile', + 'mail', + 'manager_id', + 'agent_id', + 'claim_type', + 'place_of_incident', + 'claim_description', + 'spot_surveyor_name', + 'spot_surveyor_contact', + 'workshop_surveyor_name', + 'workshop_surveyor_contact', + 'is_active', + ]; + + foreach ($allowedUpdateFields as $field) { + if (array_key_exists($field, $reqData)) { + $updateData[$field] = $reqData[$field]; + } + } + + if (array_key_exists('date_of_incident', $reqData)) { + $updateData['date_of_incident'] = format_date_for_database($reqData['date_of_incident']); + } + + if (!empty($reqData['policy_number'])) { + $policy = $this->PolicyModel + ->select('partner_policy.*, Q.insurer_id') + ->join('partner_quotation Q', 'Q.id = partner_policy.quotation_id', 'left') + ->where('partner_policy.policy_number', $reqData['policy_number']) + ->first(); + + if ($policy) { + $updateData['policy_id'] = $policy['id']; + $updateData['policy_no'] = $policy['policy_number']; + if (!array_key_exists('insurer_id', $updateData)) { + $updateData['insurer_id'] = $policy['insurer_id'] ?? null; + } + } + } + + if (isset($reqData['updated_by'])) { + $updateData['updated_by'] = $reqData['updated_by']; + } + + if (!empty($updateData) && !$this->ClaimModel->update((int) $claimId, $updateData)) { + return $this->respond(['status' => 'failed', 'code' => 422, 'data' => $this->ClaimModel->errors()], 422); + } + + $fileResult = $this->saveClaimFiles((int) $claimId, $reqData['updated_by'] ?? $reqData['created_by'] ?? null); + + if ($fileResult['attempted'] > 0 && empty($fileResult['saved'])) { + return $this->respond([ + 'status' => 'failed', + 'code' => 422, + 'data' => !empty($fileResult['errors']) ? $fileResult['errors'] : 'Failed to upload claim files', + ], 422); + } + + return $this->respond([ + 'status' => 'success', + 'code' => 200, + 'data' => [ + 'claim_id' => (int) $claimId, + 'uploaded_files' => $fileResult['saved'], + 'files' => $this->getClaimFiles((int) $claimId), + ], + ], 200); + } catch (\Exception $e) { + return $this->respond(['status' => 'failed', 'code' => 500, 'data' => $e->getMessage()], 500); + } + } + + private function formatClaimRow(array $row): array + { + if (!empty($row['created_at'])) { + $row['created_at'] = date('d-m-Y h:i A', strtotime($row['created_at'])); + } + + if (!empty($row['updated_at'])) { + $row['updated_at'] = date('d-m-Y h:i A', strtotime($row['updated_at'])); + } + + if (!empty($row['date_of_incident']) && $row['date_of_incident'] !== '0000-00-00') { + $row['date_of_incident'] = date('d-m-Y', strtotime($row['date_of_incident'])); + } else { + $row['date_of_incident'] = null; + } + + $row['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; + + $row['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 $row; + } + + private function getClaimFiles(int $claimId): array + { + return $this->ClaimFilesModel + ->where('claim_id', $claimId) + ->where('is_active', 1) + ->orderBy('id', 'ASC') + ->findAll(); + } + + private function getClaimFilesGrouped(array $claimIds): array + { + $claimIds = array_values(array_filter(array_map('intval', $claimIds))); + + if (empty($claimIds)) { + return []; + } + + $files = $this->ClaimFilesModel + ->whereIn('claim_id', $claimIds) + ->where('is_active', 1) + ->orderBy('id', 'ASC') + ->findAll(); + + $grouped = []; + foreach ($files as $file) { + $grouped[$file['claim_id']][] = $file; + } + + return $grouped; + } + + /** + * Collect uploaded files from claim_files field (single or multiple). + */ + private function collectClaimUploadFiles(): array + { + $filesToProcess = []; + + $multiple = $this->request->getFileMultiple('claim_files'); + if (!empty($multiple)) { + foreach ($multiple as $uploadedFile) { + if ($this->isValidUploadFile($uploadedFile)) { + $filesToProcess[] = $uploadedFile; + } + } + return $filesToProcess; + } + + $single = $this->request->getFile('claim_files'); + if ($this->isValidUploadFile($single)) { + $filesToProcess[] = $single; + } + + return $filesToProcess; + } + + private function isValidUploadFile($uploadedFile): bool + { + return $uploadedFile + && method_exists($uploadedFile, 'isValid') + && $uploadedFile->isValid() + && !$uploadedFile->hasMoved(); + } + + private function saveClaimFiles(int $claimId, $createdBy = null): array + { + $uploadPath = WRITEPATH . self::CLAIM_UPLOAD_DIR; + if (!is_dir($uploadPath)) { + mkdir($uploadPath, 0777, true); + } + + $result = [ + 'saved' => [], + 'errors' => [], + 'attempted' => 0, + ]; + + $filesToProcess = $this->collectClaimUploadFiles(); + $result['attempted'] = count($filesToProcess); + + foreach ($filesToProcess as $file) { + try { + $storedName = time() . '_' . $file->getRandomName(); + + if (!$file->move($uploadPath, $storedName)) { + $result['errors'][] = $file->getErrorString() ?: 'Unable to move uploaded file'; + continue; + } + + if (!$this->ClaimFilesModel->insert([ + 'claim_id' => $claimId, + 'file_name' => $file->getClientName() ?: $storedName, + 'file_path' => self::CLAIM_UPLOAD_DIR . $storedName, + 'file_extension' => $file->getClientExtension(), + 'file_mime_type' => $file->getClientMimeType(), + 'is_active' => 1, + 'created_by' => $createdBy, + ])) { + if (is_file($uploadPath . $storedName)) { + unlink($uploadPath . $storedName); + } + $result['errors'][] = $this->ClaimFilesModel->errors() ?: 'Failed to save file record'; + continue; + } + + $result['saved'][] = $storedName; + } catch (\Exception $e) { + $result['errors'][] = $e->getMessage(); + } + } + + return $result; + } } diff --git a/app/Models/ClaimFilesModel.php b/app/Models/ClaimFilesModel.php new file mode 100644 index 0000000..93cd572 --- /dev/null +++ b/app/Models/ClaimFilesModel.php @@ -0,0 +1,31 @@ +