/** * 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 { ActivatedRoute, Router } from '@angular/router'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { of } from 'rxjs'; import { catchError } from 'rxjs/operators'; import { SharesService } from '../../shares.service'; import { SHARE_TXN_TYPE, fundingLabel, holdingStateClass, holdingStateLabel, holdingStateNote, holdingStateRowClass, shareReportCsv, shareReportPrint } from '../share-report.util'; /** * Folio Statement — one member's folio in the share register: every account they hold and every * movement across all of them, in one running sequence. * *

* Where the Account Statement is one account, a folio is the member. Someone holding two share * classes has two accounts but one folio, and the register is kept by folio — so the running balance * here is across accounts, which is the figure the register itself carries. */ @Component({ selector: 'mifosx-share-folio-statement', templateUrl: './share-folio-statement.component.html', styleUrls: [ '../../../letter-mgmt/certificates/certificates.shared.scss', '../share-report.shared.scss' ], imports: [ CommonModule, FormsModule, FaIconComponent ] }) export class ShareFolioStatementComponent implements OnInit { private sharesService = inject(SharesService); private route = inject(ActivatedRoute); private router = inject(Router); search = ''; searching = false; searched = false; loadError = ''; matches: any[] = []; folio: any = null; accounts: any[] = []; lines: any[] = []; totals: any = null; fromDate = ''; toDate = ''; /** Held once a folio is open, so changing the period re-queries the same member. */ private resolvedClientId: number | null = null; ngOnInit(): void { const clientId = this.route.snapshot.queryParamMap.get('clientId'); if (clientId) { this.resolvedClientId = Number(clientId); this.fetch({ clientId: this.resolvedClientId }); } } runSearch(): void { const term = this.search.trim(); if (!term) { return; } this.resolvedClientId = null; this.fetch({ search: term }); } loadByClient(clientId: number): void { this.resolvedClientId = clientId; this.fetch({ clientId }); } reloadPeriod(): void { if (this.resolvedClientId) { this.fetch({ clientId: this.resolvedClientId }); } } clearPeriod(): void { this.fromDate = ''; this.toDate = ''; this.reloadPeriod(); } private fetch(params: { search?: string; clientId?: number }): void { this.searching = true; this.loadError = ''; this.sharesService .getShareFolioStatement({ ...params, fromDate: this.fromDate, toDate: this.toDate }) .pipe( catchError((err) => { this.loadError = this.readError(err, 'The folio statement could not be loaded.'); return of(null); }) ) .subscribe((res: any) => { this.matches = res?.matches || []; this.folio = res?.folio || null; this.accounts = res?.accounts || []; this.lines = res?.lines || []; this.totals = res?.totals || null; if (this.folio) { this.resolvedClientId = this.folio.clientId; } this.searching = false; this.searched = true; }); } typeLabel(typeEnum: number): string { return SHARE_TXN_TYPE[typeEnum]?.label || String(typeEnum ?? ''); } typeClass(typeEnum: number): string { return SHARE_TXN_TYPE[typeEnum]?.cls || 'srep-pill--grey'; } funding(source: string): string { return fundingLabel(source); } stateLabel(state: string): string { return holdingStateLabel(state); } stateClass(state: string): string { return holdingStateClass(state); } stateRowClass(state: string): string { return holdingStateRowClass(state); } stateNote(state: string): string { return holdingStateNote(state); } openAccount(account: any): void { this.router.navigate([ '/clients', this.folio.clientId, 'shares-accounts', account.shareAccountId, 'general' ]); } exportCsv(): void { if (!this.folio) { return; } shareReportCsv( `folio-statement-${this.folio.folioNumber || this.folio.clientId}`, [ 'Date', 'Share A/c No', 'Product', 'Particulars', 'Shares In', 'Shares Out', 'Unit Price', 'Amount', 'Funded By', 'Board Resolution', 'Folio Balance' ], this.lines.map((l) => [ l.transactionDate, l.accountNo, l.productName, this.typeLabel(l.typeEnum), l.sharesIn || '', l.sharesOut || '', l.unitPrice, l.amount, this.funding(l.fundingSource), l.resolutionNumber, l.folioBalance ]) ); } print(): void { shareReportPrint(); } private readError(err: any, fallback: string): string { return ( err?.error?.errors?.[0]?.defaultUserMessage || err?.error?.defaultUserMessage || err?.error?.developerMessage || fallback ); } }