feat(investment): FD TDS fields, GOI interest to the paisa, compact home reminders, deal no in holdings and settle guard
This commit is contained in:
@@ -131,7 +131,7 @@
|
||||
<table class="pg-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Cert No</th>
|
||||
<th>Deal No / Cert No</th>
|
||||
<th>Script</th>
|
||||
<th>Party</th>
|
||||
<th class="num">Units</th>
|
||||
@@ -150,7 +150,8 @@
|
||||
@for (h of holdingsForType; track h.certNo) {
|
||||
<tr>
|
||||
<td>
|
||||
<span class="pg-chip">{{ h.certNo }}</span>
|
||||
<span class="pg-chip">{{ h.dealNo }}</span>
|
||||
<br /><small>Cert {{ h.certNo }}</small>
|
||||
</td>
|
||||
<td>{{ h.scriptName }}</td>
|
||||
<td>{{ h.party }}</td>
|
||||
@@ -169,8 +170,13 @@
|
||||
</td>
|
||||
<td>
|
||||
@if (h.status === 'PENDING_SETTLEMENT') {
|
||||
<button type="button" class="pg-btn pg-btn--primary" (click)="settleDeal(h)">
|
||||
Settle ({{ h.settlementDate }})
|
||||
<button
|
||||
type="button"
|
||||
class="pg-btn pg-btn--primary"
|
||||
[disabled]="settlingDealId !== null"
|
||||
(click)="settleDeal(h)"
|
||||
>
|
||||
{{ settlingDealId === h.id ? 'Settling…' : 'Settle (' + h.settlementDate + ')' }}
|
||||
</button>
|
||||
} @else if (h.glTransactionId) {
|
||||
<span class="pg-chip" title="Journal entry transaction">GL {{ h.glTransactionId }}</span>
|
||||
@@ -357,7 +363,7 @@
|
||||
@if (!isMutualFund) {
|
||||
<label class="inv-form-field"
|
||||
><span>Premium (+) / Discount (−)</span
|
||||
><input type="text" [value]="'₹' + (purchasePremiumDiscount | number: '1.0-0')" readonly
|
||||
><input type="text" [value]="'₹' + (purchasePremiumDiscount | number: '1.2-2')" readonly
|
||||
/></label>
|
||||
<label class="inv-form-field"
|
||||
><span>Accrued Interest ({{ purchaseAccruedDays }} days)</span
|
||||
@@ -908,16 +914,16 @@
|
||||
<td class="num col-in">₹{{ r.amount | number: '1.2-2' }}</td>
|
||||
<td style="white-space: nowrap; font-size: 12px">
|
||||
@if (r.type === 'COUPON') {
|
||||
<div>Dr Bank ₹{{ r.grossInterest | number: '1.0-0' }}</div>
|
||||
<div>Dr Bank ₹{{ r.grossInterest | number: '1.2-2' }}</div>
|
||||
@if (r.alreadyBooked > 0) {
|
||||
<div>
|
||||
Cr {{ interestReceivableGl.glCode }} Int. Receivable ₹{{ r.alreadyBooked | number: '1.0-0' }}
|
||||
Cr {{ interestReceivableGl.glCode }} Int. Receivable ₹{{ r.alreadyBooked | number: '1.2-2' }}
|
||||
</div>
|
||||
}
|
||||
<div>Cr {{ sc.interestGlCode }} Int. Income ₹{{ r.amount | number: '1.0-0' }}</div>
|
||||
<div>Cr {{ sc.interestGlCode }} Int. Income ₹{{ r.amount | number: '1.2-2' }}</div>
|
||||
} @else {
|
||||
<div>Dr {{ interestReceivableGl.glCode }} Int. Receivable ₹{{ r.amount | number: '1.0-0' }}</div>
|
||||
<div>Cr {{ sc.interestGlCode }} Int. Income ₹{{ r.amount | number: '1.0-0' }}</div>
|
||||
<div>Dr {{ interestReceivableGl.glCode }} Int. Receivable ₹{{ r.amount | number: '1.2-2' }}</div>
|
||||
<div>Cr {{ sc.interestGlCode }} Int. Income ₹{{ r.amount | number: '1.2-2' }}</div>
|
||||
}
|
||||
</td>
|
||||
<td style="white-space: nowrap">
|
||||
@@ -1129,8 +1135,22 @@
|
||||
<td class="num">₹{{ s.netAmount | number: '1.2-2' }}</td>
|
||||
<td class="num">₹{{ s.profitLoss | number: '1.2-2' }}</td>
|
||||
<td style="white-space: nowrap">
|
||||
<button type="button" class="pg-btn pg-btn--primary" (click)="settleSale(s)">Settle</button>
|
||||
<button type="button" class="pg-btn pg-btn--ghost" (click)="dropSale(s)">Drop</button>
|
||||
<button
|
||||
type="button"
|
||||
class="pg-btn pg-btn--primary"
|
||||
[disabled]="busySaleId !== null"
|
||||
(click)="settleSale(s)"
|
||||
>
|
||||
{{ busySaleId === s.id ? 'Settling…' : 'Settle' }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="pg-btn pg-btn--ghost"
|
||||
[disabled]="busySaleId !== null"
|
||||
(click)="dropSale(s)"
|
||||
>
|
||||
Drop
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
} @empty {
|
||||
|
||||
@@ -604,7 +604,7 @@ export class BondInvestmentComponent implements OnInit {
|
||||
return this.purchaseBaseAmount;
|
||||
}
|
||||
const rate = f.purchaseRate || 100;
|
||||
return Math.round((this.purchaseBaseAmount * rate) / 100);
|
||||
return Math.round(this.purchaseBaseAmount * rate) / 100;
|
||||
}
|
||||
|
||||
/** Stamp duty + brokerage + other charges — paid with the settlement, booked to expense GLs. */
|
||||
@@ -627,7 +627,7 @@ export class BondInvestmentComponent implements OnInit {
|
||||
|
||||
get purchaseNextCouponAmount(): number {
|
||||
const f = this.purchaseForm;
|
||||
return f.intRate ? Math.round((this.purchaseBaseAmount * f.intRate) / 200) : 0;
|
||||
return f.intRate ? Math.round((this.purchaseBaseAmount * f.intRate) / 2) / 100 : 0;
|
||||
}
|
||||
|
||||
get purchaseDaysToNextCoupon(): number {
|
||||
@@ -648,7 +648,7 @@ export class BondInvestmentComponent implements OnInit {
|
||||
if (!f.intRate || !f.lastIntDt || !f.dealDate) {
|
||||
return 0;
|
||||
}
|
||||
return Math.round((this.purchaseBaseAmount * (f.intRate / 100) * this.purchaseAccruedDays) / 360);
|
||||
return Math.round((this.purchaseBaseAmount * f.intRate * this.purchaseAccruedDays) / 360) / 100;
|
||||
}
|
||||
|
||||
get purchaseAccruedDays(): number {
|
||||
@@ -663,7 +663,7 @@ export class BondInvestmentComponent implements OnInit {
|
||||
if (this.isMutualFund || !f.faceValue || !f.purchaseRate) {
|
||||
return 0;
|
||||
}
|
||||
return Math.round((f.faceValue * (f.purchaseRate - 100)) / 100);
|
||||
return Math.round(f.faceValue * (f.purchaseRate - 100)) / 100;
|
||||
}
|
||||
|
||||
/** Re-suggests the last coupon date when the deal date changes. */
|
||||
@@ -1022,12 +1022,17 @@ export class BondInvestmentComponent implements OnInit {
|
||||
}
|
||||
|
||||
/** Posts a pending deal to GL dated its settlement date; under maker-checker it waits in the Checker Inbox. */
|
||||
/** The purchase being settled; its button stays disabled so it cannot be sent twice. */
|
||||
settlingDealId: number | null = null;
|
||||
|
||||
settleDeal(h: InvestmentHolding): void {
|
||||
if (!h.id) {
|
||||
if (!h.id || this.settlingDealId !== null) {
|
||||
return;
|
||||
}
|
||||
this.settlingDealId = h.id;
|
||||
this.investmentService.settlePurchase(h.id).subscribe({
|
||||
next: (res) => {
|
||||
this.settlingDealId = null;
|
||||
this.toast(
|
||||
res.rollbackTransaction
|
||||
? `Settlement of deal ${h.dealNo} sent for approval (Checker Inbox).`
|
||||
@@ -1035,7 +1040,10 @@ export class BondInvestmentComponent implements OnInit {
|
||||
);
|
||||
this.loadPurchases();
|
||||
},
|
||||
error: (err) => this.toast(apiErrorMessage(err))
|
||||
error: (err) => {
|
||||
this.settlingDealId = null;
|
||||
this.toast(apiErrorMessage(err));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1345,29 +1353,44 @@ export class BondInvestmentComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
/** The pending sale being settled or dropped; its buttons stay disabled so it cannot be sent twice. */
|
||||
busySaleId: number | null = null;
|
||||
|
||||
settleSale(s: InvestmentSaleDto): void {
|
||||
if (!s.id) {
|
||||
if (!s.id || this.busySaleId !== null) {
|
||||
return;
|
||||
}
|
||||
this.busySaleId = s.id;
|
||||
this.investmentService.settleSale(s.id).subscribe({
|
||||
next: (res) => {
|
||||
this.busySaleId = null;
|
||||
this.sales = this.sales.filter((x) => x.id !== s.id);
|
||||
this.toast(`Sale of deal ${s.dealNo} settled — voucher ${res.resourceIdentifier ?? ''}.`);
|
||||
this.loadPurchases();
|
||||
},
|
||||
error: (err) => this.toast(apiErrorMessage(err))
|
||||
error: (err) => {
|
||||
this.busySaleId = null;
|
||||
this.toast(apiErrorMessage(err));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
dropSale(s: InvestmentSaleDto): void {
|
||||
if (!s.id) {
|
||||
if (!s.id || this.busySaleId !== null) {
|
||||
return;
|
||||
}
|
||||
this.busySaleId = s.id;
|
||||
this.investmentService.deleteSale(s.id).subscribe({
|
||||
next: () => {
|
||||
this.busySaleId = null;
|
||||
this.sales = this.sales.filter((x) => x.id !== s.id);
|
||||
this.toast(`Pending sale of deal ${s.dealNo} dropped.`);
|
||||
this.loadInterestLog();
|
||||
},
|
||||
error: (err) => this.toast(apiErrorMessage(err))
|
||||
error: (err) => {
|
||||
this.busySaleId = null;
|
||||
this.toast(apiErrorMessage(err));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1723,7 +1746,7 @@ export class BondInvestmentComponent implements OnInit {
|
||||
for (let k = 1; parseDDMMYYYY(addPeriod(h.lastIntDate, 0, 6 * k)) <= parseDDMMYYYY(asOn); k++) {
|
||||
lastCoupon = addPeriod(h.lastIntDate, 0, 6 * k);
|
||||
}
|
||||
return Math.round((h.faceValue * (h.interestRate / 100) * days360(lastCoupon, asOn)) / 360);
|
||||
return Math.round((h.faceValue * h.interestRate * days360(lastCoupon, asOn)) / 360) / 100;
|
||||
}
|
||||
|
||||
maturity(h: InvestmentHolding): number {
|
||||
@@ -1749,6 +1772,7 @@ export class BondInvestmentComponent implements OnInit {
|
||||
title: `${this.instrumentLabel(this.bondType)} Holdings Register`,
|
||||
subtitle: `As on ${this.asOnDate}`,
|
||||
headers: [
|
||||
'Deal No',
|
||||
'Cert No',
|
||||
'Script',
|
||||
'Party',
|
||||
@@ -1762,7 +1786,8 @@ export class BondInvestmentComponent implements OnInit {
|
||||
'Status'
|
||||
],
|
||||
widths: [
|
||||
14,
|
||||
16,
|
||||
10,
|
||||
26,
|
||||
22,
|
||||
12,
|
||||
@@ -1775,6 +1800,7 @@ export class BondInvestmentComponent implements OnInit {
|
||||
12
|
||||
],
|
||||
rows: this.holdingsForType.map((h) => [
|
||||
h.dealNo ?? '',
|
||||
h.certNo,
|
||||
h.scriptName,
|
||||
h.party,
|
||||
|
||||
Reference in New Issue
Block a user