/** * 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/. */ /** Angular Imports */ import { Component, OnInit, ElementRef, ViewChild, inject } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { UntypedFormBuilder, Validators } from '@angular/forms'; import { CurrencyPipe } from '@angular/common'; import { MatIcon } from '@angular/material/icon'; import { DateFormatPipe } from '../../../pipes/date-format.pipe'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; /** * Share Account Passbook — a printable, chronological (oldest-first) ledger of every * Purchase/Redeem entry, mirroring PassbookTabComponent (Savings) but for share holdings: * shares purchased/redeemed instead of amount deposited/withdrawn, plus the Board Resolution * Number / Date of Meeting on redeem rows. */ @Component({ selector: 'mifosx-shares-passbook-tab', templateUrl: './passbook-tab.component.html', styleUrls: ['./passbook-tab.component.scss'], standalone: true, imports: [ ...STANDALONE_SHARED_IMPORTS, MatIcon, DateFormatPipe, CurrencyPipe ] }) export class SharesPassbookTabComponent implements OnInit { private route = inject(ActivatedRoute); private formBuilder = inject(UntypedFormBuilder); @ViewChild('passbookContent') passbookContent: ElementRef; /** Account data */ accountNo = ''; clientName = ''; productName = ''; currency: any = null; status = ''; activatedOnDate: any = null; resolutionNumber = ''; resolutionDate: any = null; savingsAccountNumber = ''; totalApprovedShares = 0; currentMarketPrice = 0; /** Transactions */ allTransactions: any[] = []; filteredTransactions: any[] = []; /** Date range form */ minDate = new Date(2000, 0, 1); maxDate = new Date(); dateRangeForm: any; isFiltered = false; get currentValue(): number { return this.totalApprovedShares * this.currentMarketPrice; } ngOnInit(): void { this.route.parent.data.subscribe((data: { sharesAccountData: any }) => { const account = data.sharesAccountData; this.accountNo = account.accountNo || ''; this.clientName = account.clientName || ''; this.productName = account.productName || ''; this.currency = account.currency || null; this.status = account.status?.value || ''; this.activatedOnDate = account.timeline?.activatedDate || null; this.resolutionNumber = account.resolutionNumber || ''; this.resolutionDate = account.resolutionDate || null; this.savingsAccountNumber = account.savingsAccountNumber || ''; this.totalApprovedShares = account.summary?.totalApprovedShares || 0; this.currentMarketPrice = account.currentMarketPrice || 0; const transactions = (account.purchasedShares || []).filter( (transaction: any) => transaction.type.value !== 'Charge Payment' ); this.allTransactions = this.recalculateRunningBalances(this.sortAscending(transactions)); this.filteredTransactions = [...this.allTransactions]; }); this.dateRangeForm = this.formBuilder.group({ fromDate: [ '', Validators.required ], toDate: [ '', Validators.required ] }); } isRedeem(transaction: any): boolean { return transaction.type?.value === 'Redeem'; } filterTransactions(): void { const fromDate = this.dateRangeForm.value.fromDate; const toDate = this.dateRangeForm.value.toDate; if (!fromDate || !toDate) return; const from = new Date(fromDate).getTime(); const to = new Date(toDate).getTime(); this.filteredTransactions = this.allTransactions.filter((txn: any) => { const txnDate = this.getTransactionDateAsTime(txn.purchasedDate); return txnDate >= from && txnDate <= to; }); this.isFiltered = true; } clearFilter(): void { this.dateRangeForm.reset(); this.filteredTransactions = [...this.allTransactions]; this.isFiltered = false; } private getTransactionDateAsTime(date: any): number { if (Array.isArray(date) && date.length >= 3) { return new Date(date[0], date[1] - 1, date[2]).getTime(); } return new Date(date).getTime(); } printPassbook(): void { const content = this.passbookContent?.nativeElement?.innerHTML; if (!content) return; const printWindow = window.open('', 'SharePassbook', 'height=700,width=900'); printWindow.document.write(` Share Account Passbook - ${this.accountNo} ${content} `); printWindow.document.close(); printWindow.focus(); printWindow.print(); printWindow.close(); } private recalculateRunningBalances(transactions: any[]): any[] { let balance = 0; return transactions.map((txn) => { const shares = Number(txn.numberOfShares) || 0; balance += this.isRedeem(txn) ? -shares : shares; return { ...txn, runningBalance: balance }; }); } private sortAscending(transactions: any[]): any[] { return [...transactions].sort((a, b) => { const dateA = this.getTransactionDateAsTime(a.purchasedDate); const dateB = this.getTransactionDateAsTime(b.purchasedDate); if (dateA !== dateB) return dateA - dateB; return (a.id as number) - (b.id as number); }); } }