feat(investment): deal time, interest cycle and charges on Purchase Entry
As per Jitendra Sir's review: - Deal Time is now a mandatory field next to Deal Date. - New Interest Cycle section: the two coupon days, last and next coupon, next coupon amount and days to it. - Stamp duty, brokerage and other charges sit on the main form. They are expenses on their own GLs (500601/500602/500603), so they are added to the settlement amount but no longer to the book value, and each shows as its own debit line in the accounting preview. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -29,11 +29,16 @@ import {
|
||||
INVESTMENT_GL_BY_TYPE,
|
||||
INVESTMENT_GL_LOOKUP,
|
||||
INTEREST_RECEIVABLE_GL,
|
||||
STAMP_DUTY_GL,
|
||||
BROKERAGE_GL,
|
||||
OTHER_CHARGES_GL,
|
||||
SETTLEMENT_BANK_GL_OPTIONS,
|
||||
periodBetween,
|
||||
parseDDMMYYYY,
|
||||
days360,
|
||||
lastHalfYearlyCouponDate,
|
||||
nextHalfYearlyCouponDate,
|
||||
couponDatesLabel,
|
||||
InvestmentHolding,
|
||||
InvestmentTxn,
|
||||
InstrumentType,
|
||||
@@ -135,6 +140,7 @@ interface BondPurchaseForm {
|
||||
holdingDays: number | null;
|
||||
stampDuty: number | null;
|
||||
stampDutyAc: string;
|
||||
otherCharges: number | null;
|
||||
}
|
||||
|
||||
interface AccountingPreviewLine {
|
||||
@@ -448,7 +454,8 @@ export class BondInvestmentComponent implements OnInit {
|
||||
nav: null,
|
||||
holdingDays: null,
|
||||
stampDuty: null,
|
||||
stampDutyAc: ''
|
||||
stampDutyAc: '',
|
||||
otherCharges: null
|
||||
};
|
||||
}
|
||||
|
||||
@@ -518,14 +525,41 @@ export class BondInvestmentComponent implements OnInit {
|
||||
return this.isMutualFund ? this.purchaseForm.nav || 0 : 100;
|
||||
}
|
||||
|
||||
/** Book Value — what the investment is carried at, i.e. amount actually paid. */
|
||||
/** Book Value — the price paid for the security. Charges are expenses and stay out of it (Jitendra Sir). */
|
||||
get purchaseBookValue(): number {
|
||||
const f = this.purchaseForm;
|
||||
if (this.isMutualFund) {
|
||||
return this.purchaseBaseAmount + (f.stampDuty || 0) + (f.brokerage || 0);
|
||||
return this.purchaseBaseAmount;
|
||||
}
|
||||
const rate = f.purchaseRate || 100;
|
||||
return Math.round((this.purchaseBaseAmount * rate) / 100) + (f.brokerage || 0);
|
||||
return Math.round((this.purchaseBaseAmount * rate) / 100);
|
||||
}
|
||||
|
||||
/** Stamp duty + brokerage + other charges — paid with the settlement, booked to expense GLs. */
|
||||
get purchaseTotalCharges(): number {
|
||||
const f = this.purchaseForm;
|
||||
return (f.stampDuty || 0) + (f.brokerage || 0) + (f.otherCharges || 0);
|
||||
}
|
||||
|
||||
// Interest cycle of the security being bought: its two coupon days and the next coupon after the deal.
|
||||
get purchaseCouponDates(): string {
|
||||
return this.purchaseMaturityDate ? couponDatesLabel(this.purchaseMaturityDate) : '';
|
||||
}
|
||||
|
||||
get purchaseNextCouponDate(): string {
|
||||
const f = this.purchaseForm;
|
||||
return this.purchaseMaturityDate && f.dealDate
|
||||
? nextHalfYearlyCouponDate(this.purchaseMaturityDate, f.dealDate)
|
||||
: '';
|
||||
}
|
||||
|
||||
get purchaseNextCouponAmount(): number {
|
||||
const f = this.purchaseForm;
|
||||
return f.intRate ? Math.round((this.purchaseBaseAmount * f.intRate) / 200) : 0;
|
||||
}
|
||||
|
||||
get purchaseDaysToNextCoupon(): number {
|
||||
return this.purchaseNextCouponDate ? days360(this.purchaseForm.dealDate, this.purchaseNextCouponDate) : 0;
|
||||
}
|
||||
|
||||
get purchaseYtm(): number {
|
||||
@@ -574,9 +608,9 @@ export class BondInvestmentComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
/** Settlement Amt of Purchase — book value plus accrued interest payable to the seller. */
|
||||
/** Settlement Amt of Purchase — book value, accrued interest payable to the seller and the charges. */
|
||||
get purchaseSettlementAmount(): number {
|
||||
return this.purchaseBookValue + this.purchaseAccruedInterest;
|
||||
return this.purchaseBookValue + this.purchaseAccruedInterest + this.purchaseTotalCharges;
|
||||
}
|
||||
|
||||
get purchaseMaturityAmount(): number {
|
||||
@@ -683,6 +717,28 @@ export class BondInvestmentComponent implements OnInit {
|
||||
amount: accrued
|
||||
});
|
||||
}
|
||||
const f = this.purchaseForm;
|
||||
for (const [
|
||||
gl,
|
||||
amount
|
||||
] of [
|
||||
[
|
||||
STAMP_DUTY_GL,
|
||||
f.stampDuty
|
||||
],
|
||||
[
|
||||
BROKERAGE_GL,
|
||||
f.brokerage
|
||||
],
|
||||
[
|
||||
OTHER_CHARGES_GL,
|
||||
f.otherCharges
|
||||
]
|
||||
] as const) {
|
||||
if (amount && amount > 0) {
|
||||
lines.push({ side: 'Dr', glCode: gl.glCode, glName: gl.glName, amount });
|
||||
}
|
||||
}
|
||||
lines.push({ side: 'Cr', glCode: crGl, glName: this.glNameOf(crGl), amount: total });
|
||||
return lines;
|
||||
}
|
||||
@@ -693,6 +749,7 @@ export class BondInvestmentComponent implements OnInit {
|
||||
if (!f.scriptCode) missing.push('Script Code');
|
||||
if (!f.partyCode) missing.push('Party Code');
|
||||
if (!f.dealDate) missing.push('Deal Date');
|
||||
if (!f.dealTime) missing.push('Deal Time');
|
||||
if (this.isMutualFund) {
|
||||
if (!f.considerAmt) missing.push('Consider Amt');
|
||||
if (!f.nav) missing.push('NAV');
|
||||
@@ -726,9 +783,11 @@ export class BondInvestmentComponent implements OnInit {
|
||||
dealTime: f.dealTime || '',
|
||||
settlementType: f.settlementType,
|
||||
...(this.isMutualFund
|
||||
? { considerAmt: f.considerAmt, nav: f.nav, stampDuty: f.stampDuty ?? null }
|
||||
? { considerAmt: f.considerAmt, nav: f.nav }
|
||||
: { faceValue: f.faceValue, purchaseRate: f.purchaseRate, lastIntDate: f.lastIntDt }),
|
||||
stampDuty: f.stampDuty ?? null,
|
||||
brokerage: f.brokerage ?? null,
|
||||
otherCharges: f.otherCharges ?? null,
|
||||
category: f.category,
|
||||
crGlAccountId,
|
||||
subType: f.subType || '',
|
||||
|
||||
Reference in New Issue
Block a user