1064 lines
49 KiB
PHP
1064 lines
49 KiB
PHP
<?php
|
|
$quote = $quote ?? null;
|
|
$quoteId = $quote_id ?? ($quote['id'] ?? null);
|
|
$vehicle = $quote['vehicle'] ?? [];
|
|
$kyc = $quote['kyc'] ?? [];
|
|
$payment = $quote['payment'] ?? [];
|
|
$policy = $quote['policy'] ?? [];
|
|
$status = $quote['status'] ?? 'DRAFT';
|
|
$policyholder = $policyholder ?? ($quote['policyholder_details'] ?? []);
|
|
if (!is_array($policyholder)) {
|
|
$policyholder = [];
|
|
}
|
|
$vehicleMaster = $vehicle_master ?? null;
|
|
|
|
$statusToStep = [
|
|
'DRAFT' => 0,
|
|
'QUOTED' => 1,
|
|
'CREATED' => 2,
|
|
'KYC_DONE' => 3,
|
|
'PAID' => 4,
|
|
'EFFECTIVE' => 4,
|
|
];
|
|
$initialStep = $statusToStep[$status] ?? 0;
|
|
$coverage = is_array($quote['coverage_details'] ?? null) ? $quote['coverage_details'] : [];
|
|
// Normalize addon flags from either UI-shaped or Digit-shaped coverage JSON
|
|
$addonOn = [
|
|
'personal_accident' => !empty($coverage['personal_accident']) || !empty($coverage['personalAccident']['selection']),
|
|
'zero_dep' => !empty($coverage['zero_dep']) || !empty($coverage['addons']['partsDepreciation']['selection']),
|
|
'engine_protect' => !empty($coverage['engine_protect']) || !empty($coverage['addons']['engineProtection']['selection']),
|
|
'rsa' => !empty($coverage['rsa']) || !empty($coverage['addons']['roadSideAssistance']['selection']),
|
|
'consumables' => !empty($coverage['consumables']) || !empty($coverage['addons']['consumables']['selection']),
|
|
'key_protect' => !empty($coverage['key_protect']) || !empty($coverage['addons']['keyAndLockProtect']['selection']),
|
|
];
|
|
if ($coverage === []) {
|
|
$addonOn['personal_accident'] = true; // default matches chip markup
|
|
}
|
|
?>
|
|
<style>
|
|
:root{
|
|
--dm-teal:#02a8b5;
|
|
--dm-teal-dark:#028a95;
|
|
--dm-teal-soft:#e7f6f7;
|
|
--dm-ink:#1B1D23;
|
|
--dm-muted:#6B6A63;
|
|
--dm-line:#DEDBD2;
|
|
--dm-paper:#F7F5F0;
|
|
--dm-green:#1F7A4D;
|
|
--dm-green-bg:#E4F2EA;
|
|
--dm-steel:#35577A;
|
|
--dm-steel-bg:#E7EEF4;
|
|
--dm-red:#C43D3D;
|
|
--dm-red-bg:#FBEAEA;
|
|
}
|
|
.dm-page{width:100%;padding:24px 8px 24px;}
|
|
.dm-toolbar{
|
|
display:flex;justify-content:space-between;align-items:center;
|
|
margin:12px 0 16px;padding-top:8px;gap:12px;flex-wrap:wrap;
|
|
position:relative;z-index:2;
|
|
}
|
|
.dm-back{
|
|
display:inline-flex;align-items:center;gap:6px;
|
|
color:var(--dm-teal-dark)!important;font-weight:600;font-size:14px;text-decoration:none!important;
|
|
}
|
|
.dm-back:hover{color:var(--dm-teal)!important;}
|
|
.dm-enquiry{font-size:12px;color:var(--dm-muted);}
|
|
.dm-enquiry strong{
|
|
display:inline-block;margin-left:6px;font-family:monospace;font-size:13px;color:var(--dm-teal-dark);font-weight:600;
|
|
}
|
|
|
|
/* Progress stepper — compact */
|
|
.dm-route-wrap{
|
|
background:linear-gradient(135deg,#026a72 0%,#02a8b5 100%);
|
|
padding:12px 20px 14px;border-radius:10px;margin-bottom:14px;
|
|
}
|
|
.dm-route{position:relative;height:48px;width:100%;}
|
|
.dm-road{
|
|
position:absolute;top:14px;left:28px;right:28px;height:3px;
|
|
background:rgba(255,255,255,.22);border-radius:2px;z-index:1;
|
|
}
|
|
.dm-fill{
|
|
position:absolute;top:14px;left:28px;height:3px;
|
|
background:#fff;border-radius:2px;width:0;z-index:1;
|
|
transition:width .45s ease, left .45s ease;
|
|
}
|
|
.dm-stops{
|
|
position:absolute;top:0;left:0;right:0;bottom:0;
|
|
display:flex;justify-content:space-between;align-items:flex-start;z-index:2;
|
|
}
|
|
.dm-stop{flex:0 0 auto;width:64px;text-align:center;cursor:pointer;}
|
|
.dm-dot{
|
|
width:22px;height:22px;border-radius:50%;
|
|
background:#026a72;border:2px solid rgba(255,255,255,.55);
|
|
margin:4px auto 0;display:flex;align-items:center;justify-content:center;
|
|
color:rgba(255,255,255,.7);font-size:11px;transition:all .2s;position:relative;z-index:3;
|
|
}
|
|
.dm-stop.done .dm-dot{background:#fff;border-color:#fff;color:var(--dm-teal-dark);}
|
|
.dm-stop.active .dm-dot{
|
|
background:#fff;border-color:#fff;color:var(--dm-teal-dark);
|
|
box-shadow:0 0 0 3px rgba(255,255,255,.28);
|
|
}
|
|
.dm-stop-label{
|
|
margin-top:4px;font-size:11px;color:rgba(255,255,255,.7);white-space:nowrap;font-weight:500;line-height:1.2;
|
|
}
|
|
.dm-stop.active .dm-stop-label,.dm-stop.done .dm-stop-label{color:#fff;font-weight:600;}
|
|
|
|
.dm-panel{
|
|
background:#fff;border:1px solid var(--dm-line);border-radius:12px;padding:28px 28px 24px;position:relative;
|
|
box-shadow:0 4px 16px rgba(2,168,181,.06);
|
|
}
|
|
.dm-panel-head{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:20px;}
|
|
.dm-eyebrow{font-size:11px;color:var(--dm-teal-dark);text-transform:uppercase;letter-spacing:.08em;font-weight:600;margin-bottom:6px;}
|
|
.dm-title{font-size:20px;font-weight:600;color:var(--dm-ink);}
|
|
.dm-desc{font-size:13px;color:var(--dm-muted);margin-top:6px;max-width:640px;line-height:1.5;}
|
|
.dm-index{font-family:monospace;font-size:32px;color:#d9ecee;font-weight:500;}
|
|
.dm-step{display:none;}
|
|
.dm-step.active{display:block;}
|
|
|
|
.dm-section{
|
|
font-size:11px;color:var(--dm-muted);text-transform:uppercase;letter-spacing:.06em;font-weight:600;
|
|
margin:22px 0 12px;padding-top:16px;border-top:1px solid var(--dm-line);
|
|
}
|
|
.dm-section:first-of-type{margin-top:0;padding-top:0;border-top:none;}
|
|
.dm-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:14px 16px;}
|
|
.dm-grid.g3{grid-template-columns:repeat(3,1fr);}
|
|
.dm-grid.g4{grid-template-columns:repeat(4,1fr);}
|
|
.dm-field{display:flex;flex-direction:column;gap:6px;}
|
|
.dm-field.full{grid-column:1/-1;}
|
|
.dm-field.span2{grid-column:span 2;}
|
|
.dm-field label{font-size:12px;color:var(--dm-muted);font-weight:500;margin:0;}
|
|
.dm-field label .req{color:var(--dm-red);margin-left:2px;font-weight:700;}
|
|
.dm-field input,.dm-field select{
|
|
height:38px;border:1px solid var(--dm-line);border-radius:8px;padding:0 12px;font-size:13.5px;
|
|
background:var(--dm-paper);outline:none;width:100%;
|
|
}
|
|
.dm-field input.dm-invalid,.dm-field select.dm-invalid{
|
|
border-color:var(--dm-red)!important;background:#fff5f5;
|
|
}
|
|
.dm-field .dm-err{
|
|
display:none;font-size:11px;color:var(--dm-red);margin-top:2px;
|
|
}
|
|
.dm-field.has-error .dm-err{display:block;}
|
|
|
|
.dm-field input:focus,.dm-field select:focus{border-color:var(--dm-teal);background:#fff;}
|
|
|
|
.dm-chips{display:flex;gap:8px;flex-wrap:wrap;}
|
|
.dm-chip{
|
|
padding:7px 14px;border:1px solid var(--dm-line);border-radius:20px;font-size:12.5px;cursor:pointer;
|
|
color:var(--dm-muted);user-select:none;background:#fff;transition:all .15s;
|
|
}
|
|
.dm-chip.on{background:var(--dm-teal);border-color:var(--dm-teal);color:#fff;}
|
|
|
|
.dm-actions{display:flex;justify-content:space-between;align-items:center;margin-top:26px;padding-top:18px;border-top:1px solid var(--dm-line);}
|
|
.dm-btn{
|
|
height:40px;padding:0 18px;border-radius:8px;font-size:13.5px;font-weight:500;cursor:pointer;
|
|
border:1px solid var(--dm-line);background:#fff;color:var(--dm-ink);display:inline-flex;align-items:center;gap:6px;
|
|
}
|
|
.dm-btn.primary{background:var(--dm-teal);border-color:var(--dm-teal);color:#fff;}
|
|
.dm-btn.primary:hover{background:var(--dm-teal-dark);}
|
|
.dm-btn.ghost{border-color:transparent;color:var(--dm-muted);}
|
|
.dm-btn:disabled{opacity:.45;cursor:not-allowed;}
|
|
|
|
.dm-quote-cards{display:grid;grid-template-columns:1fr 1fr;gap:14px;}
|
|
.dm-quote-card{border:1px solid var(--dm-line);border-radius:12px;padding:18px;cursor:pointer;position:relative;}
|
|
.dm-quote-card.selected{border:2px solid var(--dm-teal);padding:17px;background:var(--dm-teal-soft);}
|
|
.dm-quote-card .tag{font-size:11px;color:var(--dm-muted);text-transform:uppercase;letter-spacing:.05em;}
|
|
.dm-quote-card .amount{font-size:24px;font-weight:600;margin:8px 0 2px;color:var(--dm-ink);}
|
|
.dm-quote-card .idv{font-size:12px;color:var(--dm-muted);}
|
|
.dm-check{
|
|
position:absolute;top:14px;right:14px;width:20px;height:20px;border-radius:50%;
|
|
background:var(--dm-teal);color:#fff;display:none;align-items:center;justify-content:center;font-size:11px;
|
|
}
|
|
.dm-quote-card.selected .dm-check{display:flex;}
|
|
|
|
.dm-status{border:1px solid var(--dm-line);border-radius:12px;padding:18px;display:flex;align-items:center;gap:14px;}
|
|
.dm-icon{width:42px;height:42px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0;}
|
|
.dm-icon.ok{background:var(--dm-green-bg);color:var(--dm-green);}
|
|
.dm-icon.wait{background:var(--dm-steel-bg);color:var(--dm-steel);}
|
|
.dm-icon.warn{background:var(--dm-red-bg);color:var(--dm-red);}
|
|
.dm-st-title{font-weight:600;font-size:14.5px;}
|
|
.dm-st-sub{font-size:12.5px;color:var(--dm-muted);margin-top:3px;}
|
|
.dm-pill{display:inline-block;padding:3px 10px;border-radius:20px;font-size:11px;font-weight:600;}
|
|
.dm-pill.ok{background:var(--dm-green-bg);color:var(--dm-green);}
|
|
.dm-pill.wait{background:var(--dm-steel-bg);color:var(--dm-steel);}
|
|
.dm-ref{width:100%;border-collapse:collapse;margin-top:16px;}
|
|
.dm-ref tr{border-top:1px solid var(--dm-line);}
|
|
.dm-ref tr:first-child{border-top:none;}
|
|
.dm-ref td{padding:10px 0;font-size:13px;}
|
|
.dm-ref td:first-child{color:var(--dm-muted);width:44%;}
|
|
.dm-ref td:last-child{text-align:right;font-family:monospace;}
|
|
.dm-doc{display:flex;align-items:center;justify-content:space-between;border:1px solid var(--dm-line);border-radius:10px;padding:12px 14px;margin-top:10px;}
|
|
.dm-alert{display:none;margin-bottom:14px;padding:10px 14px;border-radius:8px;font-size:13px;}
|
|
.dm-alert.error{display:block;background:var(--dm-red-bg);color:var(--dm-red);}
|
|
.dm-alert.ok{display:block;background:var(--dm-green-bg);color:var(--dm-green);}
|
|
.dm-loading{opacity:.55;pointer-events:none;}
|
|
.dm-suggest-wrap{position:relative;}
|
|
.dm-suggest{
|
|
position:absolute;left:0;right:0;top:100%;z-index:20;margin-top:4px;
|
|
background:#fff;border:1px solid var(--dm-line);border-radius:8px;
|
|
max-height:220px;overflow:auto;box-shadow:0 8px 20px rgba(0,0,0,.08);display:none;
|
|
}
|
|
.dm-suggest.open{display:block;}
|
|
.dm-suggest button{
|
|
display:block;width:100%;text-align:left;border:0;background:#fff;padding:8px 12px;
|
|
font-size:12.5px;color:var(--dm-ink);cursor:pointer;border-bottom:1px solid var(--dm-line);
|
|
}
|
|
.dm-suggest button:hover{background:var(--dm-teal-soft);}
|
|
.dm-suggest .meta{color:var(--dm-muted);font-size:11px;}
|
|
.dm-vcode-tag{font-family:monospace;font-size:12px;color:var(--dm-teal-dark);margin-top:4px;}
|
|
@media(max-width:768px){
|
|
.dm-grid,.dm-grid.g3,.dm-grid.g4,.dm-quote-cards{grid-template-columns:1fr;}
|
|
.dm-stop{width:52px;}
|
|
.dm-stop-label{font-size:10px;}
|
|
.dm-road{left:22px;right:22px;}
|
|
.dm-route{height:44px;}
|
|
}
|
|
</style>
|
|
|
|
<div class="container-fluid dm-page">
|
|
<div class="dm-toolbar">
|
|
<a href="<?= base_url('digit-motor/list') ?>" class="dm-back">
|
|
<i class="mdi mdi-arrow-left"></i> Back to list
|
|
</a>
|
|
<div class="dm-enquiry">Enquiry ID <strong id="enquiryIdTag"><?= esc($quote['enquiry_id'] ?? '— new —') ?></strong></div>
|
|
</div>
|
|
|
|
<div class="dm-route-wrap">
|
|
<div class="dm-route" id="dmRoute">
|
|
<div class="dm-road"></div>
|
|
<div class="dm-fill" id="dmFill"></div>
|
|
<div class="dm-stops" id="dmStops"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="dm-panel" id="dmPanel">
|
|
<div id="dmAlert" class="dm-alert"></div>
|
|
|
|
<!-- Step 0: Quick Quote -->
|
|
<div class="dm-step active" data-step="0">
|
|
<div class="dm-panel-head">
|
|
<div>
|
|
<div class="dm-eyebrow">Step 1 of 5 · quick quote</div>
|
|
<div class="dm-title">Vehicle and coverage details</div>
|
|
<div class="dm-desc">Enter the vehicle to fetch an indicative premium before creating the policy quote.</div>
|
|
</div>
|
|
<div class="dm-index">01</div>
|
|
</div>
|
|
|
|
<div class="dm-section">Vehicle</div>
|
|
<div class="dm-grid g4">
|
|
<div class="dm-field"><label>Registration number <span class="req">*</span></label><input id="f_reg" value="<?= esc($vehicle['license_plate_number'] ?? '') ?>" placeholder="GJ04DA8726" data-required="1" data-label="Registration number"><div class="dm-err">Required</div></div>
|
|
<div class="dm-field">
|
|
<label>Make <span class="req">*</span></label>
|
|
<div class="dm-suggest-wrap">
|
|
<input id="f_make" placeholder="Search make..." autocomplete="off" data-required="1" data-label="Make">
|
|
<div class="dm-suggest" id="sug_make"></div>
|
|
</div>
|
|
<div class="dm-err">Required</div>
|
|
</div>
|
|
<div class="dm-field">
|
|
<label>Model <span class="req">*</span></label>
|
|
<select id="f_model" disabled data-required="1" data-label="Model"><option value="">Select make first</option></select>
|
|
<div class="dm-err">Required</div>
|
|
</div>
|
|
<div class="dm-field">
|
|
<label>Variant / vehicle code <span class="req">*</span></label>
|
|
<select id="f_variant" disabled data-required="1" data-label="Variant / vehicle code"><option value="">Select model first</option></select>
|
|
<div class="dm-vcode-tag" id="f_vcode_tag"><?= esc($vehicle['vehicle_maincode'] ?? '') ?></div>
|
|
<input type="hidden" id="f_vcode" value="<?= esc($vehicle['vehicle_maincode'] ?? '') ?>" data-required="1" data-label="Vehicle code">
|
|
<div class="dm-err">Required</div>
|
|
</div>
|
|
<div class="dm-field"><label>Or search vehicle code</label>
|
|
<div class="dm-suggest-wrap">
|
|
<input id="f_vsearch" placeholder="Type code / make / model..." autocomplete="off">
|
|
<div class="dm-suggest" id="sug_vsearch"></div>
|
|
</div>
|
|
</div>
|
|
<div class="dm-field"><label>Registration date <span class="req">*</span></label><input type="date" id="f_reg_date" value="<?= esc($vehicle['registration_date'] ?? '') ?>" data-required="1" data-label="Registration date"><div class="dm-err">Required</div></div>
|
|
<div class="dm-field"><label>Manufacture date <span class="req">*</span></label><input type="date" id="f_mfg_date" value="<?= esc($vehicle['manufacture_date'] ?? '') ?>" data-required="1" data-label="Manufacture date"><div class="dm-err">Required</div></div>
|
|
<div class="dm-field"><label>Chassis / VIN <span class="req">*</span></label><input id="f_vin" value="<?= esc($vehicle['vehicle_identification_number'] ?? '') ?>" data-required="1" data-label="Chassis / VIN" minlength="5" placeholder="e.g. MAKGM651CJ4306951"><div class="dm-err">Required</div></div>
|
|
<div class="dm-field"><label>Engine number <span class="req">*</span></label><input id="f_engine" value="<?= esc($vehicle['engine_number'] ?? '') ?>" data-required="1" data-label="Engine number" minlength="5" placeholder="e.g. L15Z15337915"><div class="dm-err">Required</div></div>
|
|
<div class="dm-field"><label>Pincode <span class="req">*</span></label><input id="f_pin" value="<?= esc($quote['pincode'] ?? '') ?>" maxlength="6" data-required="1" data-label="Pincode" data-len="6"><div class="dm-vcode-tag" id="f_pin_tag"></div><div class="dm-err">Required (6 digits)</div></div>
|
|
<div class="dm-field"><label>Product code <span class="req">*</span></label>
|
|
<select id="f_product" data-required="1" data-label="Product code"><option value="">Loading products...</option></select>
|
|
<div class="dm-err">Required</div>
|
|
</div>
|
|
<div class="dm-field"><label>Policy start</label><input type="date" id="f_start" value="<?= esc($quote['start_date'] ?? '') ?>"></div>
|
|
</div>
|
|
|
|
<div class="dm-section">Previous policy</div>
|
|
<div class="dm-grid g4">
|
|
<div class="dm-field"><label>Previous insurer</label>
|
|
<select id="f_prev_ins"><option value="">— none / unknown —</option></select>
|
|
</div>
|
|
<div class="dm-field"><label>Prior policy expiry</label><input type="date" id="f_prev_exp" value="<?= esc($quote['previous_policy_expiry_date'] ?? '') ?>"></div>
|
|
<div class="dm-field"><label>Previous NCB</label>
|
|
<select id="f_prev_ncb"><option value="ZERO">ZERO</option></select>
|
|
</div>
|
|
<div class="dm-field"><label>Previous policy type</label>
|
|
<select id="f_prev_ptype"><option value="">— optional —</option></select>
|
|
</div>
|
|
<div class="dm-field"><label>Claim in last year</label>
|
|
<div class="dm-chips" style="height:38px;align-items:center;">
|
|
<div class="dm-chip" data-group="claim" data-val="1" onclick="dmToggleExclusive(this)">Yes</div>
|
|
<div class="dm-chip on" data-group="claim" data-val="0" onclick="dmToggleExclusive(this)">No</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="dm-section">Coverage add-ons</div>
|
|
<div class="dm-chips" id="addonChips">
|
|
<div class="dm-chip<?= !empty($addonOn['personal_accident']) ? ' on' : '' ?>" data-key="personal_accident" onclick="this.classList.toggle('on')">Personal accident</div>
|
|
<div class="dm-chip<?= !empty($addonOn['zero_dep']) ? ' on' : '' ?>" data-key="zero_dep" onclick="this.classList.toggle('on')">Zero depreciation</div>
|
|
<div class="dm-chip<?= !empty($addonOn['engine_protect']) ? ' on' : '' ?>" data-key="engine_protect" onclick="this.classList.toggle('on')">Engine protect</div>
|
|
<div class="dm-chip<?= !empty($addonOn['rsa']) ? ' on' : '' ?>" data-key="rsa" onclick="this.classList.toggle('on')">Roadside assistance</div>
|
|
<div class="dm-chip<?= !empty($addonOn['consumables']) ? ' on' : '' ?>" data-key="consumables" onclick="this.classList.toggle('on')">Consumables</div>
|
|
<div class="dm-chip<?= !empty($addonOn['key_protect']) ? ' on' : '' ?>" data-key="key_protect" onclick="this.classList.toggle('on')">Key & lock</div>
|
|
</div>
|
|
|
|
<div class="dm-actions">
|
|
<span style="font-size:11.5px;color:var(--dm-muted);font-family:monospace;">POST · motorQuickQuote</span>
|
|
<button class="dm-btn primary" type="button" onclick="dmQuickQuote()">Get quote <i class="mdi mdi-arrow-right"></i></button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 1: Create Quote -->
|
|
<div class="dm-step" data-step="1">
|
|
<div class="dm-panel-head">
|
|
<div>
|
|
<div class="dm-eyebrow">Step 2 of 5 · create quote</div>
|
|
<div class="dm-title">Confirm premium plan</div>
|
|
<div class="dm-desc">Review the quick-quote premium, add policyholder details, then create the Digit quote.</div>
|
|
</div>
|
|
<div class="dm-index">02</div>
|
|
</div>
|
|
|
|
<div class="dm-quote-cards">
|
|
<div class="dm-quote-card selected" id="planCard">
|
|
<div class="dm-check"><i class="mdi mdi-check"></i></div>
|
|
<div class="tag">Quoted premium</div>
|
|
<div class="amount" id="planPremium">₹<?= isset($quote['premium']) ? number_format((float)$quote['premium'], 0) : '—' ?></div>
|
|
<div class="idv" id="planIdv">IDV ₹<?= isset($quote['idv']) ? number_format((float)$quote['idv'], 0) : '—' ?></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="dm-section">Vehicle identifiers</div>
|
|
<div class="dm-grid">
|
|
<div class="dm-field"><label>Chassis / VIN <span class="req">*</span></label><input id="f_cq_vin" value="<?= esc($vehicle['vehicle_identification_number'] ?? '') ?>" data-required="1" data-label="Chassis / VIN" minlength="5" placeholder="e.g. MAKGM651CJ4306951"><div class="dm-err">Required for create quote</div></div>
|
|
<div class="dm-field"><label>Engine number <span class="req">*</span></label><input id="f_cq_engine" value="<?= esc($vehicle['engine_number'] ?? '') ?>" data-required="1" data-label="Engine number" minlength="5" placeholder="e.g. L15Z15337915"><div class="dm-err">Required for create quote</div></div>
|
|
</div>
|
|
|
|
<div class="dm-section">Policyholder</div>
|
|
<div class="dm-grid g4">
|
|
<div class="dm-field"><label>First name <span class="req">*</span></label><input id="f_fname" value="<?= esc($policyholder['first_name'] ?? '') ?>" data-required="1" data-label="First name"><div class="dm-err">Required</div></div>
|
|
<div class="dm-field"><label>Last name</label><input id="f_lname" value="<?= esc($policyholder['last_name'] ?? '') ?>"></div>
|
|
<div class="dm-field"><label>Mobile <span class="req">*</span></label><input id="f_mobile" value="<?= esc($policyholder['mobile'] ?? '') ?>" data-required="1" data-label="Mobile" data-len="10"><div class="dm-err">Required (10 digits)</div></div>
|
|
<div class="dm-field"><label>Email <span class="req">*</span></label><input id="f_email" type="email" value="<?= esc($policyholder['email'] ?? '') ?>" data-required="1" data-label="Email"><div class="dm-err">Required</div></div>
|
|
<div class="dm-field"><label>PAN <span class="req">*</span></label><input id="f_pan" value="<?= esc($policyholder['pan'] ?? '') ?>" data-required="1" data-label="PAN"><div class="dm-err">Required</div></div>
|
|
<div class="dm-field"><label>Date of birth <span class="req">*</span></label><input type="date" id="f_dob" value="<?= esc($policyholder['dob'] ?? '') ?>" data-required="1" data-label="Date of birth"><div class="dm-err">Required</div></div>
|
|
<div class="dm-field span2"><label>Address <span class="req">*</span></label><input id="f_address" value="<?= esc($policyholder['address'] ?? '') ?>" data-required="1" data-label="Address"><div class="dm-err">Required</div></div>
|
|
</div>
|
|
|
|
<div class="dm-actions">
|
|
<button class="dm-btn ghost" type="button" onclick="dmGo(0)"><i class="mdi mdi-arrow-left"></i> Back</button>
|
|
<button class="dm-btn primary" type="button" onclick="dmCreateQuote()">Create quote <i class="mdi mdi-arrow-right"></i></button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 2: KYC -->
|
|
<div class="dm-step" data-step="2">
|
|
<div class="dm-panel-head">
|
|
<div>
|
|
<div class="dm-eyebrow">Step 3 of 5 · KYC status</div>
|
|
<div class="dm-title">Identity verification</div>
|
|
<div class="dm-desc">Poll KYC status before the payment link can be issued.</div>
|
|
</div>
|
|
<div class="dm-index">03</div>
|
|
</div>
|
|
|
|
<div class="dm-status" id="kycStatusCard">
|
|
<div class="dm-icon wait"><i class="mdi mdi-shield-check"></i></div>
|
|
<div>
|
|
<div class="dm-st-title" id="kycTitle"><?= esc($kyc['kyc_verification_status'] ?? 'Not checked') ?></div>
|
|
<div class="dm-st-sub" id="kycSub">Click refresh to fetch latest KYC status from Digit.</div>
|
|
</div>
|
|
<div class="ml-auto"><span class="dm-pill wait" id="kycPill"><?= esc($kyc['kyc_verification_status'] ?? 'Pending') ?></span></div>
|
|
</div>
|
|
|
|
<table class="dm-ref">
|
|
<tr><td>Quote number</td><td id="refQuoteNo"><?= esc($quote['quote_number'] ?? '—') ?></td></tr>
|
|
<tr><td>Application ID</td><td id="refAppId"><?= esc($quote['application_id'] ?? '—') ?></td></tr>
|
|
<tr><td>KYC reference</td><td id="refKycRef"><?= esc($kyc['reference_id'] ?? '—') ?></td></tr>
|
|
<tr><td>OVD link</td><td id="refKycLink"><?= !empty($kyc['link']) ? '<a href="'.esc($kyc['link']).'" target="_blank">Open</a>' : '—' ?></td></tr>
|
|
</table>
|
|
|
|
<div class="dm-actions">
|
|
<button class="dm-btn ghost" type="button" onclick="dmGo(1)"><i class="mdi mdi-arrow-left"></i> Back</button>
|
|
<div>
|
|
<button class="dm-btn" type="button" onclick="dmKycStatus()"><i class="mdi mdi-refresh"></i> Refresh KYC</button>
|
|
<button class="dm-btn primary" type="button" onclick="dmGo(3)">Proceed to payment <i class="mdi mdi-arrow-right"></i></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 3: Payment -->
|
|
<div class="dm-step" data-step="3">
|
|
<div class="dm-panel-head">
|
|
<div>
|
|
<div class="dm-eyebrow">Step 4 of 5 · payment</div>
|
|
<div class="dm-title">Collect premium</div>
|
|
<div class="dm-desc">Generates a Digit UI payment link for the customer to complete the transaction.</div>
|
|
</div>
|
|
<div class="dm-index">04</div>
|
|
</div>
|
|
|
|
<div class="dm-grid">
|
|
<div class="dm-field"><label>Premium amount</label><input id="payPremium" readonly value="<?= isset($quote['premium']) ? 'INR '.number_format((float)$quote['premium'], 2, '.', '') : '' ?>"></div>
|
|
<div class="dm-field"><label>Payment mode</label><input value="EB · Digit UI" readonly></div>
|
|
</div>
|
|
|
|
<div class="dm-status" style="margin-top:18px;" id="payStatusCard">
|
|
<div class="dm-icon wait"><i class="mdi mdi-link-variant"></i></div>
|
|
<div>
|
|
<div class="dm-st-title" id="payTitle"><?= !empty($payment['dispatcher_response']) ? 'Payment link ready' : 'No payment link yet' ?></div>
|
|
<div class="dm-st-sub" id="paySub"><?= esc($payment['digit_payment_id'] ?? 'Generate a link to continue') ?></div>
|
|
</div>
|
|
<div class="ml-auto">
|
|
<?php if (!empty($payment['dispatcher_response'])): ?>
|
|
<a class="dm-btn" id="payOpenBtn" href="<?= esc($payment['dispatcher_response']) ?>" target="_blank">Open link <i class="mdi mdi-open-in-new"></i></a>
|
|
<?php else: ?>
|
|
<a class="dm-btn" id="payOpenBtn" href="#" style="display:none;" target="_blank">Open link</a>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="dm-actions">
|
|
<button class="dm-btn ghost" type="button" onclick="dmGo(2)"><i class="mdi mdi-arrow-left"></i> Back</button>
|
|
<div>
|
|
<button class="dm-btn" type="button" onclick="dmPaymentLink()"><i class="mdi mdi-link-variant"></i> Generate link</button>
|
|
<button class="dm-btn primary" type="button" onclick="dmPolicyStatus(); dmGo(4);">Check policy status <i class="mdi mdi-arrow-right"></i></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 4: Policy -->
|
|
<div class="dm-step" data-step="4">
|
|
<div class="dm-panel-head">
|
|
<div>
|
|
<div class="dm-eyebrow">Step 5 of 5 · policy</div>
|
|
<div class="dm-title">Policy status & documents</div>
|
|
<div class="dm-desc">Confirm payment outcome, then download schedule and proposal PDFs.</div>
|
|
</div>
|
|
<div class="dm-index">05</div>
|
|
</div>
|
|
|
|
<div class="dm-status" id="policyStatusCard">
|
|
<div class="dm-icon <?= in_array(strtoupper($policy['policy_status'] ?? $status), ['EFFECTIVE','COMPLETE','COMPLETED']) ? 'ok' : 'wait' ?>">
|
|
<i class="mdi mdi-file-check"></i>
|
|
</div>
|
|
<div>
|
|
<div class="dm-st-title" id="polTitle">
|
|
<?= esc(($policy['policy_number'] ?? $quote['quote_number'] ?? 'Policy') . ' · ' . ($policy['policy_status'] ?? $status)) ?>
|
|
</div>
|
|
<div class="dm-st-sub" id="polSub">Refresh status after customer payment, then fetch PDFs.</div>
|
|
</div>
|
|
<div class="ml-auto"><span class="dm-pill <?= in_array(strtoupper($policy['policy_status'] ?? ''), ['EFFECTIVE','COMPLETE']) ? 'ok' : 'wait' ?>" id="polPill"><?= esc($policy['policy_status'] ?? $status) ?></span></div>
|
|
</div>
|
|
|
|
<div class="dm-section">Documents</div>
|
|
<div class="dm-doc">
|
|
<div><i class="mdi mdi-file-pdf-box text-danger"></i> Policy schedule</div>
|
|
<a class="dm-btn" id="dlSchedule" href="<?= esc($policy['schedule_path'] ?? '#') ?>" target="_blank" <?= empty($policy['schedule_path']) ? 'style="pointer-events:none;opacity:.4"' : '' ?>>Download</a>
|
|
</div>
|
|
<div class="dm-doc">
|
|
<div><i class="mdi mdi-file-pdf-box text-danger"></i> Proposal form</div>
|
|
<a class="dm-btn" id="dlProposal" href="<?= esc($policy['proposal_path'] ?? '#') ?>" target="_blank" <?= empty($policy['proposal_path']) ? 'style="pointer-events:none;opacity:.4"' : '' ?>>Download</a>
|
|
</div>
|
|
|
|
<div class="dm-actions">
|
|
<button class="dm-btn ghost" type="button" onclick="dmGo(3)"><i class="mdi mdi-arrow-left"></i> Back</button>
|
|
<div>
|
|
<button class="dm-btn" type="button" onclick="dmPolicyStatus()"><i class="mdi mdi-refresh"></i> Refresh status</button>
|
|
<button class="dm-btn primary" type="button" onclick="dmPolicyPdf()"><i class="mdi mdi-download"></i> Fetch PDFs</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
window.DM = {
|
|
quoteId: <?= $quoteId ? (int)$quoteId : 'null' ?>,
|
|
enquiryId: <?= json_encode($quote['enquiry_id'] ?? null) ?>,
|
|
base: '<?= rtrim(base_url('digit-motor'), '/') ?>',
|
|
step: <?= (int)$initialStep ?>,
|
|
selectedProduct: '<?= esc($quote['insurance_product_code'] ?? '20102') ?>',
|
|
selectedInsurer: '<?= esc($quote['previous_insurer_code'] ?? '') ?>',
|
|
selectedVehicleCode: '<?= esc($vehicle['vehicle_maincode'] ?? '') ?>',
|
|
vehicleMake: <?= json_encode($vehicleMaster['make'] ?? '') ?>,
|
|
vehicleModel: <?= json_encode($vehicleMaster['model'] ?? '') ?>,
|
|
vehicleVariant: <?= json_encode($vehicleMaster['variant'] ?? '') ?>,
|
|
busy: false
|
|
};
|
|
|
|
const dmSteps = ["Quote","Create","KYC","Pay","Policy"];
|
|
const dmIcons = ["mdi-car","mdi-file-plus","mdi-shield-check","mdi-credit-card","mdi-file-check"];
|
|
let dmMakeTimer = null;
|
|
let dmSearchTimer = null;
|
|
|
|
(function initRoute(){
|
|
const stops = document.getElementById('dmStops');
|
|
dmSteps.forEach((label,i)=>{
|
|
const el = document.createElement('div');
|
|
el.className = 'dm-stop';
|
|
el.dataset.i = i;
|
|
el.innerHTML = '<div class="dm-dot"><i class="mdi '+dmIcons[i]+'"></i></div><div class="dm-stop-label">'+label+'</div>';
|
|
el.onclick = ()=> dmGo(i);
|
|
stops.appendChild(el);
|
|
});
|
|
dmGo(window.DM.step, true);
|
|
dmLoadMasters();
|
|
dmBindMasterUi();
|
|
dmHydrateVehicle();
|
|
})();
|
|
|
|
function dmHydrateVehicle(){
|
|
const make = window.DM.vehicleMake || '';
|
|
const model = window.DM.vehicleModel || '';
|
|
const code = window.DM.selectedVehicleCode || '';
|
|
if (!code && !make) return;
|
|
|
|
if (make) {
|
|
$('#f_make').val(make);
|
|
dmLoadModels(make, model, code);
|
|
} else if (code) {
|
|
$('#f_vcode').val(code);
|
|
$('#f_vcode_tag').text('Code ' + code);
|
|
}
|
|
}
|
|
function dmFillSelect(sel, items, valueKey, labelFn, selected, emptyLabel){
|
|
const $s = $(sel);
|
|
$s.empty();
|
|
if (emptyLabel != null) {
|
|
$s.append($('<option>').val('').text(emptyLabel));
|
|
}
|
|
(items || []).forEach(function(item){
|
|
const val = typeof item === 'string' ? item : item[valueKey];
|
|
const label = typeof labelFn === 'function' ? labelFn(item) : val;
|
|
const opt = $('<option>').val(val).text(label);
|
|
if (selected != null && String(selected) === String(val)) opt.prop('selected', true);
|
|
$s.append(opt);
|
|
});
|
|
}
|
|
|
|
function dmLoadMasters(){
|
|
dmGet(window.DM.base + '/masters/bootstrap')
|
|
.done(function(res){
|
|
if (!res.status){
|
|
dmAlert(res.message || 'Masters not loaded');
|
|
return;
|
|
}
|
|
const d = res.data || {};
|
|
dmFillSelect('#f_product', d.products || [], 'product_code', function(p){
|
|
return p.product_code + ' · ' + p.product_name;
|
|
}, window.DM.selectedProduct, null);
|
|
|
|
dmFillSelect('#f_prev_ins', d.previous_insurers || [], 'insurer_code', function(p){
|
|
return p.insurer_code + ' · ' + p.insurer_name;
|
|
}, window.DM.selectedInsurer, '— none / unknown —');
|
|
|
|
dmFillSelect('#f_prev_ncb', d.ncb || [], 'ncb_code', function(p){ return p.ncb_code; }, 'ZERO', null);
|
|
|
|
dmFillSelect('#f_prev_ptype', d.previous_policy_types || [], 'policy_type_code', function(p){
|
|
return p.policy_type_code + (p.description ? ' · ' + p.description : '');
|
|
}, '', '— optional —');
|
|
})
|
|
.fail(function(){
|
|
dmAlert('Could not load Digit masters. Import with: php spark digit-motor:import-masters --create-tables');
|
|
});
|
|
}
|
|
|
|
function dmBindMasterUi(){
|
|
$('#f_make').on('input', function(){
|
|
const q = $(this).val().trim();
|
|
clearTimeout(dmMakeTimer);
|
|
if (q.length < 1){ $('#sug_make').removeClass('open').empty(); return; }
|
|
dmMakeTimer = setTimeout(function(){
|
|
dmGet(window.DM.base + '/masters/vehicles/makes?q=' + encodeURIComponent(q))
|
|
.done(function(res){
|
|
const box = $('#sug_make').empty();
|
|
(res.data || []).slice(0, 40).forEach(function(make){
|
|
$('<button type="button">').text(make).on('click', function(){
|
|
$('#f_make').val(make);
|
|
box.removeClass('open').empty();
|
|
dmLoadModels(make);
|
|
}).appendTo(box);
|
|
});
|
|
box.toggleClass('open', (res.data || []).length > 0);
|
|
});
|
|
}, 250);
|
|
});
|
|
|
|
$('#f_model').on('change', function(){
|
|
const make = $('#f_make').val().trim();
|
|
const model = $(this).val();
|
|
if (make && model) dmLoadVariants(make, model);
|
|
});
|
|
|
|
$('#f_variant').on('change', function(){
|
|
const code = $(this).val();
|
|
dmSetVehicleCode(code);
|
|
});
|
|
|
|
$('#f_vsearch').on('input', function(){
|
|
const q = $(this).val().trim();
|
|
clearTimeout(dmSearchTimer);
|
|
if (q.length < 2){ $('#sug_vsearch').removeClass('open').empty(); return; }
|
|
dmSearchTimer = setTimeout(function(){
|
|
dmGet(window.DM.base + '/masters/vehicles/search?q=' + encodeURIComponent(q))
|
|
.done(function(res){
|
|
const box = $('#sug_vsearch').empty();
|
|
(res.data || []).forEach(function(v){
|
|
const label = (v.make || '') + ' ' + (v.model || '') + ' ' + (v.variant || '');
|
|
$('<button type="button">').html(
|
|
'<div>'+label.trim()+'</div><div class="meta">'+v.vehicle_code+(v.fuel_type ? ' · '+v.fuel_type : '')+'</div>'
|
|
).on('click', function(){
|
|
$('#f_make').val(v.make || '');
|
|
dmSetVehicleCode(v.vehicle_code);
|
|
$('#f_vsearch').val(label.trim());
|
|
box.removeClass('open').empty();
|
|
dmLoadModels(v.make || '', v.model || '', v.vehicle_code);
|
|
}).appendTo(box);
|
|
});
|
|
box.toggleClass('open', (res.data || []).length > 0);
|
|
});
|
|
}, 300);
|
|
});
|
|
|
|
$('#f_pin').on('blur', function(){
|
|
const pin = $(this).val().trim();
|
|
if (pin.length !== 6){ $('#f_pin_tag').text(''); return; }
|
|
dmGet(window.DM.base + '/masters/pincode/' + pin)
|
|
.done(function(res){
|
|
if (res.status && res.data){
|
|
$('#f_pin_tag').text((res.data.city || '') + (res.data.district ? ', ' + res.data.district : ''));
|
|
} else {
|
|
$('#f_pin_tag').text('Pincode not in Digit master');
|
|
}
|
|
})
|
|
.fail(function(){ $('#f_pin_tag').text('Pincode not in Digit master'); });
|
|
});
|
|
|
|
$(document).on('click', function(e){
|
|
if (!$(e.target).closest('.dm-suggest-wrap').length){
|
|
$('.dm-suggest').removeClass('open');
|
|
}
|
|
});
|
|
}
|
|
|
|
function dmSetVehicleCode(code){
|
|
$('#f_vcode').val(code || '');
|
|
$('#f_vcode_tag').text(code || '');
|
|
window.DM.selectedVehicleCode = code || '';
|
|
}
|
|
|
|
function dmLoadModels(make, selectedModel, selectedCode){
|
|
const $model = $('#f_model').prop('disabled', true).empty().append($('<option>').val('').text('Loading...'));
|
|
$('#f_variant').prop('disabled', true).empty().append($('<option>').val('').text('Select model first'));
|
|
dmGet(window.DM.base + '/masters/vehicles/models?make=' + encodeURIComponent(make))
|
|
.done(function(res){
|
|
dmFillSelect('#f_model', res.data || [], null, null, selectedModel || '', 'Select model');
|
|
$model.prop('disabled', false);
|
|
if (selectedModel) dmLoadVariants(make, selectedModel, selectedCode);
|
|
});
|
|
}
|
|
|
|
function dmLoadVariants(make, model, selectedCode){
|
|
const $v = $('#f_variant').prop('disabled', true).empty().append($('<option>').val('').text('Loading...'));
|
|
dmGet(window.DM.base + '/masters/vehicles/variants?make=' + encodeURIComponent(make) + '&model=' + encodeURIComponent(model))
|
|
.done(function(res){
|
|
$v.empty().append($('<option>').val('').text('Select variant'));
|
|
(res.data || []).forEach(function(v){
|
|
const label = (v.variant || 'STD') + ' · ' + v.vehicle_code + (v.fuel_type ? ' · ' + v.fuel_type : '');
|
|
const opt = $('<option>').val(v.vehicle_code).text(label);
|
|
if (selectedCode && String(selectedCode) === String(v.vehicle_code)) opt.prop('selected', true);
|
|
$v.append(opt);
|
|
});
|
|
$v.prop('disabled', false);
|
|
if (selectedCode) dmSetVehicleCode(selectedCode);
|
|
});
|
|
}
|
|
|
|
function dmGo(i, silent){
|
|
window.DM.step = i;
|
|
document.querySelectorAll('.dm-step').forEach(v=> v.classList.toggle('active', Number(v.dataset.step)===i));
|
|
document.querySelectorAll('.dm-stop').forEach(s=>{
|
|
const n = Number(s.dataset.i);
|
|
s.classList.toggle('done', n < i);
|
|
s.classList.toggle('active', n === i);
|
|
});
|
|
// Progress fill between stop centers — dots sit above the line (no crossover)
|
|
const stops = document.querySelectorAll('.dm-stop');
|
|
const fill = document.getElementById('dmFill');
|
|
if (fill && stops.length > 1){
|
|
const first = stops[0].offsetLeft + stops[0].offsetWidth / 2;
|
|
const current = stops[i].offsetLeft + stops[i].offsetWidth / 2;
|
|
fill.style.left = first + 'px';
|
|
fill.style.width = Math.max(0, current - first) + 'px';
|
|
fill.style.maxWidth = 'none';
|
|
}
|
|
}
|
|
|
|
function dmToggleExclusive(el){
|
|
const g = el.dataset.group;
|
|
document.querySelectorAll('.dm-chip[data-group="'+g+'"]').forEach(c=> c.classList.remove('on'));
|
|
el.classList.add('on');
|
|
}
|
|
|
|
function dmAlert(msg, ok){
|
|
if (window.toastr) {
|
|
if (ok) {
|
|
toastr.success(msg, 'Success');
|
|
} else {
|
|
toastr.error(msg, 'Error');
|
|
}
|
|
return;
|
|
}
|
|
// Fallback if toastr is unavailable
|
|
const el = document.getElementById('dmAlert');
|
|
if (!el) { alert(msg); return; }
|
|
el.className = 'dm-alert ' + (ok ? 'ok' : 'error');
|
|
el.textContent = msg;
|
|
if (ok) setTimeout(function(){ el.className='dm-alert'; el.textContent=''; }, 4000);
|
|
}
|
|
|
|
function dmBusy(on){
|
|
window.DM.busy = !!on;
|
|
const panel = document.getElementById('dmPanel');
|
|
if (panel) panel.classList.toggle('dm-loading', !!on);
|
|
|
|
// NHANCE global page loader (layout header)
|
|
if (on) {
|
|
$('.loader').show();
|
|
$('.loader-mask').fadeIn();
|
|
} else {
|
|
$('.loader').fadeOut();
|
|
$('.loader-mask').delay(350).fadeOut('slow');
|
|
}
|
|
}
|
|
|
|
function dmAddonFlags(){
|
|
const flags = {};
|
|
document.querySelectorAll('#addonChips .dm-chip').forEach(c=>{
|
|
flags[c.dataset.key] = c.classList.contains('on');
|
|
});
|
|
return flags;
|
|
}
|
|
|
|
function dmPost(url, body){
|
|
return $.ajax({
|
|
url: url,
|
|
type: 'POST',
|
|
contentType: 'application/json',
|
|
dataType: 'json',
|
|
data: JSON.stringify(body || {})
|
|
});
|
|
}
|
|
|
|
function dmGet(url){
|
|
return $.ajax({ url: url, type: 'GET', dataType: 'json' });
|
|
}
|
|
|
|
function dmClearFieldErrors($scope){
|
|
$scope = $scope || $(document);
|
|
$scope.find('.dm-field').removeClass('has-error');
|
|
$scope.find('.dm-invalid').removeClass('dm-invalid');
|
|
}
|
|
|
|
function dmMarkError($el, msg){
|
|
const $field = $el.closest('.dm-field');
|
|
$field.addClass('has-error');
|
|
$el.addClass('dm-invalid');
|
|
if (msg) $field.find('.dm-err').text(msg);
|
|
}
|
|
|
|
function dmValidateRequired(fieldIds){
|
|
dmClearFieldErrors();
|
|
const missing = [];
|
|
fieldIds.forEach(function(id){
|
|
const $el = $('#' + id);
|
|
if (!$el.length) return;
|
|
let val = ($el.val() || '').toString().trim();
|
|
const label = $el.data('label') || id;
|
|
const needLen = parseInt($el.data('len'), 10) || 0;
|
|
|
|
// Variant may be empty if vehicle was picked via search — accept hidden f_vcode
|
|
if (id === 'f_variant' && $('#f_vcode').val()) {
|
|
return;
|
|
}
|
|
if (id === 'f_make' && $('#f_vcode').val()) {
|
|
return;
|
|
}
|
|
if (id === 'f_model' && $('#f_vcode').val()) {
|
|
return;
|
|
}
|
|
|
|
if (!val) {
|
|
dmMarkError($el, label + ' is required');
|
|
missing.push(label);
|
|
return;
|
|
}
|
|
if (needLen && val.replace(/\D/g,'').length < needLen && id === 'f_mobile') {
|
|
dmMarkError($el, 'Enter a valid 10-digit mobile');
|
|
missing.push(label);
|
|
return;
|
|
}
|
|
if (needLen && id === 'f_pin' && val.length !== needLen) {
|
|
dmMarkError($el, 'Pincode must be 6 digits');
|
|
missing.push(label);
|
|
return;
|
|
}
|
|
if (id === 'f_reg' && val.length < 4) {
|
|
dmMarkError($el, 'Registration number is too short');
|
|
missing.push(label);
|
|
}
|
|
});
|
|
return missing;
|
|
}
|
|
|
|
function dmQuickQuote(){
|
|
if (window.DM.busy) return;
|
|
|
|
const claimChip = document.querySelector('.dm-chip[data-group="claim"].on');
|
|
const missing = dmValidateRequired([
|
|
'f_reg', 'f_make', 'f_model', 'f_variant', 'f_vcode',
|
|
'f_reg_date', 'f_mfg_date', 'f_vin', 'f_engine', 'f_pin', 'f_product'
|
|
]);
|
|
if (missing.length){
|
|
dmAlert('Please fill required fields: ' + missing.join(', '));
|
|
const first = document.querySelector('.dm-field.has-error');
|
|
if (first) first.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
return;
|
|
}
|
|
|
|
const tagEnquiry = ($('#enquiryIdTag').text() || '').trim();
|
|
const enquiryId = window.DM.enquiryId
|
|
|| (tagEnquiry && tagEnquiry !== '— new —' ? tagEnquiry : null);
|
|
|
|
const body = {
|
|
quote_id: window.DM.quoteId || null,
|
|
enquiry_id: enquiryId,
|
|
license_plate_number: $('#f_reg').val().trim(),
|
|
vehicle_maincode: $('#f_vcode').val().trim(),
|
|
registration_date: $('#f_reg_date').val(),
|
|
manufacture_date: $('#f_mfg_date').val(),
|
|
vehicle_identification_number: $('#f_vin').val().trim(),
|
|
engine_number: $('#f_engine').val().trim(),
|
|
pincode: $('#f_pin').val().trim(),
|
|
insurance_product_code: $('#f_product').val(),
|
|
start_date: $('#f_start').val() || null,
|
|
end_date: null,
|
|
previous_insurer_code: $('#f_prev_ins').val() || null,
|
|
previous_policy_expiry_date: $('#f_prev_exp').val() || null,
|
|
previous_ncb: $('#f_prev_ncb').val() || 'ZERO',
|
|
previous_policy_type: $('#f_prev_ptype').val() || '',
|
|
is_claim_in_last_year: claimChip ? claimChip.dataset.val === '1' : false,
|
|
coverages: dmAddonFlags()
|
|
};
|
|
|
|
if (body.start_date){
|
|
const d = new Date(body.start_date);
|
|
d.setFullYear(d.getFullYear()+1);
|
|
d.setDate(d.getDate()-1);
|
|
body.end_date = d.toISOString().slice(0,10);
|
|
}
|
|
|
|
dmBusy(true);
|
|
dmPost(window.DM.base + '/quotes/quick', body)
|
|
.done(function(res){
|
|
if (!res.status){ dmAlert(res.message || 'Quick quote failed'); return; }
|
|
window.DM.quoteId = res.data.quote_id;
|
|
window.DM.enquiryId = res.data.enquiry_id;
|
|
$('#enquiryIdTag').text(res.data.enquiry_id);
|
|
const prem = res.data.premium != null ? Number(res.data.premium) : null;
|
|
const idv = res.data.idv != null ? Number(res.data.idv) : null;
|
|
$('#planPremium').text(prem != null ? '₹' + prem.toLocaleString('en-IN', {maximumFractionDigits:0}) : '—');
|
|
$('#planIdv').text(idv != null ? 'IDV ₹' + idv.toLocaleString('en-IN', {maximumFractionDigits:0}) : 'IDV —');
|
|
$('#payPremium').val(prem != null ? 'INR ' + prem.toFixed(2) : '');
|
|
dmAlert('Quick quote generated.', true);
|
|
history.replaceState(null, '', window.DM.base + '/journey/' + window.DM.quoteId);
|
|
$('#f_cq_vin').val(body.vehicle_identification_number || '');
|
|
$('#f_cq_engine').val(body.engine_number || '');
|
|
dmGo(1);
|
|
})
|
|
.fail(function(xhr){
|
|
let msg = (xhr.responseJSON && xhr.responseJSON.message) || 'Quick quote failed.';
|
|
const errs = xhr.responseJSON && xhr.responseJSON.errors;
|
|
if (errs && typeof errs === 'object') {
|
|
const parts = Object.keys(errs).map(function(k){ return errs[k]; });
|
|
if (parts.length) msg = parts.join(' | ');
|
|
}
|
|
// If shell was created, keep continuity for retry
|
|
if (xhr.responseJSON && xhr.responseJSON.data) {
|
|
if (xhr.responseJSON.data.quote_id) window.DM.quoteId = xhr.responseJSON.data.quote_id;
|
|
if (xhr.responseJSON.data.enquiry_id) {
|
|
window.DM.enquiryId = xhr.responseJSON.data.enquiry_id;
|
|
$('#enquiryIdTag').text(xhr.responseJSON.data.enquiry_id);
|
|
}
|
|
}
|
|
dmAlert(msg);
|
|
})
|
|
.always(function(){ dmBusy(false); });
|
|
}
|
|
|
|
function dmCreateQuote(){
|
|
if (window.DM.busy) return;
|
|
if (!window.DM.quoteId){ dmAlert('Run quick quote first.'); return; }
|
|
|
|
// Keep QQ + CQ chassis/engine in sync when editing on step 2
|
|
if ($('#f_cq_vin').val()) $('#f_vin').val($('#f_cq_vin').val().trim().toUpperCase());
|
|
if ($('#f_cq_engine').val()) $('#f_engine').val($('#f_cq_engine').val().trim().toUpperCase());
|
|
|
|
const missing = dmValidateRequired(['f_cq_vin', 'f_cq_engine', 'f_fname', 'f_mobile', 'f_email', 'f_pan', 'f_dob', 'f_address']);
|
|
if (missing.length){
|
|
dmAlert('Please fill required fields: ' + missing.join(', '));
|
|
const first = document.querySelector('.dm-field.has-error');
|
|
if (first) first.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
return;
|
|
}
|
|
|
|
const body = {
|
|
first_name: $('#f_fname').val().trim(),
|
|
last_name: $('#f_lname').val().trim(),
|
|
mobile: $('#f_mobile').val().trim(),
|
|
email: $('#f_email').val().trim(),
|
|
pan: $('#f_pan').val().trim(),
|
|
dob: $('#f_dob').val(),
|
|
address: $('#f_address').val().trim(),
|
|
vehicle_identification_number: $('#f_cq_vin').val().trim().toUpperCase(),
|
|
engine_number: $('#f_cq_engine').val().trim().toUpperCase(),
|
|
start_date: $('#f_start').val() || null,
|
|
coverages: dmAddonFlags()
|
|
};
|
|
if (body.start_date){
|
|
const d = new Date(body.start_date);
|
|
d.setFullYear(d.getFullYear()+1);
|
|
d.setDate(d.getDate()-1);
|
|
body.end_date = d.toISOString().slice(0,10);
|
|
}
|
|
|
|
dmBusy(true);
|
|
dmPost(window.DM.base + '/quotes/' + window.DM.quoteId + '/create', body)
|
|
.done(function(res){
|
|
if (!res.status){ dmAlert(res.message || 'Create quote failed'); return; }
|
|
$('#refQuoteNo').text(res.data.quote_number || '—');
|
|
$('#refAppId').text(res.data.application_id || '—');
|
|
if (res.data.premium != null){
|
|
$('#payPremium').val('INR ' + Number(res.data.premium).toFixed(2));
|
|
$('#planPremium').text('₹' + Number(res.data.premium).toLocaleString('en-IN', {maximumFractionDigits:0}));
|
|
}
|
|
dmAlert('Quote created.', true);
|
|
dmGo(2);
|
|
})
|
|
.fail(function(xhr){
|
|
dmAlert((xhr.responseJSON && xhr.responseJSON.message) || 'Create quote failed.');
|
|
})
|
|
.always(function(){ dmBusy(false); });
|
|
}
|
|
|
|
function dmKycStatus(){
|
|
if (!window.DM.quoteId){ dmAlert('No quote loaded.'); return; }
|
|
dmBusy(true);
|
|
dmGet(window.DM.base + '/kyc/' + window.DM.quoteId)
|
|
.done(function(res){
|
|
if (!res.status){ dmAlert(res.message || 'KYC fetch failed'); return; }
|
|
const k = res.data.kyc || {};
|
|
const st = (res.data.status || k.kyc_verification_status || 'UNKNOWN').toString();
|
|
$('#kycTitle').text(st);
|
|
$('#kycPill').text(st).removeClass('ok wait').addClass(/done|verif|success|complete/i.test(st) ? 'ok' : 'wait');
|
|
$('#refKycRef').text(k.reference_id || '—');
|
|
$('#refKycLink').html(k.link ? '<a href="'+k.link+'" target="_blank">Open</a>' : '—');
|
|
$('#kycSub').text('Last checked just now.');
|
|
dmAlert('KYC status updated.', true);
|
|
})
|
|
.fail(function(xhr){
|
|
dmAlert((xhr.responseJSON && xhr.responseJSON.message) || 'KYC fetch failed.');
|
|
})
|
|
.always(function(){ dmBusy(false); });
|
|
}
|
|
|
|
function dmPaymentLink(){
|
|
if (!window.DM.quoteId){ dmAlert('No quote loaded.'); return; }
|
|
const body = {
|
|
payment_mode: $('#payMode').val() || 'EB',
|
|
premium_amount: ($('#payPremium').val() || '').trim() || null
|
|
};
|
|
dmBusy(true);
|
|
dmPost(window.DM.base + '/payments/' + window.DM.quoteId + '/link', body)
|
|
.done(function(res){
|
|
if (!res.status){ dmAlert(res.message || 'Payment link failed'); return; }
|
|
const link = res.data.dispatcher_response;
|
|
const pay = res.data.payment || {};
|
|
$('#payTitle').text(link ? 'Payment link ready' : 'Link missing in response');
|
|
$('#paySub').text(pay.digit_payment_id || 'digit payment');
|
|
if (link){
|
|
$('#payOpenBtn').attr('href', link).show();
|
|
}
|
|
dmAlert('Payment link generated.', true);
|
|
})
|
|
.fail(function(xhr){
|
|
dmAlert((xhr.responseJSON && xhr.responseJSON.message) || 'Payment link failed.');
|
|
})
|
|
.always(function(){ dmBusy(false); });
|
|
}
|
|
|
|
function dmPolicyStatus(){
|
|
if (!window.DM.quoteId){ dmAlert('No quote loaded.'); return; }
|
|
dmBusy(true);
|
|
dmGet(window.DM.base + '/policies/' + window.DM.quoteId + '/status')
|
|
.done(function(res){
|
|
if (!res.status){ dmAlert(res.message || 'Policy status failed'); return; }
|
|
const p = res.data.policy || {};
|
|
const st = (res.data.status || p.policy_status || 'UNKNOWN').toString();
|
|
$('#polTitle').text((p.policy_number || 'Policy') + ' · ' + st);
|
|
$('#polPill').text(st).removeClass('ok wait').addClass(/effective|complete|active/i.test(st) ? 'ok' : 'wait');
|
|
dmAlert('Policy status updated.', true);
|
|
})
|
|
.fail(function(xhr){
|
|
dmAlert((xhr.responseJSON && xhr.responseJSON.message) || 'Policy status failed.');
|
|
})
|
|
.always(function(){ dmBusy(false); });
|
|
}
|
|
|
|
function dmPolicyPdf(){
|
|
if (!window.DM.quoteId){ dmAlert('No quote loaded.'); return; }
|
|
dmBusy(true);
|
|
dmGet(window.DM.base + '/policies/' + window.DM.quoteId + '/pdf')
|
|
.done(function(res){
|
|
if (!res.status){ dmAlert(res.message || 'PDF fetch failed'); return; }
|
|
const p = res.data.policy || {};
|
|
if (p.schedule_path){
|
|
$('#dlSchedule').attr('href', p.schedule_path).css({pointerEvents:'auto',opacity:1});
|
|
}
|
|
if (p.proposal_path){
|
|
$('#dlProposal').attr('href', p.proposal_path).css({pointerEvents:'auto',opacity:1});
|
|
}
|
|
dmAlert('PDF links updated.', true);
|
|
})
|
|
.fail(function(xhr){
|
|
dmAlert((xhr.responseJSON && xhr.responseJSON.message) || 'PDF fetch failed.');
|
|
})
|
|
.always(function(){ dmBusy(false); });
|
|
}
|
|
|
|
window.addEventListener('resize', function(){ dmGo(window.DM.step, true); });
|
|
|
|
$(document).on('input change', '.dm-field input, .dm-field select', function(){
|
|
const $field = $(this).closest('.dm-field');
|
|
if (($(this).val() || '').toString().trim()) {
|
|
$field.removeClass('has-error');
|
|
$(this).removeClass('dm-invalid');
|
|
}
|
|
});
|
|
</script>
|