Files
cbsnexora/src/app/loan-origination/loan-pipeline/loan-pipeline.component.html
T
nitesh 2d93f80d50
build-run / Run Lint, Build and Deploy (push) Canceled after 0s
Publish Image in Docker Hub / build (push) Canceled after 0s
Playwright E2E Tests / Run Playwright Tests (push) Canceled after 0s
Tests / testRigor (push) Canceled after 0s
feat(loan-origination): guarantor share-account verification, committee resolution gating, legal doc uploads, CIC score-detection fixes, and interest/share rate chart
- Guarantor must be a real existing client with a verified active share account, with clickable share-account chips
- Loan Committee Approval now requires Resolution No./Date plus a full application report before approving
- Loan Committee gets its own pre-filtered pipeline view via a menu link and stage query param
- Legal Approval stage gets a multi-file document upload checklist with add-more support
- CIC PDF parser: item-level score detection before line-based fallback, fixing font-size-driven line-merging misdetection
- New Interest & Share Rate Chart tab: per-product interest/tenure bands and per-amount-slab Share Capital linkage requirements
2026-08-14 14:49:22 +05:30

725 lines
27 KiB
HTML
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.
<!--
Copyright since 2025 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
-->
<div class="pg">
<header class="pg-head">
<div>
<div class="pg-eyebrow">CREDIT · LOAN ORIGINATION · {{ scopeName | uppercase }}</div>
<h1 class="pg-title">Loan Origination Pipeline</h1>
<p class="pg-sub npa-report-note">
Every sanctioning stage from application intake to disbursement — KYC/OVD, CIC credit check, Field
Investigation, Personal Discussion, Credit Committee, Risk &amp; Legal Approval — as on {{ asOnDate }}.
</p>
</div>
<div class="pg-toolbar">
@if (isHeadOffice) {
<label class="pg-field">
<span>Branch</span>
<select class="pg-select" [ngModel]="branchFilter" (ngModelChange)="setBranch($event)">
<option value="">-- All Branches --</option>
@for (b of branches; track b.code) {
<option [value]="b.code">{{ b.name }}</option>
}
</select>
</label>
} @else {
<label class="pg-field">
<span>Branch</span>
<span class="pg-chip">{{ scopeName }}</span>
</label>
}
<button type="button" class="pg-btn pg-btn--ghost" [disabled]="generating" (click)="exportExcel()">
{{ generating ? 'Exporting…' : 'Export to Excel' }}
</button>
</div>
</header>
<div class="inv-kpis npa-kpis--ratio">
<div class="inv-kpi">
<span class="inv-kpi__label">Total Applications</span>
<span class="inv-kpi__value">{{ totalApplications }}</span>
<span class="inv-kpi__sub">in the active pipeline</span>
</div>
<div class="inv-kpi">
<span class="inv-kpi__label">In Progress</span>
<span class="inv-kpi__value">{{ inProgressCount }}</span>
<span class="inv-kpi__sub">moving through the workflow</span>
</div>
<div class="inv-kpi">
<span class="inv-kpi__label">On Hold</span>
<span class="inv-kpi__value npa-warn">{{ onHoldCount }}</span>
<span class="inv-kpi__sub">discrepancy under resolution</span>
</div>
<div class="inv-kpi">
<span class="inv-kpi__label">Rejected</span>
<span class="inv-kpi__value npa-warn">{{ rejectedCount }}</span>
<span class="inv-kpi__sub">declined at Committee/Risk</span>
</div>
<div class="inv-kpi">
<span class="inv-kpi__label">Disbursed</span>
<span class="inv-kpi__value">{{ disbursedApplications.length }}</span>
<span class="inv-kpi__sub">₹{{ disbursedAmount | number: '1.0-0' }} total</span>
</div>
</div>
<div class="cctr-tabs">
<button
type="button"
class="pg-btn pg-btn--ghost"
[class.pg-btn--active]="activeView === 'pipeline'"
(click)="setView('pipeline')"
>
Pipeline
</button>
<button
type="button"
class="pg-btn pg-btn--ghost"
[class.pg-btn--active]="activeView === 'new'"
(click)="setView('new')"
>
New Application
</button>
<button
type="button"
class="pg-btn pg-btn--ghost"
[class.pg-btn--active]="activeView === 'channel'"
(click)="setView('channel')"
>
Channel-wise Report
</button>
<button
type="button"
class="pg-btn pg-btn--ghost"
[class.pg-btn--active]="activeView === 'bc'"
(click)="setView('bc')"
>
BC-wise Report
</button>
<button
type="button"
class="pg-btn pg-btn--ghost"
[class.pg-btn--active]="activeView === 'share'"
(click)="setView('share')"
>
Share Member Report
</button>
<button
type="button"
class="pg-btn pg-btn--ghost"
[class.pg-btn--active]="activeView === 'target'"
(click)="setView('target')"
>
Target vs Actual
</button>
<button
type="button"
class="pg-btn pg-btn--ghost"
[class.pg-btn--active]="activeView === 'rates'"
(click)="setView('rates')"
>
Interest &amp; Share Rate Chart
</button>
</div>
<!-- ===================== PIPELINE ===================== -->
@if (activeView === 'pipeline') {
<div class="pg-card">
<div class="pos-section-label">Filters</div>
<div class="inv-form-grid">
<label class="inv-form-field">
<span>Channel</span>
<select [(ngModel)]="channelFilter" (ngModelChange)="currentPage = 1">
<option value="">-- All --</option>
<option value="BRANCH">Branch</option>
<option value="BC">Business Correspondent (BC)</option>
<option value="SELF_APPLY">Self-Apply (Digital)</option>
</select>
</label>
<label class="inv-form-field">
<span>Stage</span>
<select [(ngModel)]="stageFilter" (ngModelChange)="currentPage = 1">
<option value="">-- All --</option>
@for (s of stageOrder; track s) {
<option [value]="s">{{ stageLabels[s] }}</option>
}
</select>
</label>
<label class="inv-form-field">
<span>Status</span>
<select [(ngModel)]="statusFilter" (ngModelChange)="currentPage = 1">
<option value="">-- All --</option>
<option value="IN_PROGRESS">In Progress</option>
<option value="ON_HOLD">On Hold</option>
<option value="REJECTED">Rejected</option>
<option value="DISBURSED">Disbursed</option>
</select>
</label>
<label class="inv-form-field">
<span>Search (Application No / Applicant)</span>
<input
type="text"
[(ngModel)]="searchText"
(ngModelChange)="currentPage = 1"
placeholder="e.g. Ramesh, LN0102..."
/>
</label>
</div>
</div>
<div class="pg-card">
<div class="pos-section-label">Applications ({{ filteredApplications.length }})</div>
<div class="pg-table-scroll">
<table class="pg-table">
<thead>
<tr>
<th>Application No</th>
<th>Applicant</th>
<th>Branch</th>
<th>Channel</th>
<th>Product</th>
<th class="num">Requested Amount</th>
<th>Current Stage</th>
<th class="num">Progress</th>
<th>Status</th>
</tr>
</thead>
<tbody>
@for (a of paged(filteredApplications); track a.applicationNo) {
<tr class="cctr-branch-row" (click)="openApplication(a)">
<td>
<span class="pg-chip">{{ a.applicationNo }}</span>
</td>
<td>{{ a.applicantName }}</td>
<td>{{ a.branchName }}</td>
<td>{{ channelLabels[a.channel] }}</td>
<td>{{ a.productName }}</td>
<td class="num">₹{{ a.requestedAmount | number: '1.0-0' }}</td>
<td>{{ stageLabel(a.currentStage) }}</td>
<td class="num">{{ progress(a) }}%</td>
<td>
<span [class]="badgeClass(a)">{{ statusLabel(a.overallStatus) }}</span>
</td>
</tr>
} @empty {
<tr>
<td colspan="9" class="pg-empty">No applications match these filters.</td>
</tr>
}
</tbody>
</table>
</div>
@if (filteredApplications.length > pageSize) {
<div class="pg-pagination">
<span class="pg-pagination__info"
>Showing {{ rangeStart(filteredApplications) }}–{{ rangeEnd(filteredApplications) }} of
{{ filteredApplications.length }}</span
>
<div class="pg-pagination__controls">
<button
type="button"
class="pg-btn pg-btn--ghost"
[disabled]="currentPage === 1"
(click)="goToPage(currentPage - 1, filteredApplications)"
>
‹ Prev
</button>
<span class="pg-pagination__page">Page {{ currentPage }} of {{ pageCount(filteredApplications) }}</span>
<button
type="button"
class="pg-btn pg-btn--ghost"
[disabled]="currentPage === pageCount(filteredApplications)"
(click)="goToPage(currentPage + 1, filteredApplications)"
>
Next ›
</button>
</div>
</div>
}
</div>
}
<!-- ===================== NEW APPLICATION ===================== -->
@if (activeView === 'new') {
<div class="pg-card">
<div class="pos-section-label">New Application — Channel Intake</div>
<div class="inv-form-grid">
<label class="inv-form-field">
<span>* Channel</span>
<select [(ngModel)]="newApp.channel">
<option value="BRANCH">Branch</option>
<option value="BC">Business Correspondent (BC)</option>
<option value="SELF_APPLY">Self-Apply (Digital)</option>
</select>
</label>
@if (newApp.channel === 'BC') {
<label class="inv-form-field">
<span>* BC Agent / Point</span>
<input type="text" [(ngModel)]="newApp.bcAgentName" placeholder="e.g. Suvidha BC Point — Andheri" />
</label>
}
<label class="inv-form-field">
<span>* Customer Type</span>
<select [(ngModel)]="newApp.customerType" (ngModelChange)="onCustomerTypeChange()">
<option value="NEW">New Customer</option>
<option value="EXISTING">Existing Customer</option>
</select>
</label>
@if (newApp.customerType === 'EXISTING') {
@if (!newApp.clientId) {
<label class="inv-form-field">
<span>* Search Existing Client</span>
<input
type="text"
[(ngModel)]="existingClientSearchText"
(ngModelChange)="onExistingClientSearch($event)"
placeholder="Name, account no., mobile..."
/>
</label>
} @else {
<label class="inv-form-field">
<span>* Applicant</span>
<div class="loi-selected-client">
<span>{{ newApp.applicantName }}</span>
<button type="button" class="pg-btn" (click)="clearExistingClient()">Change</button>
</div>
</label>
}
} @else {
<label class="inv-form-field">
<span>* Applicant Name</span>
<input type="text" [(ngModel)]="newApp.applicantName" placeholder="Full name" />
</label>
}
<label class="inv-form-field">
<span>* Branch</span>
<select [(ngModel)]="newApp.branchCode" [disabled]="!isHeadOffice">
@for (b of newApplicationBranches; track b.code) {
<option [value]="b.code">{{ b.name }}</option>
}
</select>
</label>
<label class="inv-form-field">
<span>* Product</span>
<select [(ngModel)]="newApp.productCode" (ngModelChange)="onProductChange()">
@for (p of products; track p.code) {
<option [value]="p.code">{{ p.name }}</option>
}
</select>
</label>
<label class="inv-form-field">
<span>* Product Type</span>
<select [(ngModel)]="newApp.productType">
@for (t of newAppProductTypeOptions; track t) {
<option [value]="t">{{ productTypeLabels[t] }}</option>
}
</select>
</label>
<label class="inv-form-field">
<span>* Requested Amount</span>
<input type="number" [(ngModel)]="newApp.requestedAmount" placeholder="₹" />
</label>
<label class="inv-form-field">
<span>Tenure (Months)</span>
<input type="number" [(ngModel)]="newApp.tenureMonths" placeholder="e.g. 36" />
</label>
</div>
@if (newApp.customerType === 'EXISTING' && !newApp.clientId) {
@if (searchingExistingClient) {
<p class="loi-search-hint">Searching…</p>
} @else if (existingClientSearchText.length >= 2 && existingClientSearchResults.length === 0) {
<p class="loi-search-hint">No clients found.</p>
}
@if (existingClientSearchResults.length > 0) {
<div class="loi-search-results">
@for (client of existingClientSearchResults; track client.id) {
<button type="button" class="loi-search-row" (click)="selectExistingClient(client)">
<span class="loi-search-name">{{ client.displayName }}</span>
<span class="loi-search-meta">{{ client.accountNo ?? client.officeName ?? '' }}</span>
</button>
}
</div>
}
}
<div class="inv-form-actions">
<button type="button" class="pg-btn pg-btn--primary" (click)="saveNewApplication()">Submit Application</button>
</div>
</div>
}
<!-- ===================== CHANNEL-WISE REPORT ===================== -->
@if (activeView === 'channel') {
<div class="pg-card">
<div class="pos-section-label">Channel-wise Report — Branch / BC / Self-Apply</div>
<table class="pg-table">
<thead>
<tr>
<th>Channel</th>
<th class="num">Applications</th>
<th class="num">Requested Amount</th>
<th class="num col-in">Disbursed Count</th>
<th class="num col-in">Disbursed Amount</th>
</tr>
</thead>
<tbody>
@for (r of channelReport; track r.channel) {
<tr>
<td>{{ r.label }}</td>
<td class="num">{{ r.count }}</td>
<td class="num">₹{{ r.requestedAmount | number: '1.0-0' }}</td>
<td class="num col-in">{{ r.disbursedCount }}</td>
<td class="num col-in">₹{{ r.disbursedAmount | number: '1.0-0' }}</td>
</tr>
}
</tbody>
<tfoot>
<tr class="cctr-total-row">
<td>Total</td>
<td class="num">{{ totalApplications }}</td>
<td class="num">
₹{{
channelReport[0].requestedAmount + channelReport[1].requestedAmount + channelReport[2].requestedAmount
| number: '1.0-0'
}}
</td>
<td class="num">{{ disbursedApplications.length }}</td>
<td class="num">₹{{ disbursedAmount | number: '1.0-0' }}</td>
</tr>
</tfoot>
</table>
</div>
}
<!-- ===================== BC-WISE REPORT ===================== -->
@if (activeView === 'bc') {
<div class="pg-card">
<div class="pos-section-label">
BC-wise Report — Business Correspondent Sourced Applications ({{ bcApplications.length }})
</div>
<table class="pg-table">
<thead>
<tr>
<th>BC Agent / Point</th>
<th class="num">Applications</th>
<th class="num">Requested Amount</th>
<th class="num col-in">Disbursed Count</th>
<th class="num col-in">Disbursed Amount</th>
</tr>
</thead>
<tbody>
@for (r of bcReport; track r.bcAgentName) {
<tr>
<td>{{ r.bcAgentName }}</td>
<td class="num">{{ r.count }}</td>
<td class="num">₹{{ r.requestedAmount | number: '1.0-0' }}</td>
<td class="num col-in">{{ r.disbursedCount }}</td>
<td class="num col-in">₹{{ r.disbursedAmount | number: '1.0-0' }}</td>
</tr>
} @empty {
<tr>
<td colspan="5" class="pg-empty">No BC-sourced applications in this branch.</td>
</tr>
}
</tbody>
</table>
</div>
}
<!-- ===================== SHARE MEMBER REPORT ===================== -->
@if (activeView === 'share') {
<div class="pg-card">
<div class="pos-section-label">Share Member Report</div>
<p class="pg-sub npa-report-note">
A cooperative-bank borrower must hold membership shares in the society before a loan can be sanctioned.
{{ shareMemberCount }} of {{ totalApplications }} applicants are already members; the rest need membership
allotted before Credit Committee approval — done from the application's own detail screen.
</p>
<div class="pg-table-scroll">
<table class="pg-table">
<thead>
<tr>
<th>Application No</th>
<th>Applicant</th>
<th>Branch</th>
<th>Current Stage</th>
<th>Status</th>
</tr>
</thead>
<tbody>
@for (a of paged(nonMemberApplications); track a.applicationNo) {
<tr class="cctr-branch-row" (click)="openApplication(a)">
<td>
<span class="pg-chip">{{ a.applicationNo }}</span>
</td>
<td>{{ a.applicantName }}</td>
<td>{{ a.branchName }}</td>
<td>{{ stageLabel(a.currentStage) }}</td>
<td>
<span [class]="badgeClass(a)">{{ statusLabel(a.overallStatus) }}</span>
</td>
</tr>
} @empty {
<tr>
<td colspan="5" class="pg-empty">Every active applicant in this branch already holds membership.</td>
</tr>
}
</tbody>
</table>
</div>
@if (nonMemberApplications.length > pageSize) {
<div class="pg-pagination">
<span class="pg-pagination__info"
>Showing {{ rangeStart(nonMemberApplications) }}–{{ rangeEnd(nonMemberApplications) }} of
{{ nonMemberApplications.length }}</span
>
<div class="pg-pagination__controls">
<button
type="button"
class="pg-btn pg-btn--ghost"
[disabled]="currentPage === 1"
(click)="goToPage(currentPage - 1, nonMemberApplications)"
>
‹ Prev
</button>
<span class="pg-pagination__page">Page {{ currentPage }} of {{ pageCount(nonMemberApplications) }}</span>
<button
type="button"
class="pg-btn pg-btn--ghost"
[disabled]="currentPage === pageCount(nonMemberApplications)"
(click)="goToPage(currentPage + 1, nonMemberApplications)"
>
Next ›
</button>
</div>
</div>
}
</div>
}
<!-- ===================== TARGET VS ACTUAL ===================== -->
@if (activeView === 'target') {
<div class="pg-card">
<div class="pos-section-label">Branch-wise Disbursement Target — Annual</div>
<table class="pg-table">
<thead>
<tr>
<th>Branch</th>
<th class="num">Target</th>
<th class="num col-in">Disbursed (Actual)</th>
<th class="num">Achievement %</th>
<th>Status</th>
</tr>
</thead>
<tbody>
@for (row of branchTargetRows; track row.branchCode) {
<tr>
<td>{{ row.branchName }}</td>
<td class="num">₹{{ row.target | number: '1.0-0' }}</td>
<td class="num col-in">₹{{ row.actual | number: '1.0-0' }}</td>
<td class="num">{{ row.achievementPct | number: '1.1-1' }}%</td>
<td>
<span
class="loan-badge"
[class.loan-badge--disbursed]="row.status !== 'BEHIND'"
[class.loan-badge--hold]="row.status === 'BEHIND'"
>
{{ statusLabelOf(row.status) }}
</span>
</td>
</tr>
}
</tbody>
</table>
</div>
<div class="pg-card">
<div class="pos-section-label">Product Mix — Target % vs Actual % (of Disbursed Amount)</div>
<p class="pg-sub npa-report-note">
KCC and Cash Credit (MSME) targets are RBI's actual Priority Sector Lending sub-targets — Agriculture 18% and
Micro Enterprises 7.5% of Adjusted Net Bank Credit (shown here against this module's own mix, since RBI sets
them against the bank's whole loan book, not one product line). The rest are internal business-plan targets, not
RBI-mandated.
</p>
<table class="pg-table">
<thead>
<tr>
<th>Product</th>
<th>Target Basis</th>
<th class="num">Target %</th>
<th class="num col-in">Actual %</th>
<th class="num">Variance</th>
<th>Status</th>
</tr>
</thead>
<tbody>
@for (row of productTargetRows; track row.code) {
<tr>
<td>{{ row.label }}</td>
<td>
<span class="loan-badge" [class.loan-badge--progress]="row.isRbiMandated">
{{ row.isRbiMandated ? 'RBI PSL Sub-Target' : 'Internal Target' }}
</span>
</td>
<td class="num">{{ row.targetPct | number: '1.0-1' }}%</td>
<td class="num col-in">{{ row.actualPct | number: '1.1-1' }}%</td>
<td class="num" [class.col-out]="row.variancePct < 0" [class.col-in]="row.variancePct > 0">
{{ row.variancePct > 0 ? '+' : '' }}{{ row.variancePct | number: '1.1-1' }} pp
</td>
<td>
<span
class="loan-badge"
[class.loan-badge--disbursed]="row.status !== 'BEHIND'"
[class.loan-badge--hold]="row.status === 'BEHIND'"
>
{{ statusLabelOf(row.status) }}
</span>
</td>
</tr>
}
</tbody>
</table>
</div>
<div class="pg-card">
<div class="pos-section-label">Channel Mix — Target % vs Actual % (of Disbursed Amount)</div>
<table class="pg-table">
<thead>
<tr>
<th>Channel</th>
<th class="num">Target %</th>
<th class="num col-in">Actual %</th>
<th class="num">Variance</th>
<th>Status</th>
</tr>
</thead>
<tbody>
@for (row of channelTargetRows; track row.code) {
<tr>
<td>{{ row.label }}</td>
<td class="num">{{ row.targetPct | number: '1.0-1' }}%</td>
<td class="num col-in">{{ row.actualPct | number: '1.1-1' }}%</td>
<td class="num" [class.col-out]="row.variancePct < 0" [class.col-in]="row.variancePct > 0">
{{ row.variancePct > 0 ? '+' : '' }}{{ row.variancePct | number: '1.1-1' }} pp
</td>
<td>
<span
class="loan-badge"
[class.loan-badge--disbursed]="row.status !== 'BEHIND'"
[class.loan-badge--hold]="row.status === 'BEHIND'"
>
{{ statusLabelOf(row.status) }}
</span>
</td>
</tr>
}
</tbody>
</table>
</div>
}
<!-- ===================== INTEREST & SHARE RATE CHART ===================== -->
@if (activeView === 'rates') {
<div class="pg-card">
<div class="pos-section-label">Product-wise — Interest Rate &amp; Share Capital Required</div>
<p class="pg-sub npa-report-note">
Total Interest is an illustrative simple-interest figure (Amount x Rate x Tenure in years) at the product's own
min/max amount and tenure band — actual repayment is on a reducing balance and depends on the amount and tenure
chosen at sanction. Share Capital Required is the minimum a borrower must hold per bank bye-laws, proportional
to the loan amount.
</p>
<div class="pg-table-scroll">
<table class="pg-table">
<thead>
<tr>
<th>Product</th>
<th>Type</th>
<th class="num">Amount Range</th>
<th class="num">Interest Rate (p.a.)</th>
<th class="num">Tenure Range</th>
<th class="num">Illustrative Total Interest</th>
<th class="num">Share Capital Required</th>
<th class="num">Illustrative Share Amount</th>
</tr>
</thead>
<tbody>
@for (p of products; track p.code) {
<tr>
<td>{{ p.name }}</td>
<td>
<span
class="loan-badge"
[class.loan-badge--progress]="p.secured"
[class.loan-badge--hold]="!p.secured"
>
{{ p.secured ? 'Secured' : 'Unsecured' }}
</span>
</td>
<td class="num">₹{{ p.minAmt | number: '1.0-0' }} – ₹{{ p.maxAmt | number: '1.0-0' }}</td>
<td class="num">{{ p.minRate | number: '1.1-1' }}% – {{ p.maxRate | number: '1.1-1' }}%</td>
<td class="num">{{ p.minTenure }} – {{ p.maxTenure }} months</td>
<td class="num">
₹{{ illustrativeInterest(p.minAmt, p.minRate, p.minTenure) | number: '1.0-0' }} – ₹{{
illustrativeInterest(p.maxAmt, p.maxRate, p.maxTenure) | number: '1.0-0'
}}
</td>
<td class="num">{{ p.shareLinkagePercent | number: '1.1-1' }}%</td>
<td class="num">
₹{{ p.minAmt * (p.shareLinkagePercent / 100) | number: '1.0-0' }} – ₹{{
p.maxAmt * (p.shareLinkagePercent / 100) | number: '1.0-0'
}}
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
<div class="pg-card">
<div class="pos-section-label">Amount Slab-wise — Share Capital Required (All Products)</div>
<p class="pg-sub npa-report-note">
A general slab schedule by loan quantum, independent of product — where this differs from the product-wise
minimum above, whichever is higher governs the actual requirement.
</p>
<table class="pg-table">
<thead>
<tr>
<th class="num">Loan Amount Slab</th>
<th class="num">Share Capital Required</th>
<th class="num">Illustrative Share Amount</th>
</tr>
</thead>
<tbody>
@for (row of shareLinkageSlabRows; track row.minAmt) {
<tr>
<td class="num">
@if (row.maxAmt !== null) {
₹{{ row.minAmt | number: '1.0-0' }} – ₹{{ row.maxAmt | number: '1.0-0' }}
} @else {
Above ₹{{ row.minAmt | number: '1.0-0' }}
}
</td>
<td class="num">{{ row.sharePercent | number: '1.1-1' }}%</td>
<td class="num">
@if (row.shareAtMax !== null) {
₹{{ row.shareAtMin | number: '1.0-0' }} – ₹{{ row.shareAtMax | number: '1.0-0' }}
} @else {
From ₹{{ row.shareAtMin | number: '1.0-0' }}
}
</td>
</tr>
}
</tbody>
</table>
</div>
}
</div>
<div class="inv-toast" [class.show]="toastVisible">{{ toastMsg }}</div>