pending account terminate feature develop
This commit is contained in:
@@ -89,4 +89,8 @@ export class AccountsService {
|
||||
if (params.asOnDate) httpParams = httpParams.set('asOnDate', params.asOnDate);
|
||||
return this.http.get('/recurringdepositaccounts', { params: httpParams });
|
||||
}
|
||||
|
||||
terminateAccount(accountId: string, data: any): Observable<any> {
|
||||
return this.http.post(`/v1/accounts/${accountId}/terminate`, data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,9 @@ import { ClientsService } from 'app/clients/clients.service';
|
||||
import { ConfirmationDialogComponent } from 'app/shared/confirmation-dialog/confirmation-dialog.component';
|
||||
import { Currency } from 'app/shared/models/general.model';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { AccountsService } from 'app/accounts/accounts.service';
|
||||
import { SettingsService } from 'app/settings/settings.service';
|
||||
import { Dates } from 'app/core/utils/dates';
|
||||
|
||||
/** Environment Configuration */
|
||||
import { environment } from '../../../environments/environment';
|
||||
@@ -83,6 +86,9 @@ export class CurrentAccountViewComponent implements OnInit {
|
||||
private currentAccountsService = inject(CurrentAccountsService);
|
||||
private clientsService = inject(ClientsService);
|
||||
private translateService = inject(TranslateService);
|
||||
private accountsService = inject(AccountsService);
|
||||
private settingsService = inject(SettingsService);
|
||||
private dateUtils = inject(Dates);
|
||||
dialog = inject(MatDialog);
|
||||
|
||||
/** Current Account Data */
|
||||
@@ -126,7 +132,8 @@ export class CurrentAccountViewComponent implements OnInit {
|
||||
Close: 'danger',
|
||||
Reject: 'danger',
|
||||
Delete: 'danger',
|
||||
'Withdrawn by Client': 'danger'
|
||||
'Withdrawn by Client': 'danger',
|
||||
Terminate: 'danger'
|
||||
};
|
||||
|
||||
private readonly ACTION_ICON: Record<string, string> = {
|
||||
@@ -157,7 +164,8 @@ export class CurrentAccountViewComponent implements OnInit {
|
||||
Close: 'times-circle',
|
||||
Reject: 'ban',
|
||||
Delete: 'trash',
|
||||
'Withdrawn by Client': 'user-slash'
|
||||
'Withdrawn by Client': 'user-slash',
|
||||
Terminate: 'times-circle'
|
||||
};
|
||||
|
||||
kindOf(name: string): 'transact' | 'block' | 'interest' | 'admin' | 'danger' {
|
||||
@@ -309,6 +317,9 @@ export class CurrentAccountViewComponent implements OnInit {
|
||||
case 'Delete':
|
||||
this.deleteCurrentAccount();
|
||||
break;
|
||||
case 'Terminate':
|
||||
this.terminateCurrentAccount();
|
||||
break;
|
||||
case 'Calculate Interest':
|
||||
this.calculateInterest();
|
||||
break;
|
||||
@@ -370,6 +381,32 @@ export class CurrentAccountViewComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
private terminateCurrentAccount() {
|
||||
const terminateCurrentAccountDialogRef = this.dialog.open(ConfirmationDialogComponent, {
|
||||
data: {
|
||||
heading: 'Terminate Account',
|
||||
dialogContext: 'Are you sure you want to terminate this account?',
|
||||
type: 'Strong'
|
||||
}
|
||||
});
|
||||
terminateCurrentAccountDialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response && response.confirm) {
|
||||
const locale = this.settingsService.language.code;
|
||||
const dateFormat = this.settingsService.dateFormat;
|
||||
const terminatedOnDate = this.dateUtils.formatDate(new Date(), dateFormat);
|
||||
const data = {
|
||||
accountType: 'CURRENT',
|
||||
terminatedOnDate,
|
||||
dateFormat,
|
||||
locale
|
||||
};
|
||||
this.accountsService.terminateAccount(this.currentAccountData.id, data).subscribe(() => {
|
||||
this.reload();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates current account's interest
|
||||
*/
|
||||
|
||||
@@ -194,6 +194,10 @@ export class CurrentAccountButtonsConfiguration {
|
||||
{
|
||||
name: 'Delete',
|
||||
taskPermissionName: 'DELETE_CURRENTACCOUNT'
|
||||
},
|
||||
{
|
||||
name: 'Terminate',
|
||||
taskPermissionName: 'DELETE_CURRENTACCOUNT'
|
||||
}
|
||||
];
|
||||
break;
|
||||
|
||||
+40
-3
@@ -11,8 +11,8 @@ import { Component, OnInit, inject } from '@angular/core';
|
||||
import { ActivatedRoute, Router, RouterLinkActive, RouterLink, RouterOutlet } from '@angular/router';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
|
||||
/** Custom Dialogs */
|
||||
import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
|
||||
import { ConfirmationDialogComponent } from 'app/shared/confirmation-dialog/confirmation-dialog.component';
|
||||
import { CalculateInterestDialogComponent } from './custom-dialogs/calculate-interest-dialog/calculate-interest-dialog.component';
|
||||
import { PostInterestDialogComponent } from './custom-dialogs/post-interest-dialog/post-interest-dialog.component';
|
||||
import { ToggleWithholdTaxDialogComponent } from './custom-dialogs/toggle-withhold-tax-dialog/toggle-withhold-tax-dialog.component';
|
||||
@@ -23,7 +23,10 @@ import { FixedDepositsButtonsConfiguration } from './fixed-deposits-buttons.conf
|
||||
/** Custom Services */
|
||||
import { FixedDepositsService } from '../fixed-deposits.service';
|
||||
import { SavingsService } from 'app/savings/savings.service';
|
||||
import { AccountsService } from 'app/accounts/accounts.service';
|
||||
import { Currency } from 'app/shared/models/general.model';
|
||||
import { SettingsService } from 'app/settings/settings.service';
|
||||
import { Dates } from 'app/core/utils/dates';
|
||||
import { MatTooltip } from '@angular/material/tooltip';
|
||||
import { NgClass, CurrencyPipe } from '@angular/common';
|
||||
import { AccountNumberComponent } from '../../../shared/account-number/account-number.component';
|
||||
@@ -67,6 +70,9 @@ export class FixedDepositAccountViewComponent implements OnInit {
|
||||
private router = inject(Router);
|
||||
private fixedDepositsService = inject(FixedDepositsService);
|
||||
private savingsService = inject(SavingsService);
|
||||
private accountsService = inject(AccountsService);
|
||||
private settingsService = inject(SettingsService);
|
||||
private dateUtils = inject(Dates);
|
||||
dialog = inject(MatDialog);
|
||||
|
||||
/** Fixed Deposits Account Data */
|
||||
@@ -99,7 +105,8 @@ export class FixedDepositAccountViewComponent implements OnInit {
|
||||
'Apply Annual Fees': 'admin',
|
||||
Reject: 'danger',
|
||||
'Withdrawn by Client': 'danger',
|
||||
Delete: 'danger'
|
||||
Delete: 'danger',
|
||||
Terminate: 'danger'
|
||||
};
|
||||
|
||||
private readonly ACTION_ICON: Record<string, string> = {
|
||||
@@ -121,7 +128,8 @@ export class FixedDepositAccountViewComponent implements OnInit {
|
||||
'Apply Annual Fees': 'receipt',
|
||||
Reject: 'ban',
|
||||
'Withdrawn by Client': 'user-slash',
|
||||
Delete: 'trash'
|
||||
Delete: 'trash',
|
||||
Terminate: 'times-circle'
|
||||
};
|
||||
|
||||
kindOf(name: string): 'transact' | 'block' | 'interest' | 'admin' | 'danger' {
|
||||
@@ -237,6 +245,9 @@ export class FixedDepositAccountViewComponent implements OnInit {
|
||||
case 'Disable Withhold Tax':
|
||||
this.disableWithHoldTax();
|
||||
break;
|
||||
case 'Terminate':
|
||||
this.terminateFixedDepositsAccount();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,6 +267,32 @@ export class FixedDepositAccountViewComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
private terminateFixedDepositsAccount() {
|
||||
const terminateFixedDepositAccountDialogRef = this.dialog.open(ConfirmationDialogComponent, {
|
||||
data: {
|
||||
heading: 'Terminate Account',
|
||||
dialogContext: 'Are you sure you want to terminate this account?',
|
||||
type: 'Strong'
|
||||
}
|
||||
});
|
||||
terminateFixedDepositAccountDialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response && response.confirm) {
|
||||
const locale = this.settingsService.language.code;
|
||||
const dateFormat = this.settingsService.dateFormat;
|
||||
const terminatedOnDate = this.dateUtils.formatDate(new Date(), dateFormat);
|
||||
const data = {
|
||||
accountType: 'FD',
|
||||
terminatedOnDate,
|
||||
dateFormat,
|
||||
locale
|
||||
};
|
||||
this.accountsService.terminateAccount(this.fixedDepositsAccountData.id, data).subscribe(() => {
|
||||
this.reload();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates fixed deposit account's interest
|
||||
*/
|
||||
|
||||
+3
@@ -132,6 +132,9 @@ export class FixedDepositsButtonsConfiguration {
|
||||
},
|
||||
{
|
||||
name: 'Delete'
|
||||
},
|
||||
{
|
||||
name: 'Terminate'
|
||||
}
|
||||
];
|
||||
break;
|
||||
|
||||
+40
-2
@@ -20,9 +20,13 @@ import { RecurringDepositsButtonsConfiguration } from './recurring-deposits-butt
|
||||
|
||||
/** Custom Dialogs */
|
||||
import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
|
||||
import { ConfirmationDialogComponent } from 'app/shared/confirmation-dialog/confirmation-dialog.component';
|
||||
import { RecurringDepositConfirmationDialogComponent } from './custom-dialogs/recurring-deposit-confirmation-dialog/recurring-deposit-confirmation-dialog.component';
|
||||
import { Currency } from 'app/shared/models/general.model';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { AccountsService } from 'app/accounts/accounts.service';
|
||||
import { SettingsService } from 'app/settings/settings.service';
|
||||
import { Dates } from 'app/core/utils/dates';
|
||||
import { MatTooltip } from '@angular/material/tooltip';
|
||||
import { NgClass, DecimalPipe, CurrencyPipe } from '@angular/common';
|
||||
import { AccountNumberComponent } from '../../../shared/account-number/account-number.component';
|
||||
@@ -67,6 +71,9 @@ export class RecurringDepositsAccountViewComponent implements OnInit {
|
||||
private router = inject(Router);
|
||||
private recurringDepositsService = inject(RecurringDepositsService);
|
||||
private savingsService = inject(SavingsService);
|
||||
private accountsService = inject(AccountsService);
|
||||
private settingsService = inject(SettingsService);
|
||||
private dateUtils = inject(Dates);
|
||||
dialog = inject(MatDialog);
|
||||
private translateService = inject(TranslateService);
|
||||
|
||||
@@ -103,7 +110,8 @@ export class RecurringDepositsAccountViewComponent implements OnInit {
|
||||
'Apply Annual Fees': 'admin',
|
||||
Reject: 'danger',
|
||||
'Withdrawn by Client': 'danger',
|
||||
Delete: 'danger'
|
||||
Delete: 'danger',
|
||||
Terminate: 'danger'
|
||||
};
|
||||
|
||||
private readonly ACTION_ICON: Record<string, string> = {
|
||||
@@ -125,7 +133,8 @@ export class RecurringDepositsAccountViewComponent implements OnInit {
|
||||
'Apply Annual Fees': 'receipt',
|
||||
Reject: 'ban',
|
||||
'Withdrawn by Client': 'user-slash',
|
||||
Delete: 'trash'
|
||||
Delete: 'trash',
|
||||
Terminate: 'times-circle'
|
||||
};
|
||||
|
||||
kindOf(name: string): 'transact' | 'block' | 'interest' | 'admin' | 'danger' {
|
||||
@@ -287,6 +296,9 @@ export class RecurringDepositsAccountViewComponent implements OnInit {
|
||||
case 'Disable Withhold Tax':
|
||||
this.disableWithHoldTax();
|
||||
break;
|
||||
case 'Terminate':
|
||||
this.terminateRecurringDepositsAccount();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,6 +320,32 @@ export class RecurringDepositsAccountViewComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
private terminateRecurringDepositsAccount() {
|
||||
const terminateRecurringDepositAccountDialogRef = this.dialog.open(ConfirmationDialogComponent, {
|
||||
data: {
|
||||
heading: 'Terminate Account',
|
||||
dialogContext: 'Are you sure you want to terminate this account?',
|
||||
type: 'Strong'
|
||||
}
|
||||
});
|
||||
terminateRecurringDepositAccountDialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response && response.confirm) {
|
||||
const locale = this.settingsService.language.code;
|
||||
const dateFormat = this.settingsService.dateFormat;
|
||||
const terminatedOnDate = this.dateUtils.formatDate(new Date(), dateFormat);
|
||||
const data = {
|
||||
accountType: 'RD',
|
||||
terminatedOnDate,
|
||||
dateFormat,
|
||||
locale
|
||||
};
|
||||
this.accountsService.terminateAccount(this.recurringDepositsAccountData.id, data).subscribe(() => {
|
||||
this.reload();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates savings account's interest
|
||||
*/
|
||||
|
||||
+5
@@ -163,6 +163,11 @@ export class RecurringDepositsButtonsConfiguration {
|
||||
name: 'Delete',
|
||||
icon: 'trash',
|
||||
taskPermissionName: 'DELETE_RECURRINGDEPOSITACCOUNT'
|
||||
},
|
||||
{
|
||||
name: 'Terminate',
|
||||
icon: 'times-circle',
|
||||
taskPermissionName: 'DELETE_RECURRINGDEPOSITACCOUNT'
|
||||
}
|
||||
];
|
||||
break;
|
||||
|
||||
@@ -30,6 +30,7 @@ export class StatusLookupPipe implements PipeTransform {
|
||||
'savingsAccountStatusType.activeInactive': 'status-active-overdue',
|
||||
'savingsAccountStatusType.activeDormant': 'status-active-overdue',
|
||||
'savingsAccountStatusType.matured': 'status-matured',
|
||||
'savingsAccountStatusType.terminated': 'status-deleted',
|
||||
'shareAccountStatusType.submitted.and.pending.approval': 'status-pending',
|
||||
'shareAccountStatusType.approved': 'status-approved',
|
||||
'shareAccountStatusType.active': 'status-active',
|
||||
|
||||
@@ -24,6 +24,9 @@ import { SavingsService } from '../savings.service';
|
||||
import { ConfirmationDialogComponent } from 'app/shared/confirmation-dialog/confirmation-dialog.component';
|
||||
import { Currency } from 'app/shared/models/general.model';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { AccountsService } from 'app/accounts/accounts.service';
|
||||
import { SettingsService } from 'app/settings/settings.service';
|
||||
import { Dates } from 'app/core/utils/dates';
|
||||
|
||||
/** Environment Configuration */
|
||||
import { environment } from '../../../environments/environment';
|
||||
@@ -75,6 +78,9 @@ export class SavingsAccountViewComponent implements OnInit {
|
||||
private router = inject(Router);
|
||||
private savingsService = inject(SavingsService);
|
||||
private translateService = inject(TranslateService);
|
||||
private accountsService = inject(AccountsService);
|
||||
private settingsService = inject(SettingsService);
|
||||
private dateUtils = inject(Dates);
|
||||
dialog = inject(MatDialog);
|
||||
|
||||
/** Savings Account Data */
|
||||
@@ -124,7 +130,8 @@ export class SavingsAccountViewComponent implements OnInit {
|
||||
Close: 'danger',
|
||||
Reject: 'danger',
|
||||
Delete: 'danger',
|
||||
'Withdrawn by Client': 'danger'
|
||||
'Withdrawn by Client': 'danger',
|
||||
Terminate: 'danger'
|
||||
};
|
||||
|
||||
/** Lightweight icon fallback for actions whose buttonConfig doesn't
|
||||
@@ -157,7 +164,8 @@ export class SavingsAccountViewComponent implements OnInit {
|
||||
Close: 'times-circle',
|
||||
Reject: 'ban',
|
||||
Delete: 'trash',
|
||||
'Withdrawn by Client': 'user-slash'
|
||||
'Withdrawn by Client': 'user-slash',
|
||||
Terminate: 'times-circle'
|
||||
};
|
||||
|
||||
/** Returns the colour kind for a given action name (used to tint the
|
||||
@@ -306,6 +314,9 @@ export class SavingsAccountViewComponent implements OnInit {
|
||||
case 'Delete':
|
||||
this.deleteSavingsAccount();
|
||||
break;
|
||||
case 'Terminate':
|
||||
this.terminateSavingsAccount();
|
||||
break;
|
||||
case 'Calculate Interest':
|
||||
this.calculateInterest();
|
||||
break;
|
||||
@@ -363,6 +374,35 @@ export class SavingsAccountViewComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminates Savings Account.
|
||||
*/
|
||||
private terminateSavingsAccount() {
|
||||
const terminateSavingsAccountDialogRef = this.dialog.open(ConfirmationDialogComponent, {
|
||||
data: {
|
||||
heading: 'Terminate Account',
|
||||
dialogContext: 'Are you sure you want to terminate this account?',
|
||||
type: 'Strong'
|
||||
}
|
||||
});
|
||||
terminateSavingsAccountDialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response && response.confirm) {
|
||||
const locale = this.settingsService.language.code;
|
||||
const dateFormat = this.settingsService.dateFormat;
|
||||
const terminatedOnDate = this.dateUtils.formatDate(new Date(), dateFormat);
|
||||
const data = {
|
||||
accountType: 'SAVINGS',
|
||||
terminatedOnDate,
|
||||
dateFormat,
|
||||
locale
|
||||
};
|
||||
this.accountsService.terminateAccount(this.savingsAccountData.id, data).subscribe(() => {
|
||||
this.reload();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates savings account's interest
|
||||
*/
|
||||
|
||||
@@ -192,6 +192,10 @@ export class SavingsButtonsConfiguration {
|
||||
{
|
||||
name: 'Delete',
|
||||
taskPermissionName: 'DELETE_SAVINGSACCOUNT'
|
||||
},
|
||||
{
|
||||
name: 'Terminate',
|
||||
taskPermissionName: 'DELETE_SAVINGSACCOUNT'
|
||||
}
|
||||
];
|
||||
break;
|
||||
|
||||
@@ -115,11 +115,10 @@ export class CheckerInboxComponent implements OnInit {
|
||||
*/
|
||||
constructor() {
|
||||
this.route.data.subscribe((data: { makerCheckerResource: any; makerCheckerTemplate: any }) => {
|
||||
this.searchData = data.makerCheckerResource;
|
||||
if (this.searchData.length > 0) {
|
||||
this.checkerData = true;
|
||||
}
|
||||
this.makerCheckerTemplate = data.makerCheckerTemplate;
|
||||
const raw = data.makerCheckerResource;
|
||||
this.searchData = Array.isArray(raw) ? raw : (raw?.pageItems ?? []);
|
||||
this.checkerData = this.searchData.length > 0;
|
||||
this.makerCheckerTemplate = data.makerCheckerTemplate ?? {};
|
||||
this.dataSource = new MatTableDataSource(this.searchData);
|
||||
this.selection = new SelectionModel(true, []);
|
||||
});
|
||||
|
||||
+4
-2
@@ -82,8 +82,10 @@ export class PendingAccountComponent {
|
||||
|
||||
constructor() {
|
||||
this.route.data.subscribe((data: { pendingAccountsData: any }) => {
|
||||
// status 100 = submitted and pending approval only; exclude active/approved/etc.
|
||||
const items = (data.pendingAccountsData?.pageItems || []).filter((a: any) => a.status?.id === 100);
|
||||
// status 100 = submitted and pending approval only; exclude terminated accounts
|
||||
const items = (data.pendingAccountsData?.pageItems || []).filter(
|
||||
(a: any) => a.status?.id === 100 && !a.terminateTrue
|
||||
);
|
||||
this.showData = items.length > 0;
|
||||
this.dataSource = new MatTableDataSource(items);
|
||||
this.selection = new SelectionModel(true, []);
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
<!--
|
||||
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/.
|
||||
-->
|
||||
|
||||
<div class="cv-tab-content">
|
||||
@if (showData) {
|
||||
<div class="cv-action-bar">
|
||||
<mat-form-field appearance="outline" class="cv-search-field">
|
||||
<mat-icon matPrefix>search</mat-icon>
|
||||
<input matInput placeholder="Search accounts..." (keyup)="applyFilter($event.target['value'])" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="table-container">
|
||||
<table mat-table [dataSource]="dataSource" class="modern-table">
|
||||
<ng-container matColumnDef="accountNo">
|
||||
<th mat-header-cell *matHeaderCellDef>Account No</th>
|
||||
<td mat-cell *matCellDef="let row" class="cell-mono">{{ row.accountNo }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="clientName">
|
||||
<th mat-header-cell *matHeaderCellDef>Client Name</th>
|
||||
<td mat-cell *matCellDef="let row">{{ row.clientName }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="productName">
|
||||
<th mat-header-cell *matHeaderCellDef>Product</th>
|
||||
<td mat-cell *matCellDef="let row">{{ row.savingsProductName || row.productName }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="accountType">
|
||||
<th mat-header-cell *matHeaderCellDef>Type</th>
|
||||
<td mat-cell *matCellDef="let row">{{ row.accountType }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="officeName">
|
||||
<th mat-header-cell *matHeaderCellDef>Office</th>
|
||||
<td mat-cell *matCellDef="let row">{{ row.officeName }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="submittedOnDate">
|
||||
<th mat-header-cell *matHeaderCellDef>Submitted On</th>
|
||||
<td mat-cell *matCellDef="let row">{{ formatDate(row.timeline?.submittedOnDate || row.submittedOnDate) }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="status">
|
||||
<th mat-header-cell *matHeaderCellDef>Status</th>
|
||||
<td mat-cell *matCellDef="let row">
|
||||
<span class="status-badge status-badge--terminated">Terminated</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr
|
||||
mat-row
|
||||
*matRowDef="let row; columns: displayedColumns"
|
||||
(click)="navigateToAccount(row)"
|
||||
class="table-row"
|
||||
></tr>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (!showData) {
|
||||
<div class="empty-state">
|
||||
<i class="fas fa-times-circle empty-icon"></i>
|
||||
<p class="empty-title">No terminated accounts</p>
|
||||
<p class="empty-text">Accounts marked for termination will appear here.</p>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
.status-badge--terminated {
|
||||
background: #fef2f2;
|
||||
color: #dc2626;
|
||||
border: 1px solid #fecaca;
|
||||
padding: 2px 10px;
|
||||
border-radius: 12px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* 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, inject } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import {
|
||||
MatTableDataSource,
|
||||
MatTable,
|
||||
MatColumnDef,
|
||||
MatHeaderCellDef,
|
||||
MatHeaderCell,
|
||||
MatCellDef,
|
||||
MatCell,
|
||||
MatHeaderRowDef,
|
||||
MatHeaderRow,
|
||||
MatRowDef,
|
||||
MatRow
|
||||
} from '@angular/material/table';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-terminated-account',
|
||||
templateUrl: './terminated-account.component.html',
|
||||
styleUrls: ['./terminated-account.component.scss'],
|
||||
imports: [
|
||||
...STANDALONE_SHARED_IMPORTS,
|
||||
FaIconComponent,
|
||||
MatTable,
|
||||
MatColumnDef,
|
||||
MatHeaderCellDef,
|
||||
MatHeaderCell,
|
||||
MatCellDef,
|
||||
MatCell,
|
||||
MatHeaderRowDef,
|
||||
MatHeaderRow,
|
||||
MatRowDef,
|
||||
MatRow,
|
||||
MatIcon
|
||||
]
|
||||
})
|
||||
export class TerminatedAccountComponent {
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
|
||||
dataSource: MatTableDataSource<any>;
|
||||
showData = false;
|
||||
|
||||
displayedColumns: string[] = [
|
||||
'accountNo',
|
||||
'clientName',
|
||||
'productName',
|
||||
'accountType',
|
||||
'officeName',
|
||||
'submittedOnDate',
|
||||
'status'
|
||||
];
|
||||
|
||||
constructor() {
|
||||
this.route.data.subscribe((data: { terminatedAccountsData: any }) => {
|
||||
const items = data.terminatedAccountsData?.pageItems || [];
|
||||
this.showData = items.length > 0;
|
||||
this.dataSource = new MatTableDataSource(items);
|
||||
});
|
||||
}
|
||||
|
||||
navigateToAccount(account: any): void {
|
||||
const clientId = account.clientId;
|
||||
const accountId = account.id;
|
||||
const depositTypeId = account.depositType?.id;
|
||||
if (account.accountType === 'Current') {
|
||||
this.router.navigate([`/clients/${clientId}/current-accounts/${accountId}`]);
|
||||
} else if (depositTypeId === 200) {
|
||||
this.router.navigate([`/clients/${clientId}/fixed-deposits-accounts/${accountId}`]);
|
||||
} else if (depositTypeId === 300) {
|
||||
this.router.navigate([`/clients/${clientId}/recurring-deposits-accounts/${accountId}`]);
|
||||
} else {
|
||||
this.router.navigate([`/clients/${clientId}/savings-accounts/${accountId}`]);
|
||||
}
|
||||
}
|
||||
|
||||
applyFilter(filterValue: string = '') {
|
||||
this.dataSource.filter = filterValue.trim().toLowerCase();
|
||||
}
|
||||
|
||||
formatDate(date: any): string {
|
||||
if (!date) return '';
|
||||
if (Array.isArray(date)) {
|
||||
return new Date(date[0], date[1] - 1, date[2]).toLocaleDateString('en-IN', {
|
||||
day: '2-digit',
|
||||
month: 'short',
|
||||
year: 'numeric'
|
||||
});
|
||||
}
|
||||
const d = new Date(date);
|
||||
return isNaN(d.getTime())
|
||||
? date
|
||||
: d.toLocaleDateString('en-IN', { day: '2-digit', month: 'short', year: 'numeric' });
|
||||
}
|
||||
}
|
||||
@@ -106,6 +106,18 @@
|
||||
<fa-icon icon="ban" class="ac-tab__ic"></fa-icon>
|
||||
<span>Reject Account</span>
|
||||
</a>
|
||||
<a
|
||||
mat-tab-link
|
||||
class="ac-tab"
|
||||
[routerLink]="['./terminated-account']"
|
||||
routerLinkActive
|
||||
#terminatedAccount="routerLinkActive"
|
||||
[active]="terminatedAccount.isActive"
|
||||
*mifosxHasPermission="'ALL_FUNCTIONS_READ'"
|
||||
>
|
||||
<fa-icon icon="times-circle" class="ac-tab__ic"></fa-icon>
|
||||
<span>Terminated Account</span>
|
||||
</a>
|
||||
<a
|
||||
mat-tab-link
|
||||
class="ac-tab"
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* 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 { Injectable, inject } from '@angular/core';
|
||||
import { Resolve } from '@angular/router';
|
||||
import { Observable, forkJoin, of } from 'rxjs';
|
||||
import { map, catchError } from 'rxjs/operators';
|
||||
import { TasksService } from '../tasks.service';
|
||||
|
||||
@Injectable()
|
||||
export class GetTerminatedAccounts implements Resolve<any> {
|
||||
private tasksService = inject(TasksService);
|
||||
|
||||
resolve(): Observable<any> {
|
||||
return forkJoin({
|
||||
savings: this.tasksService.getTerminatedSavingsAccounts().pipe(catchError(() => of({ pageItems: [] }))),
|
||||
current: this.tasksService.getTerminatedCurrentAccounts().pipe(catchError(() => of([]))),
|
||||
offices: this.tasksService.getAllOffices().pipe(catchError(() => of([])))
|
||||
}).pipe(
|
||||
map((results) => {
|
||||
const officeMap: Record<number, string> = {};
|
||||
(results.offices || []).forEach((o: any) => {
|
||||
officeMap[o.id] = o.name;
|
||||
});
|
||||
|
||||
const savingsItems = (results.savings?.pageItems || []).map((a: any) => ({
|
||||
...a,
|
||||
officeName: officeMap[a.officeId] || a.officeName || '',
|
||||
fieldOfficerName: a.fieldOfficerName || '',
|
||||
accountType: a.depositType?.value || 'Savings'
|
||||
}));
|
||||
|
||||
const currentItems = (Array.isArray(results.current) ? results.current : results.current?.pageItems || []).map(
|
||||
(a: any) => ({ ...a, accountType: 'Current' })
|
||||
);
|
||||
|
||||
return { pageItems: [
|
||||
...savingsItems,
|
||||
...currentItems
|
||||
] };
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import { LoanDisbursalComponent } from './checker-inbox-and-tasks-tabs/loan-disb
|
||||
import { RescheduleLoanComponent } from './checker-inbox-and-tasks-tabs/reschedule-loan/reschedule-loan.component';
|
||||
import { PendingAccountComponent } from './checker-inbox-and-tasks-tabs/pending-account/pending-account.component';
|
||||
import { RejectedAccountComponent } from './checker-inbox-and-tasks-tabs/rejected-account/rejected-account.component';
|
||||
import { TerminatedAccountComponent } from './checker-inbox-and-tasks-tabs/terminated-account/terminated-account.component';
|
||||
import { ViewCheckerInboxComponent } from './view-checker-inbox/view-checker-inbox.component';
|
||||
|
||||
/** Custom Resolvers */
|
||||
@@ -38,6 +39,7 @@ import { MakerCheckerTemplate } from './common-resolvers/makerCheckerTemplate.re
|
||||
import { GetCheckerInboxDetailResolver } from './common-resolvers/getCheckerInboxDetail.resolver';
|
||||
import { GetPendingAccounts } from './common-resolvers/getPendingAccounts.resolver';
|
||||
import { GetRejectedAccounts } from './common-resolvers/getRejectedAccounts.resolver';
|
||||
import { GetTerminatedAccounts } from './common-resolvers/getTerminatedAccounts.resolver';
|
||||
|
||||
/** Tasks Routes */
|
||||
const routes: Routes = [
|
||||
@@ -105,6 +107,14 @@ const routes: Routes = [
|
||||
rejectedAccountsData: GetRejectedAccounts
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'terminated-account',
|
||||
component: TerminatedAccountComponent,
|
||||
data: { title: 'Terminated Account' },
|
||||
resolve: {
|
||||
terminatedAccountsData: GetTerminatedAccounts
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'withdrawal-requests',
|
||||
component: WithdrawalRequestsComponent,
|
||||
@@ -175,7 +185,8 @@ const routes: Routes = [
|
||||
MakerCheckerTemplate,
|
||||
GetCheckerInboxDetailResolver,
|
||||
GetPendingAccounts,
|
||||
GetRejectedAccounts
|
||||
GetRejectedAccounts,
|
||||
GetTerminatedAccounts
|
||||
]
|
||||
})
|
||||
export class TasksRoutingModule {}
|
||||
|
||||
@@ -140,6 +140,16 @@ export class TasksService {
|
||||
return this.http.get('/currentaccounts', { params: httpParams });
|
||||
}
|
||||
|
||||
getTerminatedSavingsAccounts(): Observable<any> {
|
||||
const httpParams = new HttpParams().set('limit', '1000').set('status', 'terminated');
|
||||
return this.http.get('/savingsaccounts', { params: httpParams });
|
||||
}
|
||||
|
||||
getTerminatedCurrentAccounts(): Observable<any> {
|
||||
const httpParams = new HttpParams().set('limit', '1000').set('status', 'terminated');
|
||||
return this.http.get('/currentaccounts', { params: httpParams });
|
||||
}
|
||||
|
||||
/**
|
||||
* Approve a savings account
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user