diff --git a/app/Controllers/Api/NonEbClaimApiController.php b/app/Controllers/Api/NonEbClaimApiController.php index 87347903..3cfa914d 100644 --- a/app/Controllers/Api/NonEbClaimApiController.php +++ b/app/Controllers/Api/NonEbClaimApiController.php @@ -260,7 +260,7 @@ class NonEbClaimApiController extends BaseController ->first(); if (!$acm) { - $this->myLogger->logme('error', "[NON_EB_API] No ACM found for client_id: {$cp['client_id']}"); + $this->myLogger->logme('error', "[NON_EB_API][createClaim] No ACM found for client_id: {$cp['client_id']}"); } // Auto-set first claim_status_id for this policy type @@ -349,7 +349,7 @@ class NonEbClaimApiController extends BaseController $this->saveAssets($claim_id, $body); $this->putHistoryAfterInsert($ticket_data, $claim_id); - $this->myLogger->logme('error', "[NON_EB_API] Claim created. ID: $claim_id, user: {$authUser['id']}"); + $this->myLogger->logme('error', "[NON_EB_API][createClaim] Claim created. ID: $claim_id, user: {$authUser['id']}"); return $this->respond([ 'status' => true, @@ -439,6 +439,8 @@ class NonEbClaimApiController extends BaseController $data = $builder->get()->getResultArray(); + $this->myLogger->logme('error', "[NON_EB_API][listClaims] user: {$authUser['id']}, page: $page, total: $total"); + return $this->respond([ 'status' => true, 'code' => 200, @@ -456,18 +458,61 @@ class NonEbClaimApiController extends BaseController return $this->respond(['status' => false, 'code' => 401, 'message' => 'Unauthorized'], 401); } - // Verify claim exists - $claim = $this->nonEbTicketModel - ->select('id, client_id, policy_type_id') - ->where('id', $claim_id) - ->where('is_active', 1) - ->first(); + // Fetch full claim row with joins (client, insurer, status, policy type, ACM, branch) + $raw = $this->nonEbTicketModel->getTicketDataByTicketID($claim_id); - if (!$claim) { + if (!$raw) { return $this->respond(['status' => false, 'code' => 404, 'message' => 'Claim not found'], 404); } - // Fetch only claim_status_id history rows, oldest first + // claims_data — major display fields only + $claims_data = [ + 'id' => $raw['id'], + 'nhance_claim_ref_no' => $raw['nhance_claim_ref_no'], + 'claim_number' => $raw['claim_number'], + 'policy_no' => $raw['policy_no'], + 'policy_type_name' => $raw['policy_type_name'], + 'client_name' => $raw['client_name'], + 'branch_name' => $raw['branch_name'], + 'insurer_name' => $raw['insurer_name'], + 'claim_status' => $raw['claim_status'], + 'status_display_name' => $raw['status_display_name'], + 'insured_contact_name' => $raw['insured_contact_name'], + 'insured_contact_number' => $raw['insured_contact_number'], + 'insured_contact_email' => $raw['insured_contact_email'], + 'nature_of_loss' => $raw['nature_of_loss'], + 'loss_location' => $raw['loss_location'], + 'loss_date' => $raw['loss_date'], + 'loss_description' => $raw['loss_description'], + 'loss_estimate' => $raw['loss_estimate'], + 'loss_assessed_value' => $raw['loss_assessed_value'], + 'settled_amount' => $raw['settled_amount'], + 'settlement_utr' => $raw['settlement_utr'], + 'intimation_recd_date' => $raw['intimation_recd_date'], + 'intimated_to_insurer_date'=> $raw['intimated_to_insurer_date'], + 'surveyor_name' => $raw['surveyor_name'], + 'surveyor_contact_person' => $raw['surveyor_contact_person'], + 'surveyor_contact_number' => $raw['surveyor_contact_number'], + 'acm' => $raw['acm'], + 'acm_mobile' => $raw['acm_mobile'], + 'asset_file' => $raw['asset_file'], + 'priority' => $raw['priority'], + 'created_at' => $raw['created_at'], + 'updated_at' => $raw['updated_at'], + ]; + + // required_docs — decoded separately + $required_docs = json_decode($raw['required_docs'] ?? '{}', true) ?: []; + + // claims_files + $claims_files = $this->claimFilesModel + ->select('id, doc_name, file_name, mime_type, file_type, docs_for_ir, created_at') + ->where('ticket_id', $claim_id) + ->where('ticket_type', 2) + ->where('is_active', 1) + ->findAll(); + + // ticket_data — claim status history, oldest first $history_rows = $this->ticketHistoryModel ->select('new_value, created_at') ->where('ticket_id', $claim_id) @@ -476,14 +521,9 @@ class NonEbClaimApiController extends BaseController ->orderBy('created_at', 'ASC') ->findAll(); - if (empty($history_rows)) { - return $this->respond(['status' => true, 'code' => 200, 'claim_id' => $claim_id, 'history' => []], 200); - } - - // Build display_name map for this policy type — only statuses with a display_name are user-visible $statuses = $this->claimStatusModel ->select('id, claim_status, display_name') - ->where('ticket_type', $claim['policy_type_id']) + ->where('ticket_type', $raw['policy_type_id']) ->where('display_name IS NOT NULL') ->where("display_name != ''") ->where('is_active', 1) @@ -491,24 +531,28 @@ class NonEbClaimApiController extends BaseController $display_map = array_column($statuses, 'display_name', 'id'); - // Filter and format — skip statuses with no display_name - $history = []; + $ticket_data = []; foreach ($history_rows as $row) { - $status_id = (int)$row['new_value']; + $status_id = (int)$row['new_value']; $display_name = $display_map[$status_id] ?? null; if (!$display_name) continue; - $history[] = [ + $ticket_data[] = [ 'status' => $display_name, 'changed_at' => date('d-m-Y h:i A', strtotime($row['created_at'])), ]; } + $this->myLogger->logme('error', "[NON_EB_API][claimHistory] claim_id: $claim_id, steps: " . count($ticket_data) . ", user: {$authUser['id']}"); + return $this->respond([ - 'status' => true, - 'code' => 200, - 'claim_id' => $claim_id, - 'history' => $history, + 'status' => true, + 'code' => 200, + 'claim_id' => $claim_id, + 'claims_data' => $claims_data, + 'required_docs' => $required_docs, + 'claims_files' => $claims_files, + 'ticket_data' => $ticket_data, ], 200); } @@ -530,6 +574,8 @@ class NonEbClaimApiController extends BaseController ->orderBy('id', 'ASC') ->findAll(); + $this->myLogger->logme('error', "[NON_EB_API][listClaimStatuses] user: {$authUser['id']}, count: " . count($statuses)); + return $this->respond([ 'status' => true, 'code' => 200, @@ -597,6 +643,8 @@ class NonEbClaimApiController extends BaseController $policies = $builder->get()->getResultArray(); + $this->myLogger->logme('error', "[NON_EB_API][listPolicies] user: {$authUser['id']}, client_md5: $client_id_md5, branch: $client_branch_id, count: " . count($policies)); + return $this->respond([ 'status' => true, 'code' => 200, @@ -702,12 +750,15 @@ class NonEbClaimApiController extends BaseController $db->transComplete(); if (!$db->transStatus()) { + $this->myLogger->logme('error', "[NON_EB_API][uploadRequiredDoc] Transaction failed. claim_id: $claim_id, doc: $document_name, user: {$authUser['id']}"); return $this->respond(['status' => false, 'code' => 500, 'message' => 'Failed to save document. Please try again.'], 500); } $file_id = $this->claimFilesModel->insertID(); $download_url = base_url('downloadClaimFile/') . $file_id; + $this->myLogger->logme('error', "[NON_EB_API][uploadRequiredDoc] Doc uploaded. claim_id: $claim_id, doc: $document_name, file: $file_name, user: {$authUser['id']}"); + return $this->respond([ 'status' => true, 'code' => 200, diff --git a/dev_logs/2026-04-01.md b/dev_logs/2026-04-01.md new file mode 100644 index 00000000..0870e7f5 --- /dev/null +++ b/dev_logs/2026-04-01.md @@ -0,0 +1,47 @@ +# Dev Log — 2026-04-01 + +## NonEbClaimApiController — Bug Fix, Enhancements & API Docs + +--- + +### 1. Fix: JSON Parse 500 Error on `createClaim` +- **Problem:** `getJSON(true)` throws a `500 HTTPException` (Syntax error) when the request body is multipart/form-data (file upload), not JSON. +- **Fix:** Replaced `getJSON(true)` with `json_decode(getBody()) ?? getPost()` so multipart POST data is read correctly without throwing. + +### 2. Fix: JSON Parse 500 Error on `listClaims` and `listPolicies` +- **Problem:** Same `getJSON(true)` issue — any malformed or missing JSON body causes a 500 instead of a graceful 400. +- **Fix:** Wrapped `getJSON(true)` calls in `try/catch (\Throwable)` returning a proper `400 Invalid JSON body` response. + +### 3. Add: Logging to all API endpoints +Added `myLogger->logme('error', ...)` calls to all 6 endpoints under `employeeRest/api/v1/non-eb-claim` that previously had no log coverage: + +| Endpoint | Log event | +|---|---| +| `createClaim` | No ACM found, claim created with ID + user | +| `listClaims` | User + page + total count | +| `claimHistory` | Claim ID + history steps + user | +| `listClaimStatuses` | User + status count | +| `listPolicies` | User + client_md5 + branch + count | +| `uploadRequiredDoc` | Transaction failure + successful upload with doc/file/user | + +All log tags follow the pattern `[NON_EB_API][methodName]` for easy log filtering. + +### 4. Enhance: `claimHistory` endpoint — full claim detail response +Previously returned only status history array. Now returns 4 keys: + +| Key | Source | Description | +|---|---|---| +| `claims_data` | `non_eb_ticket_master` + joins | Major display fields (name, policy, status, surveyor, etc.) | +| `required_docs` | `non_eb_ticket_master.required_docs` (decoded) | IR documents checklist | +| `claims_files` | `claim_files` table | Uploaded documents for this claim | +| `ticket_data` | `ticket_history` table | Claim status change history (renamed from `history`) | + +Also removed early-return on empty history so all 4 keys are always present in the response. + +--- + +### Files Changed +- `app/Controllers/Api/NonEbClaimApiController.php` + +### API Docs +- `dev_logs/non_eb_claim_api.md` diff --git a/dev_logs/non_eb_claim_api.md b/dev_logs/non_eb_claim_api.md new file mode 100644 index 00000000..242b4df1 --- /dev/null +++ b/dev_logs/non_eb_claim_api.md @@ -0,0 +1,309 @@ +# Non-EB Claim API — Documentation + +**Base URL:** `/employeeRest/api/v1/non-eb-claim` +**Auth:** Bearer JWT token via `Authorization` header (required on all endpoints) +**Filter:** `ratelimit`, `authJWT` + +--- + +## 1. Create Claim +`POST /create` + +**Content-Type:** `multipart/form-data` + +### Request Fields +| Field | Type | Required | Notes | +|---|---|---|---| +| `client_policy_id` | int | Yes | Must be active Non-EB or Marine policy | +| `nature_of_loss` | string | Yes | Min 3 chars | +| `loss_location` | string | Yes | | +| `loss_date` | string | Yes | Format: DD-MM-YYYY | +| `loss_description` | string | No | Required if `asset_file` is uploaded | +| `loss_estimate` | numeric | No | | +| `claim_number` | string | No | Alphanumeric, `/`, `_`, `-` only | +| `asset_file` | file | No | Allowed: pdf, xls, xlsx, csv | +| `asset_id_code[]` | array | No | Asset details | +| `serial_no[]` | array | No | | +| `vehicle_no[]` | array | No | | +| `asset_description[]` | array | No | | + +### Response — 200 +```json +{ + "status": true, + "code": 200, + "claim_id": 42, + "asset_file": "asset_20250315_abc123.pdf", + "message": "Non-EB Claim created successfully" +} +``` + +### Error Responses +| Code | Reason | +|---|---| +| 400 | Validation failed | +| 404 | Client policy not found | +| 409 | Duplicate claim (same client + loss_date + policy_no) | +| 415 | Unsupported asset file type | +| 422 | Policy type not Non-EB/Marine, or no claim status configured | +| 500 | DB insert or file upload failed | + +--- + +## 2. List Claims +`POST /list` + +**Content-Type:** `application/json` + +### Request Body (all optional) +```json +{ + "page": 1, + "per_page": 20, + "client_id": 101, + "insurer_id": 5, + "policy_type_id": 50, + "claim_status_id": 3, + "claim_number": "CLM/2025", + "nhance_claim_ref_no": "NHC/NEB", + "date_type": "created_date", + "start_date": "01-01-2025", + "end_date": "31-03-2025", + "show_closed": false +} +``` + +> `date_type`: `"created_date"` (default) or `"updated_date"` +> `show_closed`: if falsy, excludes Settled / Closed / Rejected / Withdrawn claims + +### Response — 200 +```json +{ + "status": true, + "code": 200, + "total": 84, + "page": 1, + "per_page": 20, + "data": [ + { + "id": 42, + "claim_number": "CLM/INS/2025/1234", + "nhance_claim_ref_no": "NHC/NEB/2025/00042", + "policy_no": "POL/MAR/2025/5678", + "policy_type_id": 50, + "claim_status_id": 3, + "status": "surveyor_assigned", + "status_display": "Surveyor Assigned", + "policy_type_name": "Marine Cargo", + "client_name": "Acme Logistics Pvt Ltd", + "insurer_name": "New India Assurance", + "loss_date": "2025-03-15", + "loss_location": "Chennai Port, Gate 3", + "nature_of_loss": "Fire and explosion damage to cargo", + "loss_estimate": "850000.00", + "insured_contact_name": "Ramesh Kumar", + "insured_contact_number": "9876543210", + "acm_name": "Priya Nair", + "created_date": "16-03-2025", + "updated_date": "20-03-2025" + } + ] +} +``` + +### Error Responses +| Code | Reason | +|---|---| +| 400 | Invalid JSON body | + +--- + +## 3. Claim Detail + History +`GET /history/{claim_id}` + +### Response — 200 +```json +{ + "status": true, + "code": 200, + "claim_id": 42, + "claims_data": { + "id": 42, + "nhance_claim_ref_no": "NHC/NEB/2025/00042", + "claim_number": "CLM/INS/2025/1234", + "policy_no": "POL/MAR/2025/5678", + "policy_type_name": "Marine Cargo", + "client_name": "Acme Logistics Pvt Ltd", + "branch_name": "Chennai Branch", + "insurer_name": "New India Assurance", + "claim_status": "surveyor_assigned", + "status_display_name": "Surveyor Assigned", + "insured_contact_name": "Ramesh Kumar", + "insured_contact_number": "9876543210", + "insured_contact_email": "ramesh@acmelogistics.com", + "nature_of_loss": "Fire and explosion damage to cargo", + "loss_location": "Chennai Port, Gate 3", + "loss_date": "2025-03-15", + "loss_description": "Fire broke out in warehouse bay during unloading", + "loss_estimate": "850000.00", + "loss_assessed_value": "720000.00", + "settled_amount": null, + "settlement_utr": null, + "intimation_recd_date": "2025-03-16", + "intimated_to_insurer_date": "2025-03-17", + "surveyor_name": "Suresh Inspection Services", + "surveyor_contact_person": "Suresh Babu", + "surveyor_contact_number": "9444123456", + "acm": "Priya Nair", + "acm_mobile": "9500011122", + "asset_file": "asset_20250315_abc123.pdf", + "priority": 1, + "created_at": "2025-03-16 10:30:00", + "updated_at": "2025-03-20 14:45:00" + }, + "required_docs": { + "is_action_freeze": false, + "docs": [ + { "document_name": "Claim Form", "document_received": true }, + { "document_name": "Survey Report", "document_received": false }, + { "document_name": "Police FIR Copy", "document_received": false } + ] + }, + "claims_files": [ + { + "id": 101, + "doc_name": "Claim Form", + "file_name": "claim_form_42_20250316.pdf", + "mime_type": "application/pdf", + "file_type": 2, + "docs_for_ir": 1, + "created_at": "2025-03-16 11:00:00" + } + ], + "ticket_data": [ + { "status": "Claim Registered", "changed_at": "16-03-2025 10:30 AM" }, + { "status": "Intimated to Insurer", "changed_at": "17-03-2025 09:00 AM" }, + { "status": "Surveyor Assigned", "changed_at": "20-03-2025 02:45 PM" } + ] +} +``` + +### Error Responses +| Code | Reason | +|---|---| +| 404 | Claim not found or inactive | + +--- + +## 4. Upload Required Document +`POST /{claim_id}/upload-required-doc` + +**Content-Type:** `multipart/form-data` + +### Request Fields +| Field | Type | Required | Notes | +|---|---|---|---| +| `document_name` | string | Yes | Must exactly match a name in `required_docs.docs` | +| `file` | file | Yes | Allowed: pdf, jpg, jpeg, png, doc, docx, xls, xlsx | + +### Response — 200 +```json +{ + "status": true, + "code": 200, + "message": "Document uploaded successfully", + "claim_id": 42, + "document_name": "Claim Form", + "download_url": "https://yourdomain.com/downloadClaimFile/101", + "required_docs": { + "is_action_freeze": false, + "docs": [ + { "document_name": "Claim Form", "document_received": true }, + { "document_name": "Survey Report", "document_received": false } + ] + } +} +``` + +### Error Responses +| Code | Reason | +|---|---| +| 400 | Missing `document_name` or invalid file | +| 404 | Claim not found, or `document_name` not in checklist | +| 415 | Unsupported file type | +| 422 | No required docs checklist configured | +| 423 | Checklist is locked (`is_action_freeze = true`) | +| 500 | File upload or DB transaction failed | + +--- + +## 5. List Claim Statuses +`GET /statuses` + +### Response — 200 +```json +{ + "status": true, + "code": 200, + "data": [ + { "id": 1, "claim_status": "claim_registered", "display_name": "Claim Registered" }, + { "id": 2, "claim_status": "intimated_to_insurer","display_name": "Intimated to Insurer" }, + { "id": 3, "claim_status": "surveyor_assigned", "display_name": "Surveyor Assigned" } + ] +} +``` + +--- + +## 6. List Policies (Non-EB / Marine) +`POST /policies` + +**Content-Type:** `application/json` + +### Request Body +```json +{ + "client_id": "5058f1af8388634f884bd49b13....", + "client_branch_id": 7 +} +``` + +> `client_id` — MD5 hash of the client's numeric ID + +### Response — 200 +```json +{ + "status": true, + "code": 200, + "total": 3, + "data": [ + { + "id": 88, + "policy_no": "POL/MAR/2025/5678", + "policy_type_id": 50, + "policy_type_name": "Marine Cargo", + "insurer_id": 5, + "insurer_name": "New India Assurance", + "insurer_short_name": "NIA", + "policy_start_date": "01-04-2025", + "policy_end_date": "31-03-2026" + } + ] +} +``` + +### Error Responses +| Code | Reason | +|---|---| +| 400 | Missing or invalid `client_id` / `client_branch_id` | + +--- + +## Common Auth Error (all endpoints) +```json +{ + "status": false, + "code": 401, + "message": "Unauthorized" +} +```