/** * 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, ViewChild, inject } from '@angular/core'; import { ViewJournalEntryComponent } from '../view-journal-entry/view-journal-entry.component'; import { MatDialog } from '@angular/material/dialog'; import { ActivatedRoute } from '@angular/router'; import { MatSort, MatSortHeader } from '@angular/material/sort'; import { MatPaginator } from '@angular/material/paginator'; import { MatTableDataSource, MatTable, MatColumnDef, MatHeaderCellDef, MatHeaderCell, MatCellDef, MatCell, MatHeaderRowDef, MatHeaderRow, MatRowDef, MatRow } from '@angular/material/table'; import { Location, NgClass } from '@angular/common'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { DateFormatPipe } from '../../../pipes/date-format.pipe'; import { DatetimeFormatPipe } from '../../../pipes/datetime-format.pipe'; import { FormatNumberPipe } from '../../../pipes/format-number.pipe'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; import { YesnoPipe } from '@pipes/yesno.pipe'; import { MatCardModule } from '@angular/material/card'; import { MatTooltipModule } from '@angular/material/tooltip'; @Component({ selector: 'mifosx-view-journal-entry-transaction', templateUrl: './view-journal-entry-transaction.component.html', styleUrls: ['./view-journal-entry-transaction.component.scss'], imports: [ ...STANDALONE_SHARED_IMPORTS, FaIconComponent, MatTable, MatSort, MatColumnDef, MatHeaderCellDef, MatHeaderCell, MatSortHeader, MatCellDef, MatCell, MatHeaderRowDef, MatHeaderRow, MatRowDef, MatRow, NgClass, DateFormatPipe, DatetimeFormatPipe, FormatNumberPipe, MatCardModule, MatTooltipModule ] }) export class ViewJournalEntryTransactionComponent implements OnInit { private route = inject(ActivatedRoute); dialog = inject(MatDialog); private location = inject(Location); title: string; journalEntriesData: any[]; transaction: any; transactionId: string; displayedColumns: string[] = [ 'id', 'glAccountType', 'glAccountCode', 'glAccountName', 'savingsAccountNo', 'entryType', 'debit', 'credit' ]; dataSource: MatTableDataSource; @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator; @ViewChild(MatSort, { static: true }) sort: MatSort; isJournalEntryLoaded = false; isManualJournalEntry = false; ngOnInit() { this.route.data.subscribe((data: { title: string; transaction: any; transferJournalEntryData: any }) => { this.title = data.title; this.isJournalEntryLoaded = false; if (this.isViewTransaction()) { this.transaction = data.transaction; if (data.transaction.pageItems.length > 0) { this.isJournalEntryLoaded = true; this.transactionId = data.transaction.pageItems[0].transactionId; this.isManualJournalEntry = data.transaction.pageItems[0].manualEntry; } } else if (this.isViewTransfer()) { this.journalEntriesData = data.transferJournalEntryData.journalEntryData.content; this.isJournalEntryLoaded = true; } this.setTransaction(); }); } isViewTransaction(): boolean { return this.title === 'View Transaction'; } isViewTransfer(): boolean { return this.title === 'View Transfer'; } setTransaction() { if (this.journalEntriesData != null) { this.dataSource = new MatTableDataSource(this.journalEntriesData); } else { this.dataSource = new MatTableDataSource(this.transaction.pageItems); this.dataSource.sortingDataAccessor = (transaction: any, property: any) => { switch (property) { case 'glAccountType': return transaction.glAccountType.value; case 'debit': return transaction.amount; case 'credit': return transaction.amount; default: return transaction[property]; } }; } this.dataSource.paginator = this.paginator; this.dataSource.sort = this.sort; } viewJournalEntry(journalEntry: any) { this.dialog.open(ViewJournalEntryComponent, { data: { journalEntry } }); } goBack(): void { this.location.back(); } getTotalDebit(): number { return (this.dataSource?.data || []) .filter((e) => e.entryType?.value === 'DEBIT') .reduce((sum, e) => sum + (e.amount || 0), 0); } getTotalCredit(): number { return (this.dataSource?.data || []) .filter((e) => e.entryType?.value === 'CREDIT') .reduce((sum, e) => sum + (e.amount || 0), 0); } isBalanced(): boolean { return Math.abs(this.getTotalDebit() - this.getTotalCredit()) < 0.01; } getAccountTypeBadgeClass(type: string): string { const map: Record = { ASSET: 'txn-badge--asset', LIABILITY: 'txn-badge--liability', INCOME: 'txn-badge--income', EXPENSE: 'txn-badge--expense', EQUITY: 'txn-badge--equity' }; return map[type] || 'txn-badge--default'; } }