Files
cbsnexora/src/app/shared/accounting/view-journal-entry-transaction/view-journal-entry-transaction.component.ts
T
niteshandClaude Sonnet 5.5 4e3b49a96a feat(ui): remove Undo / Revert transaction actions
Removes the Undo button and Undo menu item from savings, current, fixed deposit, recurring deposit
and loan transactions, the account-transfer Undo, and the Revert Transaction button on the
journal entry transaction detail, to prevent accidental reversal of posted entries.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:41:39 +05:30

177 lines
5.2 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, 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<any>;
@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<string, string> = {
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';
}
}