123 lines
4.0 KiB
TypeScript
123 lines
4.0 KiB
TypeScript
/**
|
|
* 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/.
|
|
*/
|
|
|
|
import { Component, OnInit, inject } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { FormsModule } from '@angular/forms';
|
|
import { RouterModule } from '@angular/router';
|
|
import { DateDdmmyyyyPickerComponent } from '../date-ddmmyyyy-picker/date-ddmmyyyy-picker.component';
|
|
import { addPeriod, todayDDMMYYYY } from '../investment-data';
|
|
import { InvestmentDiaryDto, InvestmentDiaryRowDto, InvestmentService, apiErrorMessage } from '../investment.service';
|
|
|
|
type InstrumentFilter = '' | 'SECURITY' | 'FD';
|
|
type StatusFilter = '' | 'PENDING' | 'POSTED';
|
|
|
|
/**
|
|
* Due Date Diary for All Investment: coupons, 31 Mar / 30 Sep provisions, premium amortisation, maturities and FD
|
|
* payouts in a period, with what is posted, due or overdue, and a link to the screen that posts each one.
|
|
*/
|
|
@Component({
|
|
selector: 'mifosx-investment-diary',
|
|
templateUrl: './investment-diary.component.html',
|
|
styleUrls: [
|
|
'../../cashier/cashier-shared.scss',
|
|
'../investment-shared.scss',
|
|
'./investment-diary.component.scss'
|
|
],
|
|
standalone: true,
|
|
imports: [
|
|
CommonModule,
|
|
FormsModule,
|
|
RouterModule,
|
|
DateDdmmyyyyPickerComponent
|
|
]
|
|
})
|
|
export class InvestmentDiaryComponent implements OnInit {
|
|
private readonly investmentService = inject(InvestmentService);
|
|
|
|
// Opens on everything still to be done: what is pending from the past year and what falls due in the next 30 days.
|
|
fromDate = addPeriod(todayDDMMYYYY(), -1, 0, 0);
|
|
toDate = addPeriod(todayDDMMYYYY(), 0, 0, 30);
|
|
instrument: InstrumentFilter = '';
|
|
status: StatusFilter = 'PENDING';
|
|
diary: InvestmentDiaryDto | null = null;
|
|
loading = false;
|
|
error = '';
|
|
|
|
readonly kindLabels: Record<InvestmentDiaryRowDto['kind'], string> = {
|
|
COUPON: 'Coupon',
|
|
PROVISION: 'Interest provision',
|
|
MATURITY: 'Maturity / redemption',
|
|
AMORTISATION: 'Premium amortisation',
|
|
FD_PROVISION: 'FD interest provision',
|
|
FD_PAYOUT: 'FD interest payout',
|
|
FD_MATURITY: 'FD maturity'
|
|
};
|
|
|
|
ngOnInit(): void {
|
|
this.load();
|
|
}
|
|
|
|
/** Quick ranges from today. */
|
|
setRange(days: number): void {
|
|
this.status = '';
|
|
this.fromDate = todayDDMMYYYY();
|
|
this.toDate = addPeriod(this.fromDate, 0, 0, days);
|
|
this.load();
|
|
}
|
|
|
|
/** What is still pending from the past (up to a year back) and today. */
|
|
showOverdue(): void {
|
|
this.toDate = todayDDMMYYYY();
|
|
this.fromDate = addPeriod(this.toDate, -1, 0, 0);
|
|
this.status = 'PENDING';
|
|
this.load();
|
|
}
|
|
|
|
load(): void {
|
|
if (!this.fromDate || !this.toDate) {
|
|
this.error = 'Enter the From and To dates.';
|
|
return;
|
|
}
|
|
this.loading = true;
|
|
this.error = '';
|
|
this.investmentService.getDiary(this.fromDate, this.toDate).subscribe({
|
|
next: (d) => {
|
|
this.diary = d;
|
|
this.loading = false;
|
|
},
|
|
error: (err) => {
|
|
this.diary = null;
|
|
this.loading = false;
|
|
this.error = apiErrorMessage(err);
|
|
}
|
|
});
|
|
}
|
|
|
|
get rows(): InvestmentDiaryRowDto[] {
|
|
return (this.diary?.rows ?? []).filter(
|
|
(r) =>
|
|
(!this.instrument || r.instrument === this.instrument) &&
|
|
(!this.status || (this.status === 'POSTED' ? r.status === 'POSTED' : r.status !== 'POSTED'))
|
|
);
|
|
}
|
|
|
|
/** The screen that posts this entry. */
|
|
link(r: InvestmentDiaryRowDto): { path: string; query: Record<string, string | number> } {
|
|
if (r.instrument === 'FD') {
|
|
return { path: '/investment/fd', query: { tab: 'interest', fd: r.refId } };
|
|
}
|
|
const tab = r.kind === 'MATURITY' ? 'redemption' : r.kind === 'AMORTISATION' ? 'amortize' : 'interest';
|
|
return { path: '/investment/bonds', query: { tab } };
|
|
}
|
|
|
|
statusLabel(r: InvestmentDiaryRowDto): string {
|
|
return r.status === 'DUE' ? 'Due today' : r.status.charAt(0) + r.status.slice(1).toLowerCase();
|
|
}
|
|
}
|