- Correct Investment portfolio allocation and Loan Origination product-mix targets against RBI's UCB SLR/Non-SLR framework and PSL circulars, with a Target Basis column distinguishing RBI-mandated vs board-policy rows (Excel export included). - Expand Investment holdings dataset with more near-term maturities so the Due-Date Diary reflects a realistic spread across FD/Govt Security/Non-SLR/Bond. - Add From/To period-based Interest Calculation & Post (with GL selection for both posting and receiving) across the Investment Interest module, FD Entry and Bond Entry screens; fix a bug where a posted period kept re-appearing as due since accrual wasn't tracked per-holding. - Add a reusable DD-MM-YYYY date-picker component and roll it out across all Investment date fields. - NPA Summary Report: drop SMA-0/1/2 from the stage-wise table (kept in Day-wise Overdue only). - NPA Recovery Report: add Account Type / NPA Category / Target-vs-Actual columns, a shared Account Type filter driving both the account picker and the register, and a searchable (fixed-position, not clipped by card overflow) account select for long lists. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
563 lines
18 KiB
HTML
563 lines
18 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 · MASTERS</div>
|
|
<h1 class="pg-title">Investment Masters</h1>
|
|
<p class="pg-sub">
|
|
Bank/Party, Script, SubType, Broker, Control Parameter, LIEN Reason, Mutual Fund Product, SGL Bank and Script
|
|
Market Detail masters.
|
|
</p>
|
|
</div>
|
|
<div class="pg-toolbar">
|
|
<button type="button" class="pg-btn pg-btn--ghost" [disabled]="generating" (click)="exportExcel()">
|
|
{{ generating ? 'Exporting…' : 'Export to Excel' }}
|
|
</button>
|
|
</div>
|
|
</header>
|
|
|
|
<div class="cctr-tabs">
|
|
<button
|
|
type="button"
|
|
class="pg-btn pg-btn--ghost"
|
|
[class.pg-btn--active]="activeTab === 'party'"
|
|
(click)="setTab('party')"
|
|
>
|
|
04 Bank / Party Master
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="pg-btn pg-btn--ghost"
|
|
[class.pg-btn--active]="activeTab === 'script'"
|
|
(click)="setTab('script')"
|
|
>
|
|
05 Script Master
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="pg-btn pg-btn--ghost"
|
|
[class.pg-btn--active]="activeTab === 'subtype'"
|
|
(click)="setTab('subtype')"
|
|
>
|
|
06 SubType Master
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="pg-btn pg-btn--ghost"
|
|
[class.pg-btn--active]="activeTab === 'broker'"
|
|
(click)="setTab('broker')"
|
|
>
|
|
07 Broker Master
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="pg-btn pg-btn--ghost"
|
|
[class.pg-btn--active]="activeTab === 'control'"
|
|
(click)="setTab('control')"
|
|
>
|
|
08 Control Parameter
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="pg-btn pg-btn--ghost"
|
|
[class.pg-btn--active]="activeTab === 'dailyscript'"
|
|
(click)="setTab('dailyscript')"
|
|
>
|
|
09 Daily Script Master
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="pg-btn pg-btn--ghost"
|
|
[class.pg-btn--active]="activeTab === 'lien'"
|
|
(click)="setTab('lien')"
|
|
>
|
|
10 LIEN Reason Master
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="pg-btn pg-btn--ghost"
|
|
[class.pg-btn--active]="activeTab === 'mfproduct'"
|
|
(click)="setTab('mfproduct')"
|
|
>
|
|
11 Mutual Fund Product Master
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="pg-btn pg-btn--ghost"
|
|
[class.pg-btn--active]="activeTab === 'sglbank'"
|
|
(click)="setTab('sglbank')"
|
|
>
|
|
12 SGL Bank Master
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="pg-btn pg-btn--ghost"
|
|
[class.pg-btn--active]="activeTab === 'marketdetail'"
|
|
(click)="setTab('marketdetail')"
|
|
>
|
|
13 Script Market Detail
|
|
</button>
|
|
</div>
|
|
|
|
<!-- PARTY MASTER -->
|
|
@if (activeTab === 'party') {
|
|
<div class="pg-card">
|
|
<div class="pos-section-label">Add Bank / Party</div>
|
|
<div class="inv-form-grid">
|
|
<label class="inv-form-field"
|
|
><span>Party Name *</span><input type="text" [(ngModel)]="newParty.partyName"
|
|
/></label>
|
|
<label class="inv-form-field">
|
|
<span>Party Type *</span>
|
|
<select [(ngModel)]="newParty.partyType">
|
|
<option [ngValue]="undefined">-- Select --</option>
|
|
<option value="BANK">BANK</option>
|
|
<option value="CORPORATE">CORPORATE</option>
|
|
<option value="GOVT">GOVT</option>
|
|
<option value="AMC">AMC</option>
|
|
<option value="EXCHANGE">EXCHANGE</option>
|
|
<option value="COOP_SOCIETY">COOP SOCIETY</option>
|
|
</select>
|
|
</label>
|
|
<label class="inv-form-field"><span>PAN No</span><input type="text" [(ngModel)]="newParty.panNo" /></label>
|
|
</div>
|
|
<div class="inv-form-actions">
|
|
<button type="button" class="pg-btn pg-btn--primary" (click)="addParty()">Save</button>
|
|
</div>
|
|
<table class="pg-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Party Code</th>
|
|
<th>Party Name</th>
|
|
<th>Type</th>
|
|
<th>PAN No</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (p of parties; track p.partyCode) {
|
|
<tr>
|
|
<td>
|
|
<span class="pg-chip">{{ p.partyCode }}</span>
|
|
</td>
|
|
<td>{{ p.partyName }}</td>
|
|
<td>{{ p.partyType }}</td>
|
|
<td>{{ p.panNo }}</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
}
|
|
|
|
<!-- SCRIPT MASTER -->
|
|
@if (activeTab === 'script') {
|
|
<div class="pg-card">
|
|
<div class="pos-section-label">Add Script</div>
|
|
<div class="inv-form-grid">
|
|
<label class="inv-form-field"
|
|
><span>Script Code</span><input type="text" [(ngModel)]="newScript.scriptCode"
|
|
/></label>
|
|
<label class="inv-form-field"
|
|
><span>Script Name *</span><input type="text" [(ngModel)]="newScript.scriptName"
|
|
/></label>
|
|
<label class="inv-form-field">
|
|
<span>Instrument Type *</span>
|
|
<select [(ngModel)]="newScript.instrumentType">
|
|
<option [ngValue]="undefined">-- Select --</option>
|
|
@for (t of instrumentTypes; track t) {
|
|
<option [value]="t">{{ t }}</option>
|
|
}
|
|
</select>
|
|
</label>
|
|
<label class="inv-form-field"><span>ISIN</span><input type="text" [(ngModel)]="newScript.isin" /></label>
|
|
<label class="inv-form-field"
|
|
><span>Face Value / Unit</span><input type="number" [(ngModel)]="newScript.faceValuePerUnit"
|
|
/></label>
|
|
</div>
|
|
<div class="inv-form-actions">
|
|
<button type="button" class="pg-btn pg-btn--primary" (click)="addScript()">Save</button>
|
|
</div>
|
|
<table class="pg-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Script Code</th>
|
|
<th>Script Name</th>
|
|
<th>Instrument</th>
|
|
<th>ISIN</th>
|
|
<th class="num">Face Value/Unit</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (s of scripts; track s.scriptCode) {
|
|
<tr>
|
|
<td>
|
|
<span class="pg-chip">{{ s.scriptCode }}</span>
|
|
</td>
|
|
<td>{{ s.scriptName }}</td>
|
|
<td>{{ s.instrumentType }}</td>
|
|
<td>{{ s.isin || '—' }}</td>
|
|
<td class="num">{{ s.faceValuePerUnit }}</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
}
|
|
|
|
<!-- SUBTYPE MASTER -->
|
|
@if (activeTab === 'subtype') {
|
|
<div class="pg-card">
|
|
<div class="pos-section-label">Add Sub Type</div>
|
|
<div class="inv-form-grid">
|
|
<label class="inv-form-field"
|
|
><span>Sub Type Name *</span><input type="text" [(ngModel)]="newSubType.subTypeName"
|
|
/></label>
|
|
<label class="inv-form-field">
|
|
<span>Instrument Type *</span>
|
|
<select [(ngModel)]="newSubType.instrumentType">
|
|
<option [ngValue]="undefined">-- Select --</option>
|
|
@for (t of instrumentTypes; track t) {
|
|
<option [value]="t">{{ t }}</option>
|
|
}
|
|
</select>
|
|
</label>
|
|
</div>
|
|
<div class="inv-form-actions">
|
|
<button type="button" class="pg-btn pg-btn--primary" (click)="addSubType()">Save</button>
|
|
</div>
|
|
<table class="pg-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Code</th>
|
|
<th>Sub Type</th>
|
|
<th>Instrument</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (s of subTypes; track s.subTypeCode + s.subTypeName) {
|
|
<tr>
|
|
<td>
|
|
<span class="pg-chip">{{ s.subTypeCode }}</span>
|
|
</td>
|
|
<td>{{ s.subTypeName }}</td>
|
|
<td>{{ s.instrumentType }}</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
}
|
|
|
|
<!-- BROKER MASTER -->
|
|
@if (activeTab === 'broker') {
|
|
<div class="pg-card">
|
|
<div class="pos-section-label">Add Broker</div>
|
|
<div class="inv-form-grid">
|
|
<label class="inv-form-field"
|
|
><span>Broker Name *</span><input type="text" [(ngModel)]="newBroker.brokerName"
|
|
/></label>
|
|
<label class="inv-form-field"
|
|
><span>Contact No</span><input type="text" [(ngModel)]="newBroker.contactNo"
|
|
/></label>
|
|
<label class="inv-form-field"
|
|
><span>Empanelled On</span><mifosx-date-ddmmyyyy [(ngModel)]="newBroker.empanelledOn"></mifosx-date-ddmmyyyy
|
|
></label>
|
|
</div>
|
|
<div class="inv-form-actions">
|
|
<button type="button" class="pg-btn pg-btn--primary" (click)="addBroker()">Save</button>
|
|
</div>
|
|
<table class="pg-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Broker Code</th>
|
|
<th>Broker Name</th>
|
|
<th>Contact</th>
|
|
<th>Empanelled On</th>
|
|
<th>Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (b of brokers; track b.brokerCode) {
|
|
<tr>
|
|
<td>
|
|
<span class="pg-chip">{{ b.brokerCode }}</span>
|
|
</td>
|
|
<td>{{ b.brokerName }}</td>
|
|
<td>{{ b.contactNo }}</td>
|
|
<td>{{ b.empanelledOn }}</td>
|
|
<td>
|
|
<span class="inv-badge inv-badge--active">{{ b.status }}</span>
|
|
</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
}
|
|
|
|
<!-- CONTROL PARAMETER -->
|
|
@if (activeTab === 'control') {
|
|
<div class="pg-card">
|
|
<div class="pos-section-label">Add Control Parameter</div>
|
|
<div class="inv-form-grid">
|
|
<label class="inv-form-field"
|
|
><span>Parameter Name *</span><input type="text" [(ngModel)]="newControlParam.paramName"
|
|
/></label>
|
|
<label class="inv-form-field"
|
|
><span>Value *</span><input type="text" [(ngModel)]="newControlParam.paramValue"
|
|
/></label>
|
|
<label class="inv-form-field"
|
|
><span>Description</span><input type="text" [(ngModel)]="newControlParam.description"
|
|
/></label>
|
|
</div>
|
|
<div class="inv-form-actions">
|
|
<button type="button" class="pg-btn pg-btn--primary" (click)="addControlParam()">Save</button>
|
|
</div>
|
|
<table class="pg-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Parameter</th>
|
|
<th>Value</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (c of controlParams; track c.paramName) {
|
|
<tr>
|
|
<td>
|
|
<span class="pg-chip">{{ c.paramName }}</span>
|
|
</td>
|
|
<td class="num">{{ c.paramValue }}</td>
|
|
<td>{{ c.description }}</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
}
|
|
|
|
<!-- DAILY SCRIPT MASTER -->
|
|
@if (activeTab === 'dailyscript') {
|
|
<div class="pg-card">
|
|
<div class="pos-section-label">Add Daily Script Rate</div>
|
|
<div class="inv-form-grid">
|
|
<label class="inv-form-field"
|
|
><span>Rate Date *</span><mifosx-date-ddmmyyyy [(ngModel)]="newDailyRate.rateDate"></mifosx-date-ddmmyyyy
|
|
></label>
|
|
<label class="inv-form-field">
|
|
<span>Script Code *</span>
|
|
<select [(ngModel)]="newDailyRate.scriptCode">
|
|
<option [ngValue]="undefined">-- Select --</option>
|
|
@for (s of scripts; track s.scriptCode) {
|
|
<option [value]="s.scriptCode">{{ s.scriptCode }} — {{ s.scriptName }}</option>
|
|
}
|
|
</select>
|
|
</label>
|
|
<label class="inv-form-field"
|
|
><span>Open Rate</span><input type="number" [(ngModel)]="newDailyRate.openRate" step="0.01"
|
|
/></label>
|
|
<label class="inv-form-field"
|
|
><span>Close Rate *</span><input type="number" [(ngModel)]="newDailyRate.closeRate" step="0.01"
|
|
/></label>
|
|
<label class="inv-form-field"
|
|
><span>High Rate</span><input type="number" [(ngModel)]="newDailyRate.highRate" step="0.01"
|
|
/></label>
|
|
<label class="inv-form-field"
|
|
><span>Low Rate</span><input type="number" [(ngModel)]="newDailyRate.lowRate" step="0.01"
|
|
/></label>
|
|
</div>
|
|
<div class="inv-form-actions">
|
|
<button type="button" class="pg-btn pg-btn--primary" (click)="addDailyRate()">Save</button>
|
|
</div>
|
|
<table class="pg-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Rate Date</th>
|
|
<th>Script Code</th>
|
|
<th>Script Name</th>
|
|
<th class="num">Open</th>
|
|
<th class="num">High</th>
|
|
<th class="num">Low</th>
|
|
<th class="num">Close</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (r of dailyScriptRates; track r.rateDate + r.scriptCode) {
|
|
<tr>
|
|
<td>{{ r.rateDate }}</td>
|
|
<td>
|
|
<span class="pg-chip">{{ r.scriptCode }}</span>
|
|
</td>
|
|
<td>{{ r.scriptName }}</td>
|
|
<td class="num">{{ r.openRate | number: '1.2-2' }}</td>
|
|
<td class="num">{{ r.highRate | number: '1.2-2' }}</td>
|
|
<td class="num">{{ r.lowRate | number: '1.2-2' }}</td>
|
|
<td class="num">{{ r.closeRate | number: '1.2-2' }}</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
}
|
|
|
|
<!-- LIEN REASON MASTER -->
|
|
@if (activeTab === 'lien') {
|
|
<div class="pg-card">
|
|
<div class="pos-section-label">Add LIEN Reason</div>
|
|
<div class="inv-form-grid">
|
|
<label class="inv-form-field"
|
|
><span>Reason Description *</span><input type="text" [(ngModel)]="newLienReason.reasonDescription"
|
|
/></label>
|
|
</div>
|
|
<div class="inv-form-actions">
|
|
<button type="button" class="pg-btn pg-btn--primary" (click)="addLienReason()">Save</button>
|
|
</div>
|
|
<table class="pg-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Reason Code</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (l of lienReasons; track l.reasonCode) {
|
|
<tr>
|
|
<td>
|
|
<span class="pg-chip">{{ l.reasonCode }}</span>
|
|
</td>
|
|
<td>{{ l.reasonDescription }}</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
}
|
|
|
|
<!-- MUTUAL FUND PRODUCT MASTER -->
|
|
@if (activeTab === 'mfproduct') {
|
|
<div class="pg-card">
|
|
<div class="pos-section-label">Add Mutual Fund Product</div>
|
|
<div class="inv-form-grid">
|
|
<label class="inv-form-field"
|
|
><span>Product Name *</span><input type="text" [(ngModel)]="newMfProduct.productName"
|
|
/></label>
|
|
<label class="inv-form-field"
|
|
><span>AMC Name *</span><input type="text" [(ngModel)]="newMfProduct.amcName"
|
|
/></label>
|
|
<label class="inv-form-field"
|
|
><span>Category</span><input type="text" [(ngModel)]="newMfProduct.category"
|
|
/></label>
|
|
<label class="inv-form-field">
|
|
<span>Risk Level</span>
|
|
<select [(ngModel)]="newMfProduct.riskLevel">
|
|
<option value="LOW">LOW</option>
|
|
<option value="MODERATE">MODERATE</option>
|
|
<option value="HIGH">HIGH</option>
|
|
</select>
|
|
</label>
|
|
</div>
|
|
<div class="inv-form-actions">
|
|
<button type="button" class="pg-btn pg-btn--primary" (click)="addMfProduct()">Save</button>
|
|
</div>
|
|
<table class="pg-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Product Code</th>
|
|
<th>Product Name</th>
|
|
<th>AMC</th>
|
|
<th>Category</th>
|
|
<th>Risk</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (m of mfProducts; track m.productCode) {
|
|
<tr>
|
|
<td>
|
|
<span class="pg-chip">{{ m.productCode }}</span>
|
|
</td>
|
|
<td>{{ m.productName }}</td>
|
|
<td>{{ m.amcName }}</td>
|
|
<td>{{ m.category }}</td>
|
|
<td>{{ m.riskLevel }}</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
}
|
|
|
|
<!-- SGL BANK MASTER -->
|
|
@if (activeTab === 'sglbank') {
|
|
<div class="pg-card">
|
|
<div class="pos-section-label">Add SGL Bank</div>
|
|
<div class="inv-form-grid">
|
|
<label class="inv-form-field"
|
|
><span>Bank Name *</span><input type="text" [(ngModel)]="newSglBank.bankName"
|
|
/></label>
|
|
<label class="inv-form-field"><span>Branch</span><input type="text" [(ngModel)]="newSglBank.branch" /></label>
|
|
</div>
|
|
<div class="inv-form-actions">
|
|
<button type="button" class="pg-btn pg-btn--primary" (click)="addSglBank()">Save</button>
|
|
</div>
|
|
<table class="pg-table">
|
|
<thead>
|
|
<tr>
|
|
<th>SGL Code</th>
|
|
<th>Bank Name</th>
|
|
<th>Branch</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (s of sglBanks; track s.sglCode) {
|
|
<tr>
|
|
<td>
|
|
<span class="pg-chip">{{ s.sglCode }}</span>
|
|
</td>
|
|
<td>{{ s.bankName }}</td>
|
|
<td>{{ s.branch }}</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
}
|
|
|
|
<!-- SCRIPT MARKET DETAIL (also covers "09 Daily Script Master") -->
|
|
@if (activeTab === 'marketdetail') {
|
|
<div class="pg-card">
|
|
<div class="pos-section-label">Script Market Detail (Daily Script Rates)</div>
|
|
<table class="pg-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Script Code</th>
|
|
<th class="num">Market Price</th>
|
|
<th>As On</th>
|
|
<th class="num">YTM (%)</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (m of marketDetails; track m.scriptCode) {
|
|
<tr>
|
|
<td>
|
|
<span class="pg-chip">{{ m.scriptCode }}</span>
|
|
</td>
|
|
<td class="num">₹{{ m.marketPrice | number: '1.2-2' }}</td>
|
|
<td>{{ m.asOnDate }}</td>
|
|
<td class="num">{{ m.ytm }}%</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
}
|
|
</div>
|
|
|
|
<div class="inv-toast" [class.show]="toastVisible">{{ toastMsg }}</div>
|