Files
cbsnexora/src/app/deposits/recurring-deposits/recurring-deposits-account-stepper/recurring-deposits-account-preview-step/recurring-deposits-account-preview-step.component.html
T
niteshandClaude Sonnet 5 395fb8ace8
Tests / testRigor (push) Canceled after 0s
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
feat(clients,deposits): auto-derive senior-citizen/customer-segment, fix disbursement display and reversed-transaction balances
Four independent, self-contained changes bundled from this session's work:

1. Auto-derive Senior Citizen / Minor / Customer Segment instead of manual entry

   Senior Citizen was a manual, staff-editable checkbox on FD/RD account
   creation with no validation against the client's actual age -- this let
   non-senior clients get the senior-citizen interest rate by mistake (found
   twice on live test accounts, where m_savings_account.is_senior_citizen
   was true despite the client being confirmed non-senior at the client
   record level). Likewise "minor" client classification was hardcoded to
   the age-18 threshold with no single source of truth, and FD/RD account
   creation's "Customer Segment" (Individual / Non-Individual) had no
   connection to the Individual/Non-Individual Legal Form already captured
   at client creation.

   - New src/app/clients/shared/client-age.util.ts centralises age/DOB
     derivation: MINOR_AGE_THRESHOLD (now 10, was 18), SENIOR_CITIZEN_AGE_
     THRESHOLD (60), AGE_OF_MAJORITY (18, kept separate from the minor
     threshold -- majority date math is unrelated to the minor/adult
     classification threshold), calculateAge/isMinorAge/isSeniorCitizenAge/
     isIndividualClient/deriveSeniorCitizenStatus.
   - FD/RD interest-rate-chart steps: Senior Citizen checkbox is now derived
     from the client's DOB (age >= 60, individual clients only) and
     disabled for manual editing; a hint explains why it is checked/
     unchecked.
   - Client general step and all four account-details-steps (savings,
     current, FD, RD): replaced hardcoded 18/60 literals with the shared
     helpers; "Must be below 18" hints now read the actual threshold.
   - FD/RD account-details-steps: Customer Segment auto-selects to match
     the client's Legal Form (exact match, not substring -- a substring
     match would misclassify "Individual" as matching "Non-Individual").
   - RD preview step: fixed a pre-existing display bug that always showed
     the product's default Customer Segment instead of what was actually
     selected on the account.

2. Fix wrong Account Name / Account Type on Disbursement Review screens

   Clerk disbursement review and "My Disbursement Requests" showed the
   account NUMBER instead of the holder's name, and always labelled the
   account type "SAVINGS" regardless of the real account type (FD/RD/
   Share/Loan), because transaction-entry.component.ts's account-type
   mapping only checked for CA/CB and its account-name fallback chain
   never tried clientName. Added creditEntryAccountType() covering
   GL/CA/CB/FD/RD/SHR/LA, and accountTypeLabel() display helpers on both
   review screens.

3. Stop reversed transactions from distorting displayed running balances

   Passbook and Transactions tabs were including reversed transactions in
   their client-side running-balance recalculation, so a reversed posting
   (visible struck-through) still shifted the balance shown for every
   transaction after it. Both now filter out txn.reversed before computing
   running balances; Transactions tab also defaults "Hide Reversed" to on.

4. New Interest Schedule dialog on the FD account view

   Added custom-dialogs/interest-schedule-dialog, opened from the FD
   General tab, showing the account's period-by-period interest schedule.

Excludes src/environments/.env.ts (auto-generated build version/hash
stamp, regenerated on every build -- not meaningful to hand-commit).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-26 18:58:20 +05:30

912 lines
41 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="preview-wrapper">
<!-- ══ 1. Account Details ════════════════════════════════════════ -->
<div class="preview-section">
<div class="preview-section__header">
<i class="fas fa-info-circle preview-section__icon"></i>
<span class="preview-section__title">{{ 'labels.heading.Details' | translate }}</span>
</div>
<div class="preview-body">
<div class="preview-grid preview-grid--three">
<div class="preview-field">
<span class="preview-label">{{ 'labels.inputs.Product' | translate }}</span>
<span class="preview-value">{{
recurringDepositAccountData?.productId
| find: recurringDepositsAccountTemplate?.productOptions : 'id' : 'name'
}}</span>
</div>
<div class="preview-field">
<span class="preview-label">{{ 'labels.inputs.Submitted On' | translate }}</span>
<span class="preview-value">{{ recurringDepositAccountData?.submittedOnDate | dateFormat }}</span>
</div>
<div class="preview-field">
<span class="preview-label">{{ 'labels.inputs.Field Officer' | translate }}</span>
<span class="preview-value">{{
recurringDepositAccountData?.fieldOfficerId
| find: recurringDepositsAccountProductTemplate?.fieldOfficerOptions : 'id' : 'displayName'
}}</span>
</div>
@if (recurringDepositAccountData?.externalId) {
<div class="preview-field">
<span class="preview-label">{{ 'labels.inputs.External Id' | translate }}</span>
<span class="preview-value">{{ recurringDepositAccountData.externalId }}</span>
</div>
}
</div>
</div>
</div>
<!-- ══ 1b. Status of Account ════════════════════════════════════ -->
@if (recurringDepositAccountData?.accountStatus) {
<div class="preview-section">
<div class="preview-section__header">
<i class="fas fa-id-card preview-section__icon"></i>
<span class="preview-section__title">Status of Account</span>
<span class="preview-section__badge">RBI Guidelines</span>
</div>
<div class="preview-body">
<!-- Status Tile -->
<div class="preview-soa-status-row">
<span class="preview-soa-tile">
@switch (recurringDepositAccountData.accountStatus) {
@case ('INDIVIDUAL_MALE') {
<i class="fas fa-male"></i> Individual (Male)
}
@case ('INDIVIDUAL_FEMALE') {
<i class="fas fa-female"></i> Individual (Female)
}
@case ('SINGLE') {
<i class="fas fa-user-circle"></i> Single Account
}
@case ('JOINT') {
<i class="fas fa-users"></i> Joint Account
}
@case ('MINOR') {
<i class="fas fa-child"></i> Minor Account
}
@case ('SENIOR_CITIZEN') {
<i class="fas fa-user-clock"></i> Senior Citizen
}
@default {
{{ recurringDepositAccountData.accountStatus }}
}
}
</span>
</div>
<!-- JOINT: Mode of Operation + Holders Table -->
@if (recurringDepositAccountData.accountStatus === 'JOINT') {
<div class="preview-grid preview-grid--three" style="margin-top: 12px">
<div class="preview-field">
<span class="preview-label">Mode of Operation</span>
<span class="preview-value">
@switch (recurringDepositAccountData.modeOfOperation) {
@case ('EITHER_OR_SURVIVOR') {
Either or Survivor
}
@case ('FORMER_OR_SURVIVOR') {
Former or Survivor
}
@case ('JOINTLY') {
Jointly
}
@case ('ANYONE_OR_SURVIVOR') {
Anyone or Survivor
}
@default {
{{ recurringDepositAccountData.modeOfOperation || '—' }}
}
}
</span>
</div>
</div>
@if (recurringDepositAccountData.jointHolders?.length) {
<div class="preview-soa-table-wrap">
<table class="preview-soa-tbl">
<thead>
<tr>
<th class="preview-soa-th">Sr.</th>
<th class="preview-soa-th">Holder Name</th>
<th class="preview-soa-th">CIF No.</th>
<th class="preview-soa-th">Ownership %</th>
<th class="preview-soa-th">Signing</th>
<th class="preview-soa-th">Role</th>
</tr>
</thead>
<tbody>
@for (holder of recurringDepositAccountData.jointHolders; track holder.clientId; let i = $index) {
<tr [class.preview-soa-tr--primary]="holder.isPrimary">
<td class="preview-soa-td">{{ i + 1 }}</td>
<td class="preview-soa-td">
{{ holder.displayName || holder.clientName || '—' }}
@if (holder.isPrimary) {
<span class="preview-soa-primary-tag">Primary</span>
}
</td>
<td class="preview-soa-td preview-mono">{{ holder.cifNumber || holder.clientCif || '—' }}</td>
<td class="preview-soa-td">{{ holder.sharePercentage ?? '—' }}%</td>
<td class="preview-soa-td">{{ holder.isMandatory ? 'Mandatory' : 'Optional' }}</td>
<td class="preview-soa-td">{{ holder.isPrimary ? 'Primary Account Holder' : 'Co-Holder' }}</td>
</tr>
}
</tbody>
</table>
</div>
}
}
<!-- INDIVIDUAL_MALE: Special Category -->
@if (
recurringDepositAccountData.accountStatus === 'INDIVIDUAL_MALE' && recurringDepositAccountData.specialCategory
) {
<div class="preview-grid preview-grid--three" style="margin-top: 12px">
<div class="preview-field">
<span class="preview-label">Special Category</span>
<span class="preview-value">
@switch (recurringDepositAccountData.specialCategory) {
@case ('DEFENCE') {
Defence Personnel
}
@case ('EX_SERVICEMAN') {
Ex-Serviceman
}
@case ('GOVT_EMPLOYEE') {
Government Employee
}
@case ('PHYSICALLY_CHALLENGED') {
Physically Challenged
}
@case ('NRI') {
NRI (Non-Resident Indian)
}
@case ('NONE') {
None / General
}
@default {
{{ recurringDepositAccountData.specialCategory }}
}
}
</span>
</div>
</div>
}
<!-- INDIVIDUAL_FEMALE: Weaker Section -->
@if (
recurringDepositAccountData.accountStatus === 'INDIVIDUAL_FEMALE' && recurringDepositAccountData.weakerSection
) {
<div class="preview-grid preview-grid--three" style="margin-top: 12px">
<div class="preview-field">
<span class="preview-label">Weaker Section</span>
<span class="preview-value">
@switch (recurringDepositAccountData.weakerSection) {
@case ('BPL') {
BPL (Below Poverty Line)
}
@case ('SC_ST') {
SC / ST Category
}
@case ('MINORITY') {
Minority Community
}
@case ('SHG') {
Self Help Group Member
}
@case ('PMJDY') {
PMJDY Beneficiary
}
@case ('NONE') {
None / General
}
@default {
{{ recurringDepositAccountData.weakerSection }}
}
}
</span>
</div>
</div>
}
<!-- MINOR: Guardian Details -->
@if (recurringDepositAccountData.accountStatus === 'MINOR') {
<div class="preview-grid preview-grid--three" style="margin-top: 12px">
@if (recurringDepositAccountData.guardianName) {
<div class="preview-field">
<span class="preview-label">Guardian Name</span>
<span class="preview-value">{{ recurringDepositAccountData.guardianName }}</span>
</div>
}
@if (recurringDepositAccountData.guardianCifNumber) {
<div class="preview-field">
<span class="preview-label">Guardian CIF</span>
<span class="preview-value preview-mono">{{ recurringDepositAccountData.guardianCifNumber }}</span>
</div>
}
@if (recurringDepositAccountData.guardianRelationship) {
<div class="preview-field">
<span class="preview-label">Relationship</span>
<span class="preview-value">{{ recurringDepositAccountData.guardianRelationship }}</span>
</div>
}
@if (recurringDepositAccountData.minorDateOfBirth) {
<div class="preview-field">
<span class="preview-label">Minor DOB</span>
<span class="preview-value">{{ recurringDepositAccountData.minorDateOfBirth }}</span>
</div>
}
</div>
}
</div>
</div>
}
<!-- ══ 1c. Linked Account ════════════════════════════════════════ -->
@if (recurringDepositAccountData?.linkedAccountId) {
<div class="preview-section">
<div class="preview-section__header">
<i class="fas fa-link preview-section__icon"></i>
<span class="preview-section__title">Linked Deposit Account</span>
<span class="preview-section__badge">{{ recurringDepositAccountData.linkedAccountType }}</span>
</div>
<div class="preview-body">
<div class="preview-grid preview-grid--three">
<div class="preview-field">
<span class="preview-label">Account No</span>
<span class="preview-value preview-mono">{{ recurringDepositAccountData.linkedAccountNo }}</span>
</div>
<div class="preview-field">
<span class="preview-label">Account Type</span>
<span class="preview-value">{{ recurringDepositAccountData.linkedAccountType }}</span>
</div>
<div class="preview-field">
<span class="preview-label">Account ID</span>
<span class="preview-value preview-mono">{{ recurringDepositAccountData.linkedAccountId }}</span>
</div>
</div>
</div>
</div>
}
<!-- ══ 2. Product Classification ════════════════════════════════ -->
@if (
recurringDepositsAccountProductTemplate?.accountType ||
recurringDepositsAccountProductTemplate?.customerSegment ||
recurringDepositsAccountProductTemplate?.productCode ||
recurringDepositsAccountProductTemplate?.effectiveDate ||
recurringDepositsAccountProductTemplate?.endDate ||
recurringDepositsAccountProductTemplate?.introducerRequired !== undefined ||
recurringDepositsAccountProductTemplate?.shareLinkingEnabled !== undefined
) {
<div class="preview-section">
<div class="preview-section__header">
<i class="fas fa-tags preview-section__icon"></i>
<span class="preview-section__title">Product Classification</span>
<span class="preview-section__badge">From Product</span>
</div>
<div class="preview-body">
<div class="preview-grid preview-grid--three">
@if (recurringDepositsAccountProductTemplate?.accountType) {
<div class="preview-field">
<span class="preview-label">Account Type</span>
<span class="preview-value">{{ recurringDepositsAccountProductTemplate.accountType }}</span>
</div>
}
<!-- Prefer what the details step actually selected (derived from the client's legal form) over
the product's default, which is only the starting suggestion. -->
@if (
recurringDepositAccountData?.customerSegment || recurringDepositsAccountProductTemplate?.customerSegment
) {
<div class="preview-field">
<span class="preview-label">Customer Segment</span>
<span class="preview-value">{{
recurringDepositAccountData?.customerSegment ?? recurringDepositsAccountProductTemplate.customerSegment
}}</span>
</div>
}
@if (recurringDepositsAccountProductTemplate?.productCode) {
<div class="preview-field">
<span class="preview-label">Product Code</span>
<span class="preview-value preview-mono">{{ recurringDepositsAccountProductTemplate.productCode }}</span>
</div>
}
@if (recurringDepositsAccountProductTemplate?.effectiveDate) {
<div class="preview-field">
<span class="preview-label">Effective Date</span>
<span class="preview-value">{{
recurringDepositsAccountProductTemplate.effectiveDate | dateFormat
}}</span>
</div>
}
@if (recurringDepositsAccountProductTemplate?.endDate) {
<div class="preview-field">
<span class="preview-label">End Date</span>
<span class="preview-value">{{ recurringDepositsAccountProductTemplate.endDate | dateFormat }}</span>
</div>
}
@if (
recurringDepositsAccountProductTemplate?.introducerRequired !== undefined &&
recurringDepositsAccountProductTemplate?.introducerRequired !== null
) {
<div class="preview-field">
<span class="preview-label">Introducer Required</span>
<span
class="preview-value preview-badge"
[class.preview-badge--yes]="recurringDepositsAccountProductTemplate.introducerRequired"
>
{{ recurringDepositsAccountProductTemplate.introducerRequired | yesNo }}
</span>
</div>
}
@if (
recurringDepositsAccountProductTemplate?.shareLinkingEnabled !== undefined &&
recurringDepositsAccountProductTemplate?.shareLinkingEnabled !== null
) {
<div class="preview-field">
<span class="preview-label">Deposit Account Link</span>
<span
class="preview-value preview-badge"
[class.preview-badge--yes]="recurringDepositsAccountProductTemplate.shareLinkingEnabled"
>
{{ recurringDepositsAccountProductTemplate.shareLinkingEnabled | yesNo }}
</span>
</div>
}
</div>
</div>
</div>
}
<!-- ══ 3. Introducer Details (if selected) ══════════════════════ -->
@if (recurringDepositAccountData?.introducerId) {
<div class="preview-section">
<div class="preview-section__header">
<i class="fas fa-user-tie preview-section__icon"></i>
<span class="preview-section__title">Introducer Details</span>
</div>
<div class="preview-body">
<div class="preview-grid preview-grid--three">
<div class="preview-field">
<span class="preview-label">Name</span>
<span class="preview-value">{{ recurringDepositAccountData?.introducerName || '—' }}</span>
</div>
@if (recurringDepositAccountData?.introducerCif) {
<div class="preview-field">
<span class="preview-label">CIF No</span>
<span class="preview-value preview-mono">{{ recurringDepositAccountData.introducerCif }}</span>
</div>
}
<div class="preview-field">
<span class="preview-label">Client ID</span>
<span class="preview-value preview-mono">{{ recurringDepositAccountData.introducerId }}</span>
</div>
</div>
</div>
</div>
}
<!-- ══ 4. Currency & Account Flags ══════════════════════════════ -->
<div class="preview-section">
<div class="preview-section__header">
<i class="fas fa-coins preview-section__icon"></i>
<span class="preview-section__title">{{ 'labels.heading.Currency' | translate }}</span>
</div>
<div class="preview-body">
<div class="preview-grid preview-grid--three">
<div class="preview-field">
<span class="preview-label">{{ 'labels.inputs.Currency' | translate }}</span>
<span class="preview-value">{{ currencyName }}</span>
</div>
<div class="preview-field">
<span class="preview-label">{{ 'labels.inputs.Decimal Places' | translate }}</span>
<span class="preview-value">{{ decimalPlaces }}</span>
</div>
<div class="preview-field">
<span class="preview-label">{{ 'labels.inputs.Currency In Multiples Of' | translate }}</span>
<span class="preview-value">{{ inMultiplesOf }}</span>
</div>
@if (recurringDepositsAccountProductTemplate?.withHoldTax) {
<div class="preview-field">
<span class="preview-label">{{ 'labels.inputs.Is Withhold Tax Applicable' | translate }}</span>
<span
class="preview-value preview-badge"
[class.preview-badge--yes]="recurringDepositAccountData?.withHoldTax"
>
{{ recurringDepositAccountData?.withHoldTax | yesNo }}
</span>
</div>
}
@if (recurringDepositAccountData?.withHoldTax && recurringDepositsAccountProductTemplate?.taxGroup?.name) {
<div class="preview-field">
<span class="preview-label">{{ 'labels.inputs.Tax Group' | translate }}</span>
<span class="preview-value">{{ recurringDepositsAccountProductTemplate.taxGroup.name }}</span>
</div>
}
<div class="preview-field">
<span class="preview-label">Auto Debit Facility</span>
<span class="preview-value preview-badge" [class.preview-badge--yes]="rdCurrencyFlags?.autoDebitFacility">
{{ rdCurrencyFlags?.autoDebitFacility | yesNo }}
</span>
</div>
@if (
recurringDepositsAccountProductTemplate?.dormancyAlert !== undefined &&
recurringDepositsAccountProductTemplate?.dormancyAlert !== null
) {
<div class="preview-field">
<span class="preview-label">Dormancy Alert</span>
<span
class="preview-value preview-badge"
[class.preview-badge--yes]="recurringDepositsAccountProductTemplate.dormancyAlert"
>
{{ recurringDepositsAccountProductTemplate.dormancyAlert | yesNo }}
</span>
</div>
}
@if (
recurringDepositsAccountProductTemplate?.nominationFacility !== undefined &&
recurringDepositsAccountProductTemplate?.nominationFacility !== null
) {
<div class="preview-field">
<span class="preview-label">Nomination Facility</span>
<span
class="preview-value preview-badge"
[class.preview-badge--yes]="recurringDepositsAccountProductTemplate.nominationFacility"
>
{{ recurringDepositsAccountProductTemplate.nominationFacility | yesNo }}
</span>
</div>
}
</div>
</div>
</div>
<!-- ══ 5. Dormancy Monitoring ════════════════════════════════════ -->
@if (
recurringDepositsAccountProductTemplate?.dormancyAlert ||
recurringDepositsAccountProductTemplate?.isDormancyTrackingActive
) {
<div class="preview-section">
<div class="preview-section__header">
<i class="fas fa-moon preview-section__icon"></i>
<span class="preview-section__title">Dormancy Monitoring</span>
<span
class="preview-section__badge"
[class.preview-section__badge--active]="recurringDepositsAccountProductTemplate?.isDormancyTrackingActive"
>
{{ recurringDepositsAccountProductTemplate?.isDormancyTrackingActive ? 'Active' : 'Inactive' }}
</span>
</div>
<div class="preview-body">
<div class="preview-dormancy-timeline">
<div class="preview-dorm-step">
<div class="preview-dorm-step__dot preview-dorm-step__dot--inactive"></div>
<div class="preview-dorm-step__body">
<span class="preview-dorm-step__label">Inactive</span>
<span class="preview-dorm-step__days">
@if (recurringDepositsAccountProductTemplate?.daysToInactive != null) {
After {{ recurringDepositsAccountProductTemplate.daysToInactive }} days of no transaction
} @else {
Not configured
}
</span>
</div>
</div>
<div class="preview-dorm-connector"></div>
<div class="preview-dorm-step">
<div class="preview-dorm-step__dot preview-dorm-step__dot--dormant"></div>
<div class="preview-dorm-step__body">
<span class="preview-dorm-step__label">Dormant</span>
<span class="preview-dorm-step__days">
@if (recurringDepositsAccountProductTemplate?.daysToDormancy != null) {
{{ recurringDepositsAccountProductTemplate.daysToDormancy }} days after inactive
} @else {
Not configured
}
</span>
</div>
</div>
<div class="preview-dorm-connector"></div>
<div class="preview-dorm-step">
<div class="preview-dorm-step__dot preview-dorm-step__dot--escheat"></div>
<div class="preview-dorm-step__body">
<span class="preview-dorm-step__label">Escheat</span>
<span class="preview-dorm-step__days">
@if (recurringDepositsAccountProductTemplate?.daysToEscheat != null) {
{{ recurringDepositsAccountProductTemplate.daysToEscheat }} days after dormant
} @else {
Not configured
}
</span>
</div>
</div>
</div>
<div class="preview-dorm-flags">
<span
class="preview-dorm-flag"
[class.preview-dorm-flag--on]="recurringDepositsAccountProductTemplate?.dormancyAlert"
>
<i class="fas fa-bell"></i> Alert
{{ recurringDepositsAccountProductTemplate?.dormancyAlert ? 'Enabled' : 'Disabled' }}
</span>
<span
class="preview-dorm-flag"
[class.preview-dorm-flag--on]="recurringDepositsAccountProductTemplate?.isDormancyTrackingActive"
>
<i class="fas fa-eye"></i> Tracking
{{ recurringDepositsAccountProductTemplate?.isDormancyTrackingActive ? 'Active' : 'Inactive' }}
</span>
</div>
</div>
</div>
}
<!-- ══ 6. Nominee Details (if filled) ═══════════════════════════ -->
@if (rdNominees?.length > 0) {
<div class="preview-section">
<div class="preview-section__header">
<i class="fas fa-user-shield preview-section__icon"></i>
<span class="preview-section__title">Nominee Details</span>
<span class="preview-section__badge">{{ rdNominees.length }} Nominee(s)</span>
</div>
<div class="preview-body">
@for (nom of rdNominees; track nom.nomineeClientId; let i = $index) {
@if (i > 0) {
<hr class="preview-nom-divider" />
}
<div class="preview-grid preview-grid--three">
<div class="preview-field">
<span class="preview-label">Name</span>
<span class="preview-value">{{ nom.nomineeDisplayName || '—' }}</span>
</div>
<div class="preview-field">
<span class="preview-label">Client ID</span>
<span class="preview-value preview-mono">{{ nom.nomineeClientId || '—' }}</span>
</div>
<div class="preview-field">
<span class="preview-label">Relationship</span>
<span class="preview-value">{{ nom.relationshipName || '—' }}</span>
</div>
<div class="preview-field">
<span class="preview-label">Share %</span>
<span class="preview-value">{{ nom.percentageShare ?? '—' }}%</span>
</div>
<div class="preview-field">
<span class="preview-label">Minor</span>
<span class="preview-value">{{ nom.nomineeIsMinor ? 'Yes' : 'No' }}</span>
</div>
@if (nom.guardianDisplayName) {
<div class="preview-field">
<span class="preview-label">Guardian</span>
<span class="preview-value">{{ nom.guardianDisplayName }}</span>
</div>
}
@if (nom.remarks) {
<div class="preview-field">
<span class="preview-label">Remarks</span>
<span class="preview-value">{{ nom.remarks }}</span>
</div>
}
</div>
}
</div>
</div>
}
<!-- ══ 6. Maturity Summary ═══════════════════════════════════ -->
@if (rdMaturityAmount) {
<div class="preview-section">
<div class="preview-section__header">
<i class="fas fa-piggy-bank preview-section__icon"></i>
<span class="preview-section__title">Maturity Summary</span>
<span class="preview-section__badge preview-section__badge--active">Projected</span>
</div>
<div class="preview-body">
<div class="preview-grid preview-grid--three">
<div class="preview-field">
<span class="preview-label">Total Deposit Amount</span>
<span class="preview-value"
>{{ rdMaturityAmount - rdInterestEarned | formatNumber }} {{ currencyName }}</span
>
</div>
<div class="preview-field">
<span class="preview-label">
@if (rdIsSeniorCitizen && rdSeniorCitizenBonus > 0) {
<i class="fas fa-user-shield" style="color: #5b21b6; margin-right: 4px"></i>Sr. Citizen Rate
} @else {
Applicable Interest Rate
}
</span>
<span class="preview-value" [style.color]="rdIsSeniorCitizen && rdSeniorCitizenBonus > 0 ? '#5b21b6' : ''">
{{ rdAppliedInterestRate | formatNumber }}%
</span>
</div>
<div class="preview-field">
<span class="preview-label">Tenure</span>
<span class="preview-value">{{ selectedTenureLabel }}</span>
</div>
<div class="preview-field">
<span class="preview-label">Estimated Interest Earned</span>
<span class="preview-value" style="color: var(--theme-success, #16a34a); font-weight: 500">
+ {{ rdInterestEarned | formatNumber }} {{ currencyName }}
</span>
</div>
<div class="preview-field">
<span class="preview-label">Days in Year</span>
<span class="preview-value">{{ rdDaysInYear ?? 365 }} Days</span>
</div>
<div class="preview-field" style="grid-column: span 1">
<span class="preview-label">Projected Maturity Amount</span>
<span class="preview-value preview-mono" style="font-weight: 600; font-size: 1.25rem">
{{ rdMaturityAmount | formatNumber }} {{ currencyName }}
</span>
</div>
</div>
</div>
</div>
}
<!-- ══ 7. Interest Rate Chart ═══════════════════════════════════ -->
@if (interestRateChartData?.length > 0) {
<div class="preview-section">
<div class="preview-section__header">
<i class="fas fa-chart-line preview-section__icon"></i>
<span class="preview-section__title">{{ 'labels.heading.Interest Rate Chart' | translate }}</span>
@if (rdTenureDays) {
<span class="preview-section__badge preview-section__badge--tenure">
<i class="fas fa-calendar-check"></i> Selected Tenure: {{ selectedTenureLabel }}
</span>
}
</div>
<div class="preview-body">
<!-- Selected Tenure + Rate Banner -->
@if (rdTenureDays && matchedSlabIndex >= 0) {
<!-- Senior Citizen Status Banner -->
@if (rdIsSeniorCitizen) {
@if (rdSeniorCitizenBonus > 0) {
<div class="preview-sc-status preview-sc-status--applied">
<i class="fas fa-user-shield"></i>
<span>Senior Citizen Rate Applied</span>
<span class="preview-sc-status__bonus">+{{ rdSeniorCitizenBonus | formatNumber }}% bonus</span>
</div>
} @else {
<div class="preview-sc-status preview-sc-status--notice">
<i class="fas fa-info-circle"></i>
<span>Senior Citizen selected — no additional rate configured for this slab</span>
</div>
}
}
<div
class="preview-tenure-banner"
[class.preview-tenure-banner--sc]="rdIsSeniorCitizen && rdSeniorCitizenBonus > 0"
>
<div class="preview-tenure-banner__left">
<i class="fas fa-calendar-check"></i>
<div>
<span class="preview-tenure-banner__label">Your RD Tenure</span>
<span class="preview-tenure-banner__value">{{ selectedTenureLabel }}</span>
</div>
</div>
<div class="preview-tenure-banner__divider"></div>
<div class="preview-tenure-banner__right">
<span class="preview-tenure-banner__rate-label">
@if (rdIsSeniorCitizen && rdSeniorCitizenBonus > 0) {
<i class="fas fa-user-shield" style="color: #5b21b6; margin-right: 4px"></i>Sr. Citizen Rate
} @else {
Applicable Interest Rate
}
</span>
<span
class="preview-tenure-banner__rate"
[style.color]="rdIsSeniorCitizen && rdSeniorCitizenBonus > 0 ? '#5b21b6' : ''"
>{{ rdAppliedInterestRate | formatNumber }}%</span
>
</div>
<div class="preview-tenure-banner__slab">
<i class="fas fa-layer-group"></i>
Slab: {{ interestRateChartData[matchedSlabIndex]?.fromPeriod }}–{{
interestRateChartData[matchedSlabIndex]?.toPeriod ?? '∞'
}}
{{ interestRateChartData[matchedSlabIndex]?.periodType?.value }}
</div>
</div>
}
<div class="preview-grid preview-grid--three" style="margin-bottom: 1rem">
@if (chartName) {
<div class="preview-field">
<span class="preview-label">{{ 'labels.inputs.name' | translate }}</span>
<span class="preview-value">{{ chartName }}</span>
</div>
}
@if (chartFromDate) {
<div class="preview-field">
<span class="preview-label">Valid From</span>
<span class="preview-value">{{ chartFromDate | dateFormat }}</span>
</div>
}
<div class="preview-field">
<span class="preview-label">Primary Grouping by Amount</span>
<span class="preview-value preview-badge" [class.preview-badge--yes]="isPrimaryGroupingByAmount">
{{ isPrimaryGroupingByAmount | yesNo }}
</span>
</div>
</div>
@if (interestRateChartData?.length) {
<table
class="mat-elevation-z1 irc-table preview-table"
mat-table
[dataSource]="interestRateChartData"
multiTemplateDataRows
>
<ng-container matColumnDef="period">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Period' | translate }}</th>
<td mat-cell *matCellDef="let chartSlab">
{{ chartSlab.fromPeriod }} - {{ chartSlab.toPeriod }}&nbsp;{{
chartSlab.periodType?.value | translateKey: 'catalogs'
}}
</td>
</ng-container>
<ng-container matColumnDef="amountRange">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Amount Range' | translate }}</th>
<td mat-cell *matCellDef="let chartSlab">
{{ chartSlab.amountRangeFrom | formatNumber }} - {{ chartSlab.amountRangeTo | formatNumber }}
</td>
</ng-container>
<ng-container matColumnDef="interest">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Interest' | translate }}</th>
<td mat-cell *matCellDef="let chartSlab">{{ chartSlab.annualInterestRate | formatNumber }} %</td>
</ng-container>
<ng-container matColumnDef="description">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Description' | translate }}</th>
<td mat-cell *matCellDef="let chartSlab">{{ chartSlab.description }}</td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Actions' | translate }}</th>
<td mat-cell *matCellDef="let chartSlab; let chartSlabIndex = dataIndex">
<button
mat-button
color="primary"
(click)="expandChartSlabIndex = expandChartSlabIndex === chartSlabIndex ? null : chartSlabIndex"
>
<fa-icon
[icon]="expandChartSlabIndex === chartSlabIndex ? 'eye-slash' : 'eye'"
class="m-r-10"
></fa-icon>
{{
(expandChartSlabIndex === chartSlabIndex
? 'labels.buttons.Hide Incentives'
: 'labels.buttons.View Incentives'
) | translate
}}
</button>
</td>
</ng-container>
<ng-container matColumnDef="incentives">
<td
mat-cell
*matCellDef="let chartSlab; let chartSlabIndex = dataIndex"
[attr.colspan]="chartSlabsDisplayedColumns?.length"
>
<div
class="layout-row-wrap flex-100 incentives"
[@expandChartSlab]="chartSlabIndex === expandChartSlabIndex ? 'expanded' : 'collapsed'"
>
<mat-card class="layout-row-wrap flex-100">
<h4 class="m-b-10 flex-13">{{ 'labels.heading.Incentives' | translate }}</h4>
<table
class="flex-100 mat-elevation-z1"
mat-table
[dataSource]="chartSlab.incentives"
*ngIf="chartSlab.incentives?.length"
>
<ng-container matColumnDef="entityType">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Entity Type' | translate }}</th>
<td mat-cell *matCellDef="let incentive">{{ incentive.entityType?.value }}</td>
</ng-container>
<ng-container matColumnDef="attributeName">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Attribute Name' | translate }}</th>
<td mat-cell *matCellDef="let incentive">{{ incentive.attributeName?.value }}</td>
</ng-container>
<ng-container matColumnDef="conditionType">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Condition Type' | translate }}</th>
<td mat-cell *matCellDef="let incentive">{{ incentive.conditionType?.value | titlecase }}</td>
</ng-container>
<ng-container matColumnDef="attributeValue">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Attribute Value' | translate }}</th>
<td mat-cell *matCellDef="let incentive">{{ incentive.attributeValueDesc }}</td>
</ng-container>
<ng-container matColumnDef="incentiveType">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Incentive Type' | translate }}</th>
<td mat-cell *matCellDef="let incentive">{{ incentive.incentiveType?.value }}</td>
</ng-container>
<ng-container matColumnDef="amount">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Interest' | translate }}</th>
<td mat-cell *matCellDef="let incentive">{{ incentive.amount | formatNumber }}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="incentivesDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: incentivesDisplayedColumns"></tr>
</table>
</mat-card>
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="chartSlabsDisplayedColumns"></tr>
<tr
mat-row
*matRowDef="let row; columns: chartSlabsDisplayedColumns; let i = dataIndex"
[class.preview-slab-row--matched]="i === matchedSlabIndex"
></tr>
<tr mat-row *matRowDef="let row; columns: chartSlabsIncentivesDisplayedColumns" class="incentives-row"></tr>
</table>
@if (rdTenureDays && matchedSlabIndex >= 0) {
<div class="preview-slab-legend">
<span class="preview-slab-legend__dot"></span>
Highlighted row is the slab applicable for your selected tenure of
<strong>{{ selectedTenureLabel }}</strong>
</div>
}
}
</div>
</div>
}
</div>
<div class="preview-section">
<div class="preview-section__header">
<i class="fas fa-flag-checkered preview-section__icon"></i>
<span class="preview-section__title">Maturity &amp; Pre-mature Closure</span>
</div>
<div class="preview-body">
<div class="preview-grid preview-grid--three">
<div class="preview-field">
<span class="preview-label">{{ 'labels.inputs.Maturity Instructions' | translate }}</span>
<span class="preview-value">{{ closureMaturityInstructionLabel }}</span>
</div>
@if (closureSettings?.transferToSavingsId) {
<div class="preview-field">
<span class="preview-label">{{ 'labels.inputs.Transfer to savings account' | translate }}</span>
<span class="preview-value">{{ closureTransferToSavingsLabel }}</span>
</div>
}
<div class="preview-field">
<span class="preview-label">{{ 'labels.inputs.Apply Penal Interest (less)' | translate }}</span>
<span class="preview-value">{{ closureSettings?.preClosurePenalApplicable | yesNo }}</span>
</div>
@if (closureSettings?.preClosurePenalApplicable) {
<div class="preview-field">
<span class="preview-label">{{ 'labels.inputs.Penal Interest' | translate }} (%)</span>
<span class="preview-value">{{ closureSettings?.preClosurePenalInterest }}%</span>
</div>
<div class="preview-field">
<span class="preview-label">{{ 'labels.inputs.Period' | translate }}</span>
<span class="preview-value">{{ closurePenalInterestOnTypeLabel }}</span>
</div>
}
</div>
</div>
</div>
@if (!hideButtons) {
<div class="layout-row responsive-column align-center gap-2px margin-t">
<button mat-raised-button matStepperPrevious>
<fa-icon icon="arrow-left" class="m-r-10"></fa-icon>
{{ 'labels.buttons.Previous' | translate }}
</button>
<button mat-raised-button [routerLink]="['../..']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
<button mat-raised-button color="primary" class="preview-submit-row__primary" (click)="submitEvent.emit()">
<fa-icon icon="check" class="m-r-10"></fa-icon>
{{ 'labels.buttons.Submit' | translate }}
</button>
</div>
}