nhance/app/Views/docs/non-eb-claims.php
2026-05-22 15:01:14 +05:30

489 lines
29 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* Non-EB Claims — content only
* app/Views/docs/non-eb-claims.php
*
* Scope: web MVC only (/non-eb-claim/*). REST API under employeeRest is out of scope.
* Sources:
* - app/Controllers/NonEbClaimController.php
* - app/Views/non_eb_claim_*.php
* - app/Config/Routes.php (authMVC group)
*/
?>
<p>
This page documents the <strong>Non-EB Claims</strong> web workflow: list and filter claims,
create and edit tickets, status-driven form sections, document uploads, manual email reply,
<strong>mail template CRUD</strong>, auto-mail on create/status change, and claim reports.
</p>
<p>
<strong>Scope:</strong> authenticated MVC routes under <code>/non-eb-claim/*</code> only.
Mobile/REST endpoints in <code>Api\NonEbClaimApiController</code> are not covered here.
</p>
<p>
Policy types are limited to <code>policy_type.allocg IN ('Non-EB', 'Marine')</code>.
Claim records live in <code>non_eb_ticket_master</code>; claim files use <code>ticket_type = 2</code>
in <code>claim_files</code>.
</p>
<h2 id="overview">End-to-end flow</h2>
<div class="mermaid-wrapper">
<div class="mermaid">
flowchart TD
L["GET /non-eb-claim/list"] --> F["Filter sidebar → POST /list"]
F --> T["Table non_eb_claim_list.php"]
T --> A{"Action"}
A -->|Add| N["GET /non-eb-claim/new/50 or new/{policy_type_id}"]
N --> C["POST /non-eb-claim/create"]
C --> AM["sendAutoMailTrigger if template is_auto_mail=1"]
A -->|Row click / View| V["GET /non-eb-claim/view/{id}"]
V --> U["POST /non-eb-claim/update"]
U --> SC{"claim_status_id changed?"}
SC -->|yes| AM2["sendAutoMailTrigger"]
MT["GET /non-eb-claim/mail_template"] --> CRUD["POST crud_mail_template/1|2|3"]
R["GET /non-eb-claim/reports"] --> RP["POST /reports — UI only; see pitfalls"]
</div>
</div>
<p><strong>Typical user path:</strong></p>
<ol>
<li>Open claim list (default: open claims excluding settled/closed/rejected/withdrawn).</li>
<li>Add claim → form opens with canonical status policy type <code>50</code> — see <a href="#policy-type-50-default">why 50 is hardcoded</a>.</li>
<li>On save, optional auto-mail fires if a matching template has <code>is_auto_mail = 1</code>.</li>
<li>Open claim from list → edit view with history, messages, files, notes.</li>
<li>Change status → allowed next statuses from <code>ticket_claim_status.allowed_status</code>; section visibility updates.</li>
<li>Configure templates at <code>/non-eb-claim/mail_template</code> (direct URL; not in main Claims sidebar today).</li>
</ol>
<h2 id="policy-type-50-default">Why policy type <code>50</code> is hardcoded (read this before changing Non-EB Claims)</h2>
<div style="border-left: 4px solid #c0392b; background: #fdf2f2; padding: 1rem 1.25rem; margin: 1.25rem 0;">
<p style="margin-top: 0;">
<strong>Non-EB has many real policy products</strong> (Fire, Marine, Liability, etc. — each row in
<code>policy_type</code> with <code>allocg</code> Non-EB or Marine). Claim <strong>status workflows</strong> are
<em>not</em> stored separately per product today. The team configured <strong>one canonical policy type,
id <code>50</code></strong>, in the database as the single source of status definitions. The application
assumes <strong>every</strong> Non-EB/Marine claim uses that same status set unless you deliberately change
backend and frontend.
</p>
</div>
<h3 id="policy-type-50-assumption">Design assumption</h3>
<p>
Claim statuses live in <code>ticket_claim_status</code>, keyed by <code>ticket_type</code> (which equals
<code>policy_type.id</code>). Mail templates in <code>ticket_mail_template</code> also key off
<code>ticket_type</code> + <code>trigger_type</code> from that status row.
</p>
<p>Instead of maintaining duplicate status trees for every Non-EB product, developers assumed:</p>
<blockquote>
<p style="margin: 0;">
<strong>All Non-EB and Marine policy types share one identical claim status lifecycle.</strong>
That lifecycle is configured only under policy type <code>50</code> in
<code>ticket_claim_status</code> (and matching templates under <code>ticket_type = 50</code>).
</p>
</blockquote>
<p>
New claims opened via the list <strong>Add</strong> button or <strong>New Non EB Claim</strong> menu therefore
pass <code>50</code> into the form URL. Status dropdowns, section visibility, and initial status resolution in
<code>getClaimStatusForPolicyType($policy_type_id)</code> all use that id on create — not the id of the policy
the user later picks from <code>client_policy</code>.
</p>
<h3 id="policy-type-50-vs-selected-policy">Policy type 50 vs policy selected on the form</h3>
<p>On create (<code>non_eb_claim_form.php</code>):</p>
<ul>
<li>Hidden <code>policy_type_id</code> is set from the URL segment (typically <code>50</code>) and is <strong>not</strong> updated when the user selects a branch policy.</li>
<li>The UI shows the real product name in <code>policy_type_display</code> from the selected policy row (<code>data-policy-type</code>).</li>
<li><code>POST /non-eb-claim/create</code> persists <code>policy_type_id</code> from that hidden field — so new tickets from Add often store <code>policy_type_id = 50</code> even when the linked policy is Fire, Marine, etc.</li>
</ul>
<p>
On edit (<code>non_eb_claim_edit.php</code>), <code>policy_type_id</code> comes from
<code>non_eb_ticket_master</code> as saved. Status changes and templates use that stored id.
</p>
<h3 id="policy-type-50-where-hardcoded">Where <code>50</code> appears in code (change all if this design changes)</h3>
<div class="docs-table-wrap">
<table>
<thead>
<tr><th>Location</th><th>Usage</th></tr>
</thead>
<tbody>
<tr><td><code>app/Config/Routes.php</code></td><td><code>GET non-eb-claim/new</code> → <code>claimForm/50</code></td></tr>
<tr><td><code>app/Views/non_eb_claim_list.php</code></td><td>DataTable Add button → <code>/non-eb-claim/new/50</code></td></tr>
<tr><td><code>app/Views/non_eb_claim_form.php</code></td><td>Hidden <code>policy_type_id</code> from route; status/section AJAX uses this value</td></tr>
<tr><td><code>ticket_claim_status</code> (DB)</td><td>Master status rows maintained with <code>ticket_type = 50</code></td></tr>
<tr><td><code>ticket_mail_template</code> (DB)</td><td>Non-EB auto-mail templates should use <code>ticket_type = 50</code> if they follow the shared workflow</td></tr>
<tr><td><code>Api\NonEbClaimApiController::listClaimStatuses()</code></td><td>API hardcodes <code>where('ticket_type', 50)</code> (out of scope for this page but same assumption)</td></tr>
</tbody>
</table>
</div>
<h3 id="policy-type-50-future">When a Non-EB product needs a <em>different</em> status set</h3>
<p>
If a new (or existing) policy type must have its <strong>own</strong> statuses, triggers, or allowed transitions
(not the shared tree under <code>50</code>), you cannot only change the product row in
<code>policy_type</code>. You must update <strong>both backend and frontend</strong>:
</p>
<ol>
<li><strong>Database</strong> — Add full <code>ticket_claim_status</code> rows with
<code>ticket_type = &lt;that policy_type.id&gt;</code> (claim_status, display_name, trigger_type,
allowed_status JSON). Add matching <code>ticket_mail_template</code> rows for that
<code>ticket_type</code> if auto-mail applies.</li>
<li><strong>Routes / entry URL</strong> — Stop routing every new claim through <code>50</code>: e.g. change
<code>claimForm/50</code>, restore policy-type picker modal (commented in
<code>non_eb_claim_search.php</code>), or pass the correct <code>policy_type_id</code> per product.</li>
<li><strong>List Add button</strong> — Replace hardcoded <code>new/50</code> in
<code>non_eb_claim_list.php</code> with the correct id or dynamic selection.</li>
<li><strong>Create form</strong> — On policy selection, set hidden <code>#policy_type_id</code> to the real
<code>policy_type_id</code> from <code>getBranchAndPolicy</code> (field <code>p.policy_type_id</code> is
already returned) so create/update and <code>getVisibleSections</code> use the right status tree.</li>
<li><strong>Controller logic</strong> — Ensure <code>getClaimStatusForPolicyType</code>,
<code>getTemplateDataByTicketID</code>, and filters that assume a single Non-EB status catalog are tested for
the new <code>ticket_type</code>.</li>
<li><strong>API</strong> — Replace hardcoded <code>50</code> in <code>listClaimStatuses()</code> if mobile
clients need per-product statuses.</li>
</ol>
<p>
Until those steps are done, pointing Add at another id without cloning the full status + template set under
that id will produce <strong>empty status lists</strong>, <strong>wrong section visibility</strong>, or
<strong>missing auto-mail</strong>.
</p>
<h2 id="key-files">Key files and routes</h2>
<table>
<thead>
<tr><th>Area</th><th>File / route</th></tr>
</thead>
<tbody>
<tr><td>Controller</td><td><code>app/Controllers/NonEbClaimController.php</code></td></tr>
<tr><td>Model</td><td><code>app/Models/NonEbTicketMasterModel.php</code></td></tr>
<tr><td>List + filters</td><td><code>app/Views/non_eb_claim_search.php</code>, <code>non_eb_claim_list.php</code></td></tr>
<tr><td>New claim</td><td><code>app/Views/non_eb_claim_form.php</code></td></tr>
<tr><td>View / edit</td><td><code>app/Views/non_eb_claim_edit.php</code></td></tr>
<tr><td>Mail templates</td><td><code>app/Views/non_eb_claim_mail_template.php</code></td></tr>
<tr><td>Reports</td><td><code>app/Views/non_eb_claim_reports.php</code></td></tr>
<tr><td>Routes</td><td><code>app/Config/Routes.php</code> — group <code>/non-eb-claim</code>, filter <code>authMVC</code></td></tr>
<tr><td>ACL</td><td><code>app/Config/Acl.php</code> — <code>#^/non-eb-claim#</code> (Claims team roles)</td></tr>
<tr><td>App menu</td><td><code>app/Views/layout/header.php</code> — New / List only (EB mail template link is separate)</td></tr>
</tbody>
</table>
<h3 id="route-map">MVC route map</h3>
<div class="docs-table-wrap docs-table-wrap--fluid">
<table>
<thead>
<tr><th>Method</th><th>Route</th><th>Controller</th><th>Purpose</th></tr>
</thead>
<tbody>
<tr><td>GET</td><td><code>/non-eb-claim/list</code></td><td><code>claimList</code></td><td>Search page + default open claims</td></tr>
<tr><td>POST</td><td><code>/non-eb-claim/list</code></td><td><code>claimList</code></td><td>Filter → HTML partial for DataTable</td></tr>
<tr><td>GET</td><td><code>/non-eb-claim/new</code></td><td><code>claimForm/50</code></td><td>New claim (default policy type 50)</td></tr>
<tr><td>GET</td><td><code>/non-eb-claim/new/{policy_type_id}</code></td><td><code>claimForm</code></td><td>New claim for selected product</td></tr>
<tr><td>POST</td><td><code>/non-eb-claim/create</code></td><td><code>createClaim</code></td><td>Create ticket + assets + history + auto-mail</td></tr>
<tr><td>GET</td><td><code>/non-eb-claim/view/{id}</code></td><td><code>view_claim</code></td><td>Edit layout (<code>non_eb_claim_edit</code>)</td></tr>
<tr><td>POST</td><td><code>/non-eb-claim/update</code></td><td><code>updateClaim</code></td><td>Update; auto-mail on status change</td></tr>
<tr><td>GET</td><td><code>/non-eb-claim/remove?ticket_id=</code></td><td><code>removeClaim</code></td><td>Soft delete (<code>is_active = 0</code>)</td></tr>
<tr><td>GET</td><td><code>/non-eb-claim/mail_template</code></td><td><code>mailTemplate</code></td><td>Template list + modal CRUD UI</td></tr>
<tr><td>POST</td><td><code>/non-eb-claim/crud_mail_template/1</code></td><td><code>crudTemplate</code></td><td>Save template</td></tr>
<tr><td>POST</td><td><code>/non-eb-claim/crud_mail_template/2</code></td><td><code>crudTemplate</code></td><td>Fetch one template (edit)</td></tr>
<tr><td>POST</td><td><code>/non-eb-claim/crud_mail_template/3</code></td><td><code>crudTemplate</code></td><td>Soft delete template</td></tr>
<tr><td>POST</td><td><code>/non-eb-claim/note/1</code></td><td><code>crudNote</code></td><td>Get note</td></tr>
<tr><td>POST</td><td><code>/non-eb-claim/note/2</code></td><td><code>crudNote</code></td><td>Save note</td></tr>
<tr><td>POST</td><td><code>/non-eb-claim/reply</code></td><td><code>saveReply</code></td><td>Manual outbound mail + message row</td></tr>
<tr><td>GET</td><td><code>/non-eb-claim/reports</code></td><td><code>claimReports</code></td><td>Reports UI shell</td></tr>
<tr><td>POST</td><td><code>/non-eb-claim/reports</code></td><td><code>claimReports</code></td><td><em>Not implemented in controller</em> — see <a href="#reports">Reports</a></td></tr>
<tr><td>POST</td><td><code>/non-eb-claim/getBranchAndPolicy</code></td><td><code>getBranchAndPolicyByClientID</code></td><td>Branches, policies, contacts for client</td></tr>
<tr><td>POST</td><td><code>/non-eb-claim/getVisibleSections</code></td><td><code>getVisibleSectionsAjax</code></td><td>Section keys for status</td></tr>
<tr><td>POST</td><td><code>/non-eb-claim/getMoreInfo</code></td><td><code>getMoreInfo</code></td><td>Ticket row JSON</td></tr>
<tr><td>POST</td><td><code>/non-eb-claim/uploadFile</code></td><td><code>uploadFile</code></td><td>Claim docs (file or Drive URL)</td></tr>
<tr><td>POST</td><td><code>/non-eb-claim/getClaimFiles</code></td><td><code>getClaimFiles</code></td><td>List files for ticket</td></tr>
<tr><td>GET</td><td><code>/non-eb-claim/removeFile?id=</code></td><td><code>removeFile</code></td><td>Soft delete file</td></tr>
<tr><td>POST</td><td><code>/non-eb-claim/saveIRDocs</code></td><td><code>saveIRDocs</code></td><td>Persist required-docs JSON on ticket</td></tr>
<tr><td>GET</td><td><code>/non-eb-claim/testAutoMail/{id}</code></td><td><code>testAutoMailTrigger</code></td><td>Dev/test auto-mail (optional)</td></tr>
</tbody>
</table>
</div>
<h2 id="access">Access control</h2>
<p>
All routes in the <code>/non-eb-claim</code> group use the <code>authMVC</code> filter.
<code>Acl.php</code> allows roles <code>HEAD</code>, <code>ADMIN</code>, <code>MANAGER</code>,
<code>ACCOUNT_MANAGER</code> on the Claims team.
</p>
<p>
List row actions (view / delete) render only for roles <code>1, 2, 5</code> in
<code>non_eb_claim_list.php</code>.
</p>
<h2 id="list-flow">List and filter</h2>
<p><strong>GET <code>/non-eb-claim/list</code></strong> loads <code>non_eb_claim_search.php</code>, which includes the table partial. Initial data comes from <code>claimSearch(1)</code>: active tickets where status display name is <em>not</em> in Claim Settled, Claim Closed, Claim Rejected, Claim Withdrawn.</p>
<p><strong>Filter sidebar</strong> posts the same URL with criteria (at least one required):</p>
<ul>
<li><code>policy_type_id</code>, <code>insurer_id</code>, <code>claim_number</code>, <code>nhance_claim_ref_no</code></li>
<li><code>client_id</code>, <code>claim_status_id</code> (status options filtered by policy type in JS)</li>
<li><code>date_type</code> + <code>start_date</code> / <code>end_date</code> (<code>created_date</code> or <code>updated_date</code>)</li>
</ul>
<p>
Response is JSON <code>{ status: true, html: "…" }</code>; JS replaces <code>#claim_list_div</code>
and re-initializes the DataTable. Row click navigates to <code>/non-eb-claim/view/{id}</code>.
</p>
<p>
<strong>Add</strong> button: <code>window.location.href = '/non-eb-claim/new/50'</code>.
Header menu uses <code>/non-eb-claim/new</code> (routes to <code>claimForm/50</code>).
See <a href="#policy-type-50-default">Policy type 50</a> for why this id is fixed and what to change if a product needs its own statuses.
</p>
<h2 id="create-edit">Create and edit claim</h2>
<h3 id="create">Create</h3>
<ol>
<li><code>GET /non-eb-claim/new/{policy_type_id}</code> → <code>getFormData()</code>: ACMs (role 3), clients, insurers, initial claim status for product, visible sections.</li>
<li>User selects client → <code>POST getBranchAndPolicy</code> fills branch, policy (Non-EB/Marine only), branch contact.</li>
<li>Status change → <code>POST getVisibleSections</code> toggles accordion sections client-side.</li>
<li><code>POST /non-eb-claim/create</code> — validation via <code>getValidationRules()</code>, <code>sanitizeInputArrayAdvanced</code>, date normalization, optional asset file upload.</li>
<li>Duplicate guard: same <code>client_id</code> + <code>loss_date</code> + <code>policy_no</code> (if policy set) → HTTP 409-style JSON.</li>
<li>On success: insert <code>non_eb_ticket_master</code>, <code>saveAssets()</code>, history row, <code>sendAutoMailTrigger()</code>, redirect to list.</li>
</ol>
<h3 id="edit">View / edit</h3>
<p>
<code>view_claim($id)</code> loads ticket via <code>NonEbTicketMasterModel::getTicketDataByTicketID()</code>,
merges mail template preview (<code>getTemplateDataByTicketID</code> + placeholder replace),
messages, history, assets, and reuses the edit view <code>non_eb_claim_edit.php</code>.
</p>
<p>
<code>POST /non-eb-claim/update</code> mirrors create validation. If <code>claim_status_id</code> changes,
auto-mail runs again. <code>remark_mode=append</code> appends to <code>closure_remark</code> with a separator.
</p>
<h2 id="status-sections">Status-driven sections</h2>
<p>
<code>$statusSectionVisibility</code> in the controller maps each <code>ticket_claim_status.claim_status</code>
label to section keys: <code>policy_account</code>, <code>loss_incident</code>, <code>intimation</code>,
<code>insured_contact</code>, <code>asset</code>, <code>documents</code>, <code>surveyor</code>, <code>settlement</code>.
</p>
<p>
Allowed next statuses come from <code>getClaimStatusForPolicyType()</code>: current status plus IDs in
<code>allowed_status</code> JSON on the status row. Both create and edit forms call
<code>getVisibleSectionsAjax</code> when the user changes status.
</p>
<h2 id="auto-mail">Auto-mail and placeholders</h2>
<p>Template lookup (<code>NonEbTicketMasterModel::getTemplateDataByTicketID</code>):</p>
<ul>
<li>Join <code>ticket_claim_status</code> on tickets <code>claim_status_id</code> (or explicit <code>status_id</code> for tests).</li>
<li>Join <code>ticket_mail_template</code> where <code>ticket_type = policy_type_id</code> AND <code>trigger_type = tcs.trigger_type</code>.</li>
</ul>
<p>
<code>sendAutoMailTrigger($ticket_id)</code> sends only when the matched template has
<code>is_auto_mail = 1</code>. Mail goes to <code>insured_contact_email</code> from
<code>constructMailContent()</code>; from address <code>claims@nhanceindia.in</code> via <code>MailHelper::send_email()</code>.
Successful sends insert a <code>ticket_messages</code> row via <code>autoMessageInsertBasedOnMailResponse()</code>.
</p>
<p>Placeholders (subject/body):</p>
<div class="docs-table-wrap">
<table>
<thead><tr><th>Token</th><th>Ticket field</th></tr></thead>
<tbody>
<tr><td><code>((ACM))</code></td><td><code>acm</code></td></tr>
<tr><td><code>((ACM_CONTACT))</code></td><td><code>acm_mobile</code></td></tr>
<tr><td><code>((INSURED_NAME))</code></td><td><code>insured_contact_name</code></td></tr>
<tr><td><code>((CORPORATE_NAME))</code></td><td><code>client_name</code></td></tr>
<tr><td><code>((CLAIM_NO))</code></td><td><code>claim_number</code></td></tr>
<tr><td><code>((POLICY_TYPE))</code></td><td><code>policy_type_name</code></td></tr>
<tr><td><code>((NHANCE_REF_NO))</code></td><td><code>nhance_claim_ref_no</code></td></tr>
<tr><td><code>((LOSS_DATE))</code></td><td><code>loss_date</code></td></tr>
<tr><td><code>((LOSS_LOCATION))</code></td><td><code>loss_location</code></td></tr>
<tr><td><code>((NATURE_OF_LOSS))</code></td><td><code>nature_of_loss</code></td></tr>
</tbody>
</table>
</div>
<p>
Edit screen also supports <strong>manual reply</strong>: <code>POST /non-eb-claim/reply</code> validates To/Subject,
inserts <code>ticket_messages</code>, sends via <code>sendReplyMessage()</code> with placeholder replacement.
</p>
<h2 id="mail-template-crud">Mail template CRUD</h2>
<p>
Page: <code>GET /non-eb-claim/mail_template</code>. DataTable lists rows from
<code>ticket_mail_template</code> (<code>is_active = 1</code>). Tooltip on each row shows the
matching <code>ticket_claim_status.claim_status</code> for that policy type + trigger type.
</p>
<div class="mermaid-wrapper">
<div class="mermaid">
flowchart LR
UI["mail_template UI"] --> S1["POST crud_mail_template/1 Save"]
UI --> S2["POST crud_mail_template/2 Fetch"]
UI --> S3["POST crud_mail_template/3 Delete"]
S1 --> DB["ticket_mail_template"]
S2 --> DB
S3 --> DB
</div>
</div>
<h3 id="template-fields">Template fields</h3>
<ul>
<li><code>template_name</code>, <code>ticket_type</code> (policy type id), <code>trigger_type</code> (19)</li>
<li><code>subject</code>, <code>mail_content</code> (Jodit HTML)</li>
<li><code>is_auto_mail</code> — checkbox “Auto Mail” (1 = send on create / status change when matched)</li>
<li>Optional <code>id</code> on save for update</li>
</ul>
<p>
<strong>Trigger ↔ status:</strong> Each <code>ticket_claim_status</code> row for a Non-EB/Marine
<code>ticket_type</code> has a <code>trigger_type</code>. The templates <code>trigger_type</code> must match
that column for auto-mail and for the “Claim Status” readonly hint (<code>tool_tip</code> from server on fetch).
</p>
<h3 id="template-actions">UI actions</h3>
<div class="docs-table-wrap docs-table-wrap--fluid">
<table>
<thead>
<tr><th>Action</th><th>Endpoint</th><th>Body</th><th>Result</th></tr>
</thead>
<tbody>
<tr><td>Add / Save</td><td><code>POST …/crud_mail_template/1</code></td><td>Form fields + <code>mail_content</code> + <code>is_auto_mail</code></td><td><code>{ status: bool }</code> → reload</td></tr>
<tr><td>Edit load</td><td><code>POST …/crud_mail_template/2</code></td><td><code>id</code></td><td><code>{ status, data }</code> opens modal</td></tr>
<tr><td>Delete</td><td><code>POST …/crud_mail_template/3</code></td><td><code>id</code></td><td>Soft delete (<code>is_active = 0</code>)</td></tr>
</tbody>
</table>
</div>
<p>
Placeholder dropdown in the modal inserts tokens into subject (focused input) or Jodit body.
Validation errors return HTTP 400 with <code>errors</code> map (shown via toastr).
</p>
<h2 id="notes">Notes</h2>
<p>On the edit screen:</p>
<ul>
<li><code>POST /non-eb-claim/note/1</code> — <code>id</code> (ticket), optional <code>is_auto_query</code> → fetch active note.</li>
<li><code>POST /non-eb-claim/note/2</code> — save note (required 31000 chars) via <code>TicketNoteModel</code>.</li>
</ul>
<h2 id="documents">Documents and IR checklist</h2>
<ul>
<li><code>uploadFile</code> — multi upload to <code>writable/uploads/claim_files/</code> or Google Drive URLs (<code>file_type</code> 1 vs 2).</li>
<li><code>getClaimFiles</code> — lists rows; local files expose download URL <code>downloadClaimFile/{id}</code>.</li>
<li><code>removeFile</code> — soft delete by file id.</li>
<li><code>saveIRDocs</code> — stores JSON in <code>non_eb_ticket_master.required_docs</code>.</li>
<li>Asset spreadsheet on ticket: <code>asset_file</code> under <code>writable/uploads/non_eb_asset_files/</code>; loss description required when file uploaded.</li>
</ul>
<h2 id="reports">Reports</h2>
<p>
<code>GET /non-eb-claim/reports</code> renders filters: policy type, ACM name, date range (default last 60 days).
<code>generateReport()</code> in the view POSTs to the same URL and expects
<code>{ status: true, data: [ rows ] }</code> for DataTable columns (status, policy type, claim/ref, client, insurer, loss fields, surveyor, settlement, ACM, created date).
</p>
<p>
<strong>Gap:</strong> <code>NonEbClaimController::claimReports()</code> only handles GET (layout load).
There is no POST handler to return report data — Generate Report will fail until POST logic is added
(mirror EB <code>ticket_reports</code> or reuse <code>claimSearch</code> with report-specific selects).
</p>
<h2 id="data-model">Data model (summary)</h2>
<table>
<thead><tr><th>Table</th><th>Role</th></tr></thead>
<tbody>
<tr><td><code>non_eb_ticket_master</code></td><td>Main claim ticket</td></tr>
<tr><td><code>non_eb_claim_asset</code></td><td>Repeating asset lines per ticket</td></tr>
<tr><td><code>ticket_claim_status</code></td><td>Statuses per <code>ticket_type</code> (policy type id); <code>trigger_type</code>, <code>allowed_status</code></td></tr>
<tr><td><code>ticket_mail_template</code></td><td>Templates; <code>ticket_type</code> = policy type id</td></tr>
<tr><td><code>ticket_history</code></td><td>Field-level audit (status, ACM, priority, …)</td></tr>
<tr><td><code>ticket_messages</code></td><td>Outbound mail log</td></tr>
<tr><td><code>ticket_notes</code></td><td>User notes per ticket</td></tr>
<tr><td><code>claim_files</code></td><td>Attachments; <code>ticket_type = 2</code> for Non-EB</td></tr>
</tbody>
</table>
<h2 id="controller-reference">Controller reference</h2>
<div class="docs-table-wrap docs-table-wrap--fluid">
<table>
<thead><tr><th>Method</th><th>Used for</th></tr></thead>
<tbody>
<tr><td><code>claimList</code> / <code>claimSearch</code></td><td>List UI and filtered HTML</td></tr>
<tr><td><code>claimForm</code> / <code>getFormData</code></td><td>New claim form bootstrap</td></tr>
<tr><td><code>view_claim</code></td><td>Edit view</td></tr>
<tr><td><code>createClaim</code> / <code>updateClaim</code></td><td>Persist ticket</td></tr>
<tr><td><code>getClaimStatusForPolicyType</code> / <code>getVisibleSections*</code></td><td>Status dropdown + sections</td></tr>
<tr><td><code>mailTemplate</code> / <code>crudTemplate</code></td><td>Template admin</td></tr>
<tr><td><code>sendAutoMailTrigger</code> / <code>constructMailContent</code></td><td>Automated email</td></tr>
<tr><td><code>saveReply</code> / <code>getTicketMessage</code></td><td>Manual email thread</td></tr>
<tr><td><code>crudNote</code></td><td>Notes</td></tr>
<tr><td><code>uploadFile</code> / <code>getClaimFiles</code> / <code>removeFile</code> / <code>saveIRDocs</code></td><td>Documents</td></tr>
<tr><td><code>saveAssets</code> / <code>getAssets</code></td><td>Asset grid</td></tr>
<tr><td><code>claimHistory</code> / <code>putHistoryAfterInsert</code></td><td>Audit trail</td></tr>
<tr><td><code>getBranchAndPolicyByClientID</code></td><td>Client cascade</td></tr>
<tr><td><code>claimReports</code></td><td>Reports page (GET only today)</td></tr>
<tr><td><code>testAutoMailTrigger</code></td><td>Dev preview/send test</td></tr>
</tbody>
</table>
</div>
<h2 id="developer-steps">Developer checklist</h2>
<ol>
<li>Ensure <code>ticket_claim_status</code> rows exist per Non-EB/Marine <code>policy_type.id</code> with correct <code>trigger_type</code> and <code>allowed_status</code>.</li>
<li>Create mail templates at <code>/non-eb-claim/mail_template</code> with matching <code>ticket_type</code> + <code>trigger_type</code>; enable Auto Mail only where intended.</li>
<li>Verify insured email is present before relying on auto-mail.</li>
<li>Before changing Add/new URLs: read <a href="#policy-type-50-default">Policy type 50</a> — clone statuses + templates in DB and update every hardcoded <code>50</code> if a product needs its own workflow.</li>
<li>Implement POST branch in <code>claimReports()</code> if reports Generate must work.</li>
<li>Claim files: always set <code>ticket_type = 2</code> in new file-related code paths.</li>
<li>ACL: extend <code>#^/non-eb-claim#</code> if new roles need access.</li>
</ol>
<h2 id="pitfalls">Common pitfalls</h2>
<ul>
<li><strong>Template mismatch:</strong> No row in <code>ticket_mail_template</code> for policy type + status <code>trigger_type</code> → no auto-mail and empty reply preview.</li>
<li><strong>Reports POST missing:</strong> UI POSTs to <code>/non-eb-claim/reports</code> but controller only loads view on GET.</li>
<li><strong>Duplicate claims:</strong> Same client + loss date + policy number blocked on create.</li>
<li><strong>Policy type 50 assumption:</strong> Shared status catalog under DB <code>ticket_type = 50</code>; Add/new routes and hidden form field use <code>50</code> — not the policy picked on the form. Different per-product statuses require full backend + frontend changes — <a href="#policy-type-50-future">checklist</a>.</li>
<li><strong>Menu vs Non-EB templates:</strong> Sidebar “Mail Template” points to EB <code>/ticket/mail_template</code>, not Non-EB.</li>
<li><strong>Soft deletes:</strong> Remove claim/file/template sets <code>is_active = 0</code>; list queries filter active only.</li>
<li><strong>Asset file:</strong> Upload without loss description fails validation on create/update.</li>
<li><strong>REST API separate:</strong> Mobile create/list under <code>employeeRest</code> / <code>Api\NonEbClaimApiController</code> — different validation and flows.</li>
</ul>