+
+
+
+
+
+
+
+
+
+
+
+ @if (error) {
+
{{ error }}
+ }
+
+
+ @if (report; as r) {
+
+
+ Received₹{{ totals.received | number: '1.2-2' }}
+
+
+ Receivable₹{{ totals.receivable | number: '1.2-2' }}
+
+
+ Of which provisioned (100603)₹{{ totals.provisioned | number: '1.2-2' }}
+
+
+ Total₹{{ totals.total | number: '1.2-2' }}
+
+
+
+
+
+ {{ r.fromDate }} to {{ r.toDate }} · received in the period, receivable as on {{ r.toDate }}
+
+
+
+
+ | Investment |
+ Deal No |
+ Particulars |
+ Status |
+ Principal / Face Value |
+ Rate |
+ Received |
+ Receivable |
+ Of which provisioned |
+ Total |
+
+
+
+ @for (x of rows; track x.instrument + x.refId) {
+
+ | {{ x.instrument === 'FD' ? 'FD' : 'Govt Security / Bond' }} |
+
+ {{ x.dealNo }}
+ |
+ {{ x.particulars }} |
+ {{ x.status }} |
+ ₹{{ x.principal | number: '1.2-2' }} |
+ {{ x.rate !== null && x.rate !== undefined ? x.rate + '%' : '—' }} |
+ ₹{{ x.received | number: '1.2-2' }} |
+ ₹{{ x.receivable | number: '1.2-2' }} |
+ ₹{{ x.provisioned | number: '1.2-2' }} |
+ ₹{{ x.total | number: '1.2-2' }} |
+
+ } @empty {
+
+ | No interest received or receivable in this period. |
+
+ }
+
+ @if (rows.length) {
+
+
+ | Total |
+ ₹{{ totals.received | number: '1.2-2' }} |
+ ₹{{ totals.receivable | number: '1.2-2' }} |
+ ₹{{ totals.provisioned | number: '1.2-2' }} |
+ ₹{{ totals.total | number: '1.2-2' }} |
+
+
+ }
+
+
+ }
+
diff --git a/src/app/investment/investment-interest-report/investment-interest-report.component.ts b/src/app/investment/investment-interest-report/investment-interest-report.component.ts
new file mode 100644
index 000000000..913aca0b0
--- /dev/null
+++ b/src/app/investment/investment-interest-report/investment-interest-report.component.ts
@@ -0,0 +1,173 @@
+/**
+ * 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 { DateDdmmyyyyPickerComponent } from '../date-ddmmyyyy-picker/date-ddmmyyyy-picker.component';
+import { parseDDMMYYYY, todayDDMMYYYY } from '../investment-data';
+import { exportWorkbook } from '../investment-export';
+import {
+ InvestmentInterestReportDto,
+ InvestmentInterestReportRowDto,
+ InvestmentService,
+ apiErrorMessage
+} from '../investment.service';
+
+type InstrumentFilter = '' | 'SECURITY' | 'FD';
+
+/**
+ * Total Interest Received & Receivable: per Govt Security / bond deal and FD, the interest received in a period and the
+ * interest earned up to its last day that has not come in yet, with the part already provisioned in the books.
+ */
+@Component({
+ selector: 'mifosx-investment-interest-report',
+ templateUrl: './investment-interest-report.component.html',
+ styleUrls: [
+ '../../cashier/cashier-shared.scss',
+ '../investment-shared.scss',
+ '../investment-diary/investment-diary.component.scss'
+ ],
+ standalone: true,
+ imports: [
+ CommonModule,
+ FormsModule,
+ DateDdmmyyyyPickerComponent
+ ]
+})
+export class InvestmentInterestReportComponent implements OnInit {
+ private readonly investmentService = inject(InvestmentService);
+
+ /** Defaults to the current financial year, 1 April to today. */
+ fromDate = InvestmentInterestReportComponent.financialYearStart();
+ toDate = todayDDMMYYYY();
+ instrument: InstrumentFilter = '';
+ report: InvestmentInterestReportDto | null = null;
+ loading = false;
+ generating = false;
+ error = '';
+
+ ngOnInit(): void {
+ this.load();
+ }
+
+ private static financialYearStart(): string {
+ const d = parseDDMMYYYY(todayDDMMYYYY());
+ const year = d.getMonth() >= 3 ? d.getFullYear() : d.getFullYear() - 1;
+ return `01-04-${year}`;
+ }
+
+ load(): void {
+ if (!this.fromDate || !this.toDate) {
+ this.error = 'Enter the From and To dates.';
+ return;
+ }
+ this.loading = true;
+ this.error = '';
+ this.investmentService.getInterestReport(this.fromDate, this.toDate).subscribe({
+ next: (r) => {
+ this.report = r;
+ this.loading = false;
+ },
+ error: (err) => {
+ this.report = null;
+ this.loading = false;
+ this.error = apiErrorMessage(err);
+ }
+ });
+ }
+
+ get rows(): InvestmentInterestReportRowDto[] {
+ return (this.report?.rows ?? []).filter((r) => !this.instrument || r.instrument === this.instrument);
+ }
+
+ /** Totals of the rows shown, so they follow the Investment filter. */
+ get totals(): { received: number; receivable: number; provisioned: number; total: number } {
+ return this.rows.reduce(
+ (t, r) => ({
+ received: t.received + r.received,
+ receivable: t.receivable + r.receivable,
+ provisioned: t.provisioned + r.provisioned,
+ total: t.total + r.total
+ }),
+ { received: 0, receivable: 0, provisioned: 0, total: 0 }
+ );
+ }
+
+ async exportExcel(): Promise