730 lines
30 KiB
HTML
730 lines
30 KiB
HTML
<!--
|
||
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">TREASURY · INVESTMENT · FIXED DEPOSIT</div>
|
||
<h1 class="pg-title">FD Investment</h1>
|
||
<p class="pg-sub">
|
||
Fixed deposits the bank places with other banks — placement, maturity, premature closure and renewal.
|
||
</p>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="cctr-tabs">
|
||
<button
|
||
type="button"
|
||
class="pg-btn pg-btn--ghost"
|
||
[class.pg-btn--active]="activeTab === 'holdings'"
|
||
(click)="setTab('holdings')"
|
||
>
|
||
Holdings
|
||
</button>
|
||
<button
|
||
type="button"
|
||
class="pg-btn pg-btn--ghost"
|
||
[class.pg-btn--active]="activeTab === 'purchase'"
|
||
(click)="setTab('purchase')"
|
||
>
|
||
01 FD Purchase Entry
|
||
</button>
|
||
<button
|
||
type="button"
|
||
class="pg-btn pg-btn--ghost"
|
||
[class.pg-btn--active]="activeTab === 'closure'"
|
||
(click)="setTab('closure')"
|
||
>
|
||
02 Maturity / Premature / Renewal
|
||
</button>
|
||
<button
|
||
type="button"
|
||
class="pg-btn pg-btn--ghost"
|
||
[class.pg-btn--active]="activeTab === 'interest'"
|
||
(click)="setTab('interest')"
|
||
>
|
||
03 Interest Entry
|
||
</button>
|
||
</div>
|
||
|
||
<!-- ===================== HOLDINGS ===================== -->
|
||
@if (activeTab === 'holdings') {
|
||
<div class="pg-card">
|
||
<div class="pos-section-label">
|
||
FD Holdings Register — {{ activeFds.length }} active, ₹{{ totalPlaced | number: '1.2-2' }} placed
|
||
</div>
|
||
<table class="pg-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Deal No</th>
|
||
<th>Bank</th>
|
||
<th>Certificate</th>
|
||
<th>Deal Date</th>
|
||
<th class="num">Amount</th>
|
||
<th class="num">Rate</th>
|
||
<th>Maturity Date</th>
|
||
<th class="num">Days</th>
|
||
<th>Interest</th>
|
||
<th class="num col-in">Interest (expected)</th>
|
||
<th class="num col-net">Maturity Amount</th>
|
||
<th>Status</th>
|
||
<th>Voucher</th>
|
||
<th></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
@for (f of fds; track f.id) {
|
||
<tr>
|
||
<td>
|
||
<span class="pg-chip">{{ f.dealNo }}</span>
|
||
</td>
|
||
<td>{{ f.partyName }}</td>
|
||
<td>{{ f.certNo }}</td>
|
||
<td>{{ f.dealDate }}</td>
|
||
<td class="num">₹{{ f.principal | number: '1.2-2' }}</td>
|
||
<td class="num">{{ f.intRate }}%</td>
|
||
<td>{{ f.maturityDate }}</td>
|
||
<td class="num">{{ f.days }}</td>
|
||
<td>
|
||
{{ payoutLabel(f.payout) }}
|
||
@if (f.payout === 'MATURITY') {
|
||
<br /><small>{{ calcLabel(f.calcType) }}</small>
|
||
}
|
||
</td>
|
||
<td class="num col-in">₹{{ f.expectedInterest | number: '1.2-2' }}</td>
|
||
<td class="num col-net">₹{{ f.expectedMaturityAmount | number: '1.2-2' }}</td>
|
||
<td>
|
||
{{ f.status }}
|
||
@if (f.closedOnDate) {
|
||
<br /><small
|
||
>{{ f.closedOnDate }} · interest ₹{{ f.closureInterest | number: '1.2-2' }}
|
||
@if (f.closureTds) {
|
||
· TDS ₹{{ f.closureTds | number: '1.2-2' }}
|
||
}
|
||
@if (f.closurePenal) {
|
||
· penal ₹{{ f.closurePenal | number: '1.2-2' }}
|
||
}
|
||
</small>
|
||
}
|
||
@if (f.renewedFromDealNo) {
|
||
<br /><small>renewal of {{ f.renewedFromDealNo }}</small>
|
||
}
|
||
</td>
|
||
<td>
|
||
{{ f.voucherNo }}
|
||
@if (f.closureVoucherNo) {
|
||
<br /><small>closed: {{ f.closureVoucherNo }}</small>
|
||
}
|
||
</td>
|
||
<td>
|
||
@if (f.status === 'ACTIVE') {
|
||
<button type="button" class="pg-btn pg-btn--ghost" (click)="openInterest(f)">Interest</button>
|
||
<button type="button" class="pg-btn pg-btn--ghost" (click)="openClosure(f)">Close / Renew</button>
|
||
}
|
||
</td>
|
||
</tr>
|
||
} @empty {
|
||
<tr>
|
||
<td colspan="14" class="pg-empty">No FDs placed yet. Use 01 FD Purchase Entry.</td>
|
||
</tr>
|
||
}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
}
|
||
|
||
<!-- ===================== 01 FD PURCHASE ===================== -->
|
||
@if (activeTab === 'purchase') {
|
||
<div class="pg-card">
|
||
<div class="pos-section-label">Investment - FD Purchase Entry (money placed with another bank)</div>
|
||
<div class="inv-form-grid">
|
||
<label class="inv-form-field">
|
||
<span>* Bank (FD Party)</span>
|
||
<select [(ngModel)]="form.partyId" (ngModelChange)="refreshQuote()">
|
||
<option [ngValue]="null">-- Select --</option>
|
||
@for (p of fdParties; track p.id) {
|
||
<option [ngValue]="p.id">{{ p.partyCode }} — {{ p.partyName }}</option>
|
||
}
|
||
</select>
|
||
</label>
|
||
@if (selectedParty; as p) {
|
||
<label class="inv-form-field"
|
||
><span>FD GL</span><input type="text" [value]="p.glCode + ' ' + p.glName" readonly
|
||
/></label>
|
||
<label class="inv-form-field"
|
||
><span>Interest GL</span
|
||
><input
|
||
type="text"
|
||
[value]="
|
||
p.interestGlCode
|
||
? p.interestGlCode + ' ' + p.interestGlName
|
||
: 'Not mapped — set it in Bank / Party Master'
|
||
"
|
||
readonly
|
||
/></label>
|
||
}
|
||
<label class="inv-form-field"
|
||
><span>* Certificate No</span><input type="text" maxlength="50" [(ngModel)]="form.certNo"
|
||
/></label>
|
||
<label class="inv-form-field"
|
||
><span>Certificate Date</span><mifosx-date-ddmmyyyy [(ngModel)]="form.certDate"></mifosx-date-ddmmyyyy
|
||
></label>
|
||
<label class="inv-form-field"
|
||
><span>* Deal Date</span
|
||
><mifosx-date-ddmmyyyy [(ngModel)]="form.dealDate" (ngModelChange)="onPeriodChange()"></mifosx-date-ddmmyyyy
|
||
></label>
|
||
<label class="inv-form-field"
|
||
><span>* Amount (₹)</span><input type="number" min="0" [(ngModel)]="form.amount" (change)="refreshQuote()"
|
||
/></label>
|
||
<label class="inv-form-field"
|
||
><span>* Interest Rate %</span
|
||
><input type="number" min="0" step="0.01" [(ngModel)]="form.intRate" (change)="refreshQuote()"
|
||
/></label>
|
||
<label class="inv-form-field"
|
||
><span>Period – Years</span
|
||
><input type="number" min="0" [(ngModel)]="form.periodYears" (change)="onPeriodChange()"
|
||
/></label>
|
||
<label class="inv-form-field"
|
||
><span>Period – Months</span
|
||
><input type="number" min="0" [(ngModel)]="form.periodMonths" (change)="onPeriodChange()"
|
||
/></label>
|
||
<label class="inv-form-field"
|
||
><span>Period – Days</span
|
||
><input type="number" min="0" [(ngModel)]="form.periodDays" (change)="onPeriodChange()"
|
||
/></label>
|
||
<label class="inv-form-field"
|
||
><span>* Maturity Date</span
|
||
><mifosx-date-ddmmyyyy [(ngModel)]="form.maturityDate" (ngModelChange)="refreshQuote()"></mifosx-date-ddmmyyyy
|
||
></label>
|
||
<label class="inv-form-field">
|
||
<span>* Interest Paid</span>
|
||
<select [(ngModel)]="form.payout" (ngModelChange)="refreshQuote()">
|
||
@for (o of payoutOptions; track o.value) {
|
||
<option [ngValue]="o.value">{{ o.label }}</option>
|
||
}
|
||
</select>
|
||
</label>
|
||
@if (form.payout === 'MATURITY') {
|
||
<label class="inv-form-field">
|
||
<span>Maturity Calculation</span>
|
||
<select [(ngModel)]="form.calcType" (ngModelChange)="refreshQuote()">
|
||
@for (o of calcTypeOptions; track o.value) {
|
||
<option [ngValue]="o.value">{{ o.label }}</option>
|
||
}
|
||
</select>
|
||
</label>
|
||
}
|
||
<label class="inv-form-field">
|
||
<span>* Paid From (our bank)</span>
|
||
<select [(ngModel)]="form.bankGlAccountId">
|
||
<option [ngValue]="null">-- Select --</option>
|
||
@for (g of bankGlOptions; track g.id) {
|
||
<option [ngValue]="g.id">{{ g.glCode }} — {{ g.name }}</option>
|
||
}
|
||
</select>
|
||
</label>
|
||
<label class="inv-form-field"
|
||
><span>Remarks</span><input type="text" maxlength="500" [(ngModel)]="form.remarks"
|
||
/></label>
|
||
</div>
|
||
|
||
@if (quote; as q) {
|
||
<div class="pos-section-label">FD Calculation</div>
|
||
<div class="inv-form-grid">
|
||
<label class="inv-form-field"><span>Days</span><input type="text" [value]="q.days" readonly /></label>
|
||
<label class="inv-form-field"
|
||
><span>Interest (expected)</span
|
||
><input type="text" [value]="'₹' + (q.expectedInterest | number: '1.2-2')" readonly
|
||
/></label>
|
||
<label class="inv-form-field"
|
||
><span>Maturity Amount</span
|
||
><input
|
||
type="text"
|
||
[value]="
|
||
q.expectedMaturityAmount === null || q.expectedMaturityAmount === undefined
|
||
? ''
|
||
: '₹' + (q.expectedMaturityAmount | number: '1.2-2')
|
||
"
|
||
readonly
|
||
/></label>
|
||
@if (q.payout !== 'MATURITY') {
|
||
<label class="inv-form-field"
|
||
><span
|
||
>Approx. interest per {{ q.payout === 'HALF_YEARLY' ? 'half year' : 'year' }} (actual days vary)</span
|
||
><input type="text" [value]="'₹' + (q.periodInterest | number: '1.2-2')" readonly
|
||
/></label>
|
||
}
|
||
</div>
|
||
@if (form.amount && selectedParty && form.bankGlAccountId) {
|
||
<p class="pg-sub" style="padding: 0 16px">
|
||
Voucher on save: Dr {{ selectedParty!.glCode }} {{ selectedParty!.glName }} ₹{{
|
||
form.amount | number: '1.2-2'
|
||
}}
|
||
/ Cr {{ bankGlName(form.bankGlAccountId) }} ₹{{ form.amount | number: '1.2-2' }}
|
||
</p>
|
||
}
|
||
|
||
@if (q.limit; as l) {
|
||
<div class="pos-section-label">RBI Limit — deposits with other banks (as on {{ l.asOnDate }})</div>
|
||
@if (l.totalDeposits === null || l.totalDeposits === undefined) {
|
||
<div class="inv-form-grid">
|
||
<label class="inv-form-field"
|
||
><span>* Total Deposits as on {{ l.asOnDate }} (₹)</span
|
||
><input type="number" min="0" [(ngModel)]="baseAmount"
|
||
/></label>
|
||
<label class="inv-form-field"
|
||
><span>From Deposit GLs (suggestion)</span
|
||
><input type="text" [value]="'₹' + (l.glTotalDeposits | number: '1.2-2')" readonly
|
||
/></label>
|
||
</div>
|
||
<div class="inv-form-actions">
|
||
<button type="button" class="pg-btn pg-btn--primary" [disabled]="savingBase" (click)="saveBase()">
|
||
Save Total Deposits
|
||
</button>
|
||
</div>
|
||
} @else {
|
||
<table class="pg-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Limit</th>
|
||
<th class="num">Allowed</th>
|
||
<th class="num">After this FD</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>
|
||
All banks — 20% of total deposits ₹{{ l.totalDeposits | number: '1.2-2' }} <br /><small
|
||
>FDs ₹{{ l.fdOutstanding | number: '1.2-2' }} + current accounts with banks ₹{{
|
||
l.bankBalances | number: '1.2-2'
|
||
}}</small
|
||
>
|
||
</td>
|
||
<td class="num">₹{{ l.grossLimit | number: '1.2-2' }}</td>
|
||
<td class="num">₹{{ l.grossAfter | number: '1.2-2' }}</td>
|
||
</tr>
|
||
@if (l.partyName) {
|
||
<tr>
|
||
<td>{{ l.partyName }} — 5% with one bank</td>
|
||
<td class="num">₹{{ l.bankLimit | number: '1.2-2' }}</td>
|
||
<td class="num">₹{{ l.bankAfter | number: '1.2-2' }}</td>
|
||
</tr>
|
||
}
|
||
</tbody>
|
||
</table>
|
||
}
|
||
<p class="pg-sub" style="padding: 0 16px" [style.color]="l.withinLimits ? '#067647' : '#b42318'">
|
||
{{ l.message }}
|
||
</p>
|
||
}
|
||
}
|
||
@if (quoteError) {
|
||
<p class="pg-sub" style="padding: 0 16px; color: #b42318">{{ quoteError }}</p>
|
||
}
|
||
|
||
<div class="inv-form-actions">
|
||
<button type="button" class="pg-btn pg-btn--primary" [disabled]="saving" (click)="savePurchase()">Save</button>
|
||
<button type="button" class="pg-btn pg-btn--ghost" (click)="resetPurchase()">Cancel</button>
|
||
<button type="button" class="pg-btn pg-btn--ghost" (click)="setTab('holdings')">Exit</button>
|
||
</div>
|
||
</div>
|
||
}
|
||
|
||
<!-- ===================== 03 INTEREST ENTRY ===================== -->
|
||
@if (activeTab === 'interest') {
|
||
<div class="pg-card">
|
||
<div class="pos-section-label">
|
||
Investment - FD Interest Entry (31 Mar / 30 Sep provision and interest payouts)
|
||
</div>
|
||
<div class="inv-form-grid">
|
||
<label class="inv-form-field">
|
||
<span>* FD (Deal No)</span>
|
||
<select [(ngModel)]="interestFdId" (ngModelChange)="loadSchedule()">
|
||
<option [ngValue]="null">-- Select --</option>
|
||
@for (f of activeFds; track f.id) {
|
||
<option [ngValue]="f.id">
|
||
{{ f.dealNo }} — {{ f.partyName }} — ₹{{ f.principal | number: '1.0-0' }} @ {{ f.intRate }}%
|
||
</option>
|
||
}
|
||
</select>
|
||
</label>
|
||
@if (schedule; as s) {
|
||
<label class="inv-form-field"
|
||
><span>Interest Paid</span><input type="text" [value]="payoutLabel(s.fd.payout)" readonly
|
||
/></label>
|
||
<label class="inv-form-field"
|
||
><span>Interest GL</span
|
||
><input type="text" [value]="s.fd.interestGlCode + ' ' + s.fd.interestGlName" readonly
|
||
/></label>
|
||
<label class="inv-form-field"
|
||
><span>Provisioned, not yet received</span
|
||
><input type="text" [value]="'₹' + (s.provisioned | number: '1.2-2')" readonly
|
||
/></label>
|
||
}
|
||
</div>
|
||
@if (schedule; as s) {
|
||
<p class="pg-sub" style="padding: 0 16px">
|
||
Days are actual / 365. A provision books the interest earned since the last payout (Dr 100603 Interest
|
||
Receivable / Cr {{ s.fd.interestGlCode }}); a payout clears what was provisioned and books the rest. Post the
|
||
lines in date order, on or after their date. The interest of the last period comes with the maturity (02
|
||
Maturity tab).
|
||
</p>
|
||
<table class="pg-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Type</th>
|
||
<th>Date</th>
|
||
<th>Period</th>
|
||
<th class="num">Days</th>
|
||
<th class="num">Interest</th>
|
||
<th class="num">Already Provisioned</th>
|
||
<th class="num col-in">Amount</th>
|
||
<th>Voucher</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
@for (r of s.rows; track r.lineType + r.intDate) {
|
||
<tr>
|
||
<td>{{ lineLabel(r.lineType) }}</td>
|
||
<td>{{ r.intDate }}</td>
|
||
<td>{{ r.fromDate }} → {{ r.toDate }}</td>
|
||
<td class="num">{{ r.days }}</td>
|
||
<td class="num">₹{{ r.grossInterest | number: '1.2-2' }}</td>
|
||
<td class="num">{{ r.alreadyBooked ? '₹' + (r.alreadyBooked | number: '1.2-2') : '' }}</td>
|
||
<td class="num col-in">₹{{ r.amount | number: '1.2-2' }}</td>
|
||
<td>
|
||
@if (r.posted) {
|
||
<span class="pg-chip">Posted · {{ r.voucherNo }}</span>
|
||
@if (r.tds) {
|
||
<br /><small>TDS ₹{{ r.tds | number: '1.2-2' }}</small>
|
||
}
|
||
} @else if (r.lineType === 'MATURITY') {
|
||
<button type="button" class="pg-btn pg-btn--ghost" (click)="openClosure(s.fd)">
|
||
Maturity tab →
|
||
</button>
|
||
} @else if (r.postable) {
|
||
<button
|
||
type="button"
|
||
class="pg-btn pg-btn--primary"
|
||
[disabled]="postingInterest"
|
||
(click)="postInterest(r)"
|
||
>
|
||
Generate Voucher
|
||
</button>
|
||
} @else if (isDueSoon(r.intDate)) {
|
||
🔔 Due {{ r.intDate }}
|
||
} @else {
|
||
Scheduled {{ r.intDate }}
|
||
}
|
||
</td>
|
||
</tr>
|
||
@if (r.postable && r.lineType === 'PAYOUT') {
|
||
<tr>
|
||
<td colspan="8">
|
||
<div class="inv-form-grid">
|
||
<label class="inv-form-field"
|
||
><span>Amount received from Bank (₹)</span
|
||
><input
|
||
type="number"
|
||
min="0"
|
||
[(ngModel)]="payoutReceived"
|
||
[placeholder]="r.grossInterest - (r.tds || 0)"
|
||
/></label>
|
||
@if (s.fd.tdsRate) {
|
||
<label class="inv-form-field"
|
||
><span>TDS deducted (₹) · auto at {{ s.fd.tdsRate }}%</span
|
||
><input type="number" min="0" [(ngModel)]="payoutTds" [placeholder]="r.tds || 0"
|
||
/></label>
|
||
}
|
||
<label class="inv-form-field">
|
||
<span>Received into</span>
|
||
<select [(ngModel)]="payoutBankGlAccountId">
|
||
@for (g of bankGlOptions; track g.id) {
|
||
<option [ngValue]="g.id">{{ g.glCode }} — {{ g.name }}</option>
|
||
}
|
||
</select>
|
||
</label>
|
||
</div>
|
||
<small
|
||
>Leave the amount blank to take the system's interest.
|
||
@if (s.fd.tdsRate) {
|
||
Leave TDS blank to work it out at {{ s.fd.tdsRate }}%; enter the bank's figure if it differs.
|
||
} @else {
|
||
{{ s.fd.partyName }} does not deduct TDS (Bank / Party Master).
|
||
}
|
||
Voucher: Dr bank + Dr 100602 TDS / Cr 100603 (provisioned) + Cr interest income (the rest).</small
|
||
>
|
||
</td>
|
||
</tr>
|
||
}
|
||
}
|
||
</tbody>
|
||
</table>
|
||
}
|
||
<div class="inv-form-actions">
|
||
<button type="button" class="pg-btn pg-btn--ghost" (click)="setTab('holdings')">Exit</button>
|
||
</div>
|
||
</div>
|
||
}
|
||
|
||
<!-- ===================== 02 MATURITY / PREMATURE / RENEWAL ===================== -->
|
||
@if (activeTab === 'closure') {
|
||
<div class="pg-card">
|
||
<div class="pos-section-label">Investment - FD Maturity / Premature / Renewal</div>
|
||
<div class="inv-form-grid">
|
||
<label class="inv-form-field">
|
||
<span>* FD (Deal No)</span>
|
||
<select [(ngModel)]="closure.fdId" (ngModelChange)="onClosureFdChange()">
|
||
<option [ngValue]="null">-- Select --</option>
|
||
@for (f of activeFds; track f.id) {
|
||
<option [ngValue]="f.id">
|
||
{{ f.dealNo }} — {{ f.partyName }} — ₹{{ f.principal | number: '1.0-0' }} — matures {{ f.maturityDate }}
|
||
</option>
|
||
}
|
||
</select>
|
||
</label>
|
||
@if (closureFd; as f) {
|
||
<label class="inv-form-field">
|
||
<span>* Action</span>
|
||
<select [(ngModel)]="closure.type" (ngModelChange)="refreshClosureQuote()">
|
||
<option value="MATURITY" [disabled]="!closureFdMatured">Maturity</option>
|
||
<option value="RENEWAL" [disabled]="!closureFdMatured">Maturity & Renewal</option>
|
||
<option value="PREMATURE" [disabled]="closureFdMatured">Premature Closure</option>
|
||
</select>
|
||
</label>
|
||
<label class="inv-form-field"
|
||
><span>Certificate / Rate</span><input type="text" [value]="f.certNo + ' @ ' + f.intRate + '%'" readonly
|
||
/></label>
|
||
<label class="inv-form-field"
|
||
><span>Principal</span><input type="text" [value]="'₹' + (f.principal | number: '1.2-2')" readonly
|
||
/></label>
|
||
<label class="inv-form-field"
|
||
><span>Deal → Maturity</span><input type="text" [value]="f.dealDate + ' → ' + f.maturityDate" readonly
|
||
/></label>
|
||
@if (closure.type === 'PREMATURE') {
|
||
<label class="inv-form-field"
|
||
><span>* Closure Date</span
|
||
><mifosx-date-ddmmyyyy
|
||
[(ngModel)]="closure.closeDate"
|
||
(ngModelChange)="refreshClosureQuote()"
|
||
></mifosx-date-ddmmyyyy
|
||
></label>
|
||
}
|
||
<label class="inv-form-field"
|
||
><span>{{
|
||
closure.type === 'PREMATURE'
|
||
? '* Amount Received from Bank (₹)'
|
||
: closure.type === 'RENEWAL'
|
||
? 'Maturity Amount as per Bank (₹)'
|
||
: 'Amount Received from Bank (₹)'
|
||
}}</span
|
||
><input
|
||
type="number"
|
||
min="0"
|
||
[(ngModel)]="closure.receivedAmount"
|
||
[placeholder]="closure.type === 'PREMATURE' ? '' : (closureQuote?.receivedAmount ?? '')"
|
||
(change)="refreshClosureQuote()"
|
||
/></label>
|
||
@if (closureFd?.tdsRate) {
|
||
<label class="inv-form-field"
|
||
><span>TDS deducted by Bank (₹) · auto at {{ closureFd?.tdsRate }}%</span
|
||
><input
|
||
type="number"
|
||
min="0"
|
||
[(ngModel)]="closure.tds"
|
||
[placeholder]="closureQuote?.tds ?? ''"
|
||
(change)="refreshClosureQuote()"
|
||
/></label>
|
||
}
|
||
@if (closure.type === 'PREMATURE') {
|
||
<label class="inv-form-field"
|
||
><span>Penal Interest (₹)</span
|
||
><input type="number" min="0" [(ngModel)]="closure.penalAmount" placeholder="0"
|
||
/></label>
|
||
}
|
||
@if (closure.type !== 'RENEWAL') {
|
||
<label class="inv-form-field">
|
||
<span>Principal received into</span>
|
||
<select [(ngModel)]="closure.principalBankGlAccountId" (ngModelChange)="refreshClosureQuote()">
|
||
@for (g of bankGlOptions; track g.id) {
|
||
<option [ngValue]="g.id">{{ g.glCode }} — {{ g.name }}</option>
|
||
}
|
||
</select>
|
||
</label>
|
||
<label class="inv-form-field">
|
||
<span>Interest received into</span>
|
||
<select [(ngModel)]="closure.interestBankGlAccountId" (ngModelChange)="refreshClosureQuote()">
|
||
@for (g of bankGlOptions; track g.id) {
|
||
<option [ngValue]="g.id">{{ g.glCode }} — {{ g.name }}</option>
|
||
}
|
||
</select>
|
||
</label>
|
||
}
|
||
}
|
||
</div>
|
||
|
||
@if (closureFd && closure.type === 'RENEWAL') {
|
||
<div class="pos-section-label">New Certificate</div>
|
||
<div class="inv-form-grid">
|
||
<label class="inv-form-field"
|
||
><span>* New Certificate No</span><input type="text" maxlength="50" [(ngModel)]="closure.newCertNo"
|
||
/></label>
|
||
<label class="inv-form-field"
|
||
><span>Certificate Date</span><mifosx-date-ddmmyyyy [(ngModel)]="closure.newCertDate"></mifosx-date-ddmmyyyy
|
||
></label>
|
||
<label class="inv-form-field"
|
||
><span>* New Interest Rate %</span
|
||
><input type="number" min="0" step="0.01" [(ngModel)]="closure.newIntRate"
|
||
/></label>
|
||
<label class="inv-form-field"
|
||
><span>Period – Years</span
|
||
><input type="number" min="0" [(ngModel)]="closure.newPeriodYears" (change)="onNewPeriodChange()"
|
||
/></label>
|
||
<label class="inv-form-field"
|
||
><span>Period – Months</span
|
||
><input type="number" min="0" [(ngModel)]="closure.newPeriodMonths" (change)="onNewPeriodChange()"
|
||
/></label>
|
||
<label class="inv-form-field"
|
||
><span>Period – Days</span
|
||
><input type="number" min="0" [(ngModel)]="closure.newPeriodDays" (change)="onNewPeriodChange()"
|
||
/></label>
|
||
<label class="inv-form-field"
|
||
><span>* New Maturity Date</span
|
||
><mifosx-date-ddmmyyyy [(ngModel)]="closure.newMaturityDate"></mifosx-date-ddmmyyyy
|
||
></label>
|
||
<label class="inv-form-field">
|
||
<span>Interest Paid</span>
|
||
<select [(ngModel)]="closure.newPayout">
|
||
@for (o of payoutOptions; track o.value) {
|
||
<option [ngValue]="o.value">{{ o.label }}</option>
|
||
}
|
||
</select>
|
||
</label>
|
||
@if (closure.newPayout === 'MATURITY') {
|
||
<label class="inv-form-field">
|
||
<span>Maturity Calculation</span>
|
||
<select [(ngModel)]="closure.newCalcType">
|
||
@for (o of calcTypeOptions; track o.value) {
|
||
<option [ngValue]="o.value">{{ o.label }}</option>
|
||
}
|
||
</select>
|
||
</label>
|
||
}
|
||
<label class="inv-form-field"
|
||
><span>Renewal Amount (₹) — blank = full maturity amount</span
|
||
><input
|
||
type="number"
|
||
min="0"
|
||
[(ngModel)]="closure.renewalAmount"
|
||
[placeholder]="closureQuote?.receivedAmount ?? ''"
|
||
(change)="refreshClosureQuote()"
|
||
/></label>
|
||
@if (closureTopUp !== 0) {
|
||
<label class="inv-form-field">
|
||
<span
|
||
>* {{ closureTopUp > 0 ? 'Extra' : 'Taken out' }} ₹{{
|
||
(closureTopUp > 0 ? closureTopUp : -closureTopUp) | number: '1.2-2'
|
||
}}
|
||
— {{ closureTopUp > 0 ? 'paid from' : 'credited to' }}</span
|
||
>
|
||
<select [(ngModel)]="closure.diffBankGlAccountId" (ngModelChange)="refreshClosureQuote()">
|
||
<option [ngValue]="null">-- Select --</option>
|
||
@for (g of bankGlOptions; track g.id) {
|
||
<option [ngValue]="g.id">{{ g.glCode }} — {{ g.name }}</option>
|
||
}
|
||
</select>
|
||
</label>
|
||
}
|
||
</div>
|
||
}
|
||
|
||
@if (closureQuote; as q) {
|
||
<div class="pos-section-label">Interest — system vs bank</div>
|
||
<div class="inv-form-grid">
|
||
<label class="inv-form-field"
|
||
><span>Interest as per System</span
|
||
><input type="text" [value]="'₹' + (q.expectedInterest | number: '1.2-2')" readonly
|
||
/></label>
|
||
<label class="inv-form-field"
|
||
><span>Interest as per Bank (received + TDS − principal)</span
|
||
><input type="text" [value]="'₹' + (q.interest | number: '1.2-2')" readonly
|
||
/></label>
|
||
<label class="inv-form-field"
|
||
><span>Difference</span><input type="text" [value]="'₹' + (q.difference | number: '1.2-2')" readonly
|
||
/></label>
|
||
<label class="inv-form-field"
|
||
><span>Already Provisioned</span
|
||
><input type="text" [value]="'₹' + (q.provisioned | number: '1.2-2')" readonly
|
||
/></label>
|
||
</div>
|
||
@if (q.difference !== 0 && closure.type !== 'PREMATURE') {
|
||
<p class="pg-sub" style="padding: 0 16px">
|
||
The bank and the system differ by ₹{{ q.difference | number: '1.2-2' }}: the bank may compound differently
|
||
(daily / monthly / quarterly). The bank's figure is what gets posted.
|
||
</p>
|
||
}
|
||
<table class="pg-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Dr / Cr</th>
|
||
<th>GL</th>
|
||
<th class="num">Amount</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
@for (l of q.lines; track $index) {
|
||
<tr>
|
||
<td>{{ l.side }}</td>
|
||
<td>{{ l.glCode }} {{ l.glName }}</td>
|
||
<td class="num">₹{{ l.amount | number: '1.2-2' }}</td>
|
||
</tr>
|
||
} @empty {
|
||
<tr>
|
||
<td colspan="3" class="pg-empty">No voucher needed.</td>
|
||
</tr>
|
||
}
|
||
</tbody>
|
||
</table>
|
||
@if (closure.type === 'RENEWAL' && closureTopUp !== 0 && !closure.diffBankGlAccountId) {
|
||
<p class="pg-sub" style="padding: 0 16px; color: #b42318">
|
||
Choose the bank for the {{ closureTopUp > 0 ? 'extra amount' : 'amount taken out' }} to complete the
|
||
voucher.
|
||
</p>
|
||
}
|
||
<p class="pg-sub" style="padding: 0 16px">
|
||
Voucher dated {{ q.closeDate }}. The lines follow the amounts entered above.
|
||
</p>
|
||
}
|
||
@if (closureError) {
|
||
<p class="pg-sub" style="padding: 0 16px; color: #b42318">{{ closureError }}</p>
|
||
}
|
||
@if (closureFd) {
|
||
<div class="inv-form-grid">
|
||
<label class="inv-form-field"
|
||
><span>Remarks</span><input type="text" maxlength="500" [(ngModel)]="closure.remarks"
|
||
/></label>
|
||
</div>
|
||
}
|
||
<div class="inv-form-actions">
|
||
<button type="button" class="pg-btn pg-btn--primary" [disabled]="!closureFd || closing" (click)="saveClosure()">
|
||
{{
|
||
closure.type === 'RENEWAL'
|
||
? 'Renew'
|
||
: closure.type === 'PREMATURE'
|
||
? 'Close Premature'
|
||
: 'Close at Maturity'
|
||
}}
|
||
</button>
|
||
<button type="button" class="pg-btn pg-btn--ghost" (click)="setTab('holdings')">Exit</button>
|
||
</div>
|
||
</div>
|
||
}
|
||
</div>
|
||
|
||
<div class="inv-toast" [class.show]="toastVisible">{{ toastMsg }}</div>
|