feat(investment): Daily Script Master, market rate on purchase, broken-period interest as expense
- 09 Daily Script Master now saves to and loads from the backend (sample rows removed), with Drop to correct a wrong rate. - Purchase Entry takes the rate (NAV for a mutual fund) from the newest Daily Script Master rate on or before the deal date, shows which rate was used, warns when the rate entered is outside the day's low-high, and clears the rate when the script has none. - Broken-period interest paid to the seller is debited to expense GL 500606 instead of Interest Receivable (RBI UCB Investment Directions, para 152, confirmed by Jitendra Sir); Interest Entry labels it so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -17,7 +17,6 @@ import {
|
||||
MUTUAL_FUND_PRODUCTS,
|
||||
SGL_BANK_MASTER,
|
||||
SCRIPT_MARKET_DETAIL,
|
||||
DAILY_SCRIPT_RATES,
|
||||
LIEN_REASON_MASTER,
|
||||
ScriptMaster,
|
||||
BrokerMaster,
|
||||
@@ -36,7 +35,7 @@ import {
|
||||
periodBetween
|
||||
} from '../investment-data';
|
||||
import { exportWorkbook, ExportSheetSpec } from '../investment-export';
|
||||
import { InvestmentGlAccount, InvestmentService, apiErrorMessage } from '../investment.service';
|
||||
import { InvestmentGlAccount, InvestmentService, apiErrorMessage, toDailyScriptRate } from '../investment.service';
|
||||
|
||||
type MasterTab =
|
||||
| 'party'
|
||||
@@ -79,7 +78,8 @@ export class InvestmentMastersComponent implements OnInit {
|
||||
mfProducts: MutualFundProductMaster[] = [...MUTUAL_FUND_PRODUCTS];
|
||||
sglBanks: SglBankMaster[] = [...SGL_BANK_MASTER];
|
||||
marketDetails: ScriptMarketDetail[] = [...SCRIPT_MARKET_DETAIL];
|
||||
dailyScriptRates: DailyScriptRate[] = [...DAILY_SCRIPT_RATES];
|
||||
/** Loaded from the backend (Daily Script Master) in ngOnInit. */
|
||||
dailyScriptRates: DailyScriptRate[] = [];
|
||||
lienReasons: LienReason[] = [...LIEN_REASON_MASTER];
|
||||
|
||||
readonly instrumentTypes: InstrumentType[] = [
|
||||
@@ -131,6 +131,7 @@ export class InvestmentMastersComponent implements OnInit {
|
||||
newDailyRate: Partial<DailyScriptRate> = {};
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadDailyRates();
|
||||
this.investmentService.getAssetGlAccounts().subscribe({
|
||||
next: (gls) => (this.investmentGlOptions = gls),
|
||||
error: (err) => this.toast(`Could not load GL accounts: ${apiErrorMessage(err)}`)
|
||||
@@ -435,24 +436,56 @@ export class InvestmentMastersComponent implements OnInit {
|
||||
this.toast('SGL Bank master added.');
|
||||
}
|
||||
|
||||
private loadDailyRates(): void {
|
||||
this.investmentService.getDailyRates().subscribe({
|
||||
next: (rows) => (this.dailyScriptRates = rows.map(toDailyScriptRate)),
|
||||
error: (err) => this.toast(`Could not load daily script rates: ${apiErrorMessage(err)}`)
|
||||
});
|
||||
}
|
||||
|
||||
addDailyRate(): void {
|
||||
if (!this.newDailyRate.scriptCode || !this.newDailyRate.rateDate || this.newDailyRate.closeRate == null) {
|
||||
const r = this.newDailyRate;
|
||||
if (!r.scriptCode || !r.rateDate || r.closeRate == null) {
|
||||
this.toast('Enter Rate Date, Script Code and Close Rate.');
|
||||
return;
|
||||
}
|
||||
const script = this.scripts.find((s) => s.scriptCode === this.newDailyRate.scriptCode);
|
||||
this.dailyScriptRates = [
|
||||
{
|
||||
scriptName: script?.scriptName || '',
|
||||
openRate: this.newDailyRate.closeRate,
|
||||
highRate: this.newDailyRate.closeRate,
|
||||
lowRate: this.newDailyRate.closeRate,
|
||||
...this.newDailyRate
|
||||
} as DailyScriptRate,
|
||||
...this.dailyScriptRates
|
||||
];
|
||||
this.newDailyRate = {};
|
||||
this.toast('Daily script rate added.');
|
||||
const script = this.scripts.find((s) => s.scriptCode === r.scriptCode);
|
||||
if (!script?.id) {
|
||||
this.toast(`Script ${r.scriptCode} is not saved in Script Master.`);
|
||||
return;
|
||||
}
|
||||
const body = {
|
||||
scriptId: script.id,
|
||||
rateDate: r.rateDate,
|
||||
closeRate: r.closeRate,
|
||||
...(r.openRate != null ? { openRate: r.openRate } : {}),
|
||||
...(r.highRate != null ? { highRate: r.highRate } : {}),
|
||||
...(r.lowRate != null ? { lowRate: r.lowRate } : {}),
|
||||
dateFormat: 'dd-MM-yyyy',
|
||||
locale: 'en'
|
||||
};
|
||||
this.investmentService.createDailyRate(body).subscribe({
|
||||
next: () => {
|
||||
this.toast(`Rate for ${r.scriptCode} on ${r.rateDate} saved.`);
|
||||
this.newDailyRate = {};
|
||||
this.loadDailyRates();
|
||||
},
|
||||
error: (err) => this.toast(apiErrorMessage(err))
|
||||
});
|
||||
}
|
||||
|
||||
/** A wrong rate is corrected by dropping it and entering it again. */
|
||||
dropDailyRate(r: DailyScriptRate): void {
|
||||
if (!r.id) {
|
||||
return;
|
||||
}
|
||||
this.investmentService.deleteDailyRate(r.id).subscribe({
|
||||
next: () => {
|
||||
this.toast(`Rate for ${r.scriptCode} on ${r.rateDate} dropped.`);
|
||||
this.loadDailyRates();
|
||||
},
|
||||
error: (err) => this.toast(apiErrorMessage(err))
|
||||
});
|
||||
}
|
||||
|
||||
// -------------------- Export to Excel --------------------
|
||||
|
||||
Reference in New Issue
Block a user