feat: add Current Account module, DIP verification, charges integration, and translations
- Current Account module with full CRUD, transactions, charges, hold/release, block/unblock - Current Products management under Products module - DIP mobile number verification with real API call to /lookup/check - Sanctions verification dialog - Charges support for Current Account (chargeAppliesTo=5) in create/edit - Fixed permissions from SAVINGSACCOUNT to CURRENTACCOUNT across all current account components - Added all missing translation keys for Current Account in en-US.json Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
73aa69ee02
commit
0a32d7135e
+81
@@ -0,0 +1,81 @@
|
||||
<!--
|
||||
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="container mat-elevation-z8">
|
||||
<mat-card>
|
||||
@if (transactionType.holdamount) {
|
||||
<mat-card-title>{{ 'labels.heading.Hold Amount' | translate }}</mat-card-title>
|
||||
}
|
||||
@if (transactionType.blockaccount) {
|
||||
<mat-card-title>{{ 'labels.heading.Block Current Account' | translate }}</mat-card-title>
|
||||
}
|
||||
|
||||
<form [formGroup]="manageCurrentAccountForm" (ngSubmit)="submit()">
|
||||
<mat-card-content class="layout-row">
|
||||
<mat-form-field class="flex-100">
|
||||
<mat-label>{{ 'labels.inputs.Reason' | translate }}</mat-label>
|
||||
<mat-select required formControlName="reasonForBlock">
|
||||
@for (codeValue of reasonOptions; track codeValue) {
|
||||
<mat-option [value]="codeValue.id">
|
||||
{{ codeValue.name }}
|
||||
</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
@if (manageCurrentAccountForm.controls.reasonForBlock.hasError('required')) {
|
||||
<mat-error>
|
||||
{{ 'labels.inputs.Reason' | translate }} {{ 'labels.commons.is' | translate }}
|
||||
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
||||
</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
|
||||
@if (transactionType.holdamount) {
|
||||
<mat-form-field class="flex-100" (click)="transactionDatePicker.open()">
|
||||
<mat-label>{{ 'labels.inputs.Transaction Date' | translate }}</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[min]="minDate"
|
||||
[max]="maxDate"
|
||||
[matDatepicker]="transactionDatePicker"
|
||||
required
|
||||
formControlName="transactionDate"
|
||||
/>
|
||||
<mat-datepicker-toggle matSuffix [for]="transactionDatePicker"></mat-datepicker-toggle>
|
||||
<mat-datepicker #transactionDatePicker></mat-datepicker>
|
||||
@if (manageCurrentAccountForm.controls.transactionDate.hasError('required')) {
|
||||
<mat-error>
|
||||
{{ 'labels.inputs.Transaction Date' | translate }} {{ 'labels.commons.is' | translate }}
|
||||
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
||||
</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
}
|
||||
|
||||
@if (transactionType.holdamount) {
|
||||
<mifosx-input-amount
|
||||
class="flex-100"
|
||||
[currency]="currency"
|
||||
[isRequired]="true"
|
||||
[inputFormControl]="manageCurrentAccountForm.controls.transactionAmount"
|
||||
[inputLabel]="'Transaction Amount'"
|
||||
>
|
||||
</mifosx-input-amount>
|
||||
}
|
||||
</mat-card-content>
|
||||
|
||||
<mat-card-actions class="layout-row align-center gap-5px responsive-column">
|
||||
<button type="button" mat-raised-button [routerLink]="['../../transactions']">
|
||||
{{ 'labels.buttons.Cancel' | translate }}
|
||||
</button>
|
||||
<button mat-raised-button color="primary" [disabled]="!manageCurrentAccountForm.valid">
|
||||
{{ 'labels.buttons.Confirm' | translate }}
|
||||
</button>
|
||||
</mat-card-actions>
|
||||
</form>
|
||||
</mat-card>
|
||||
</div>
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
.container {
|
||||
width: 37rem;
|
||||
}
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* 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, Input, OnInit, inject } from '@angular/core';
|
||||
import { UntypedFormBuilder, UntypedFormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
|
||||
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
||||
import { Dates } from 'app/core/utils/dates';
|
||||
import { CurrentAccountsService } from 'app/current-accounts/current-accounts.service';
|
||||
import { SettingsService } from 'app/settings/settings.service';
|
||||
import { Currency } from 'app/shared/models/general.model';
|
||||
import { SystemService } from 'app/system/system.service';
|
||||
import { MatCard, MatCardTitle, MatCardContent, MatCardActions } from '@angular/material/card';
|
||||
import { InputAmountComponent } from '../../../shared/input-amount/input-amount.component';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
|
||||
type TransactionCommandType = 'holdamount' | 'blockaccount' | 'blockdeposit' | 'blockwithdrawal';
|
||||
|
||||
interface TransactionType {
|
||||
holdamount: boolean;
|
||||
blockaccount: boolean;
|
||||
blockdeposit: boolean;
|
||||
blockwithdrawal: boolean;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-manage-current-account',
|
||||
templateUrl: './manage-current-account.component.html',
|
||||
styleUrls: ['./manage-current-account.component.scss'],
|
||||
imports: [
|
||||
...STANDALONE_SHARED_IMPORTS,
|
||||
MatCardTitle,
|
||||
InputAmountComponent
|
||||
]
|
||||
})
|
||||
export class ManageCurrentAccountComponent implements OnInit {
|
||||
private formBuilder = inject(UntypedFormBuilder);
|
||||
private currentAccountsService = inject(CurrentAccountsService);
|
||||
private dateUtils = inject(Dates);
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
private systemService = inject(SystemService);
|
||||
private settingsService = inject(SettingsService);
|
||||
|
||||
@Input() currency: Currency;
|
||||
/** Minimum date allowed. */
|
||||
minDate = new Date(2000, 0, 1);
|
||||
/** Maximum date allowed. */
|
||||
maxDate = new Date();
|
||||
/** Manage Current Account form. */
|
||||
manageCurrentAccountForm: UntypedFormGroup;
|
||||
/** Current Account Id */
|
||||
currentAccountId: string;
|
||||
transactionCommand: TransactionCommandType;
|
||||
|
||||
reasonOptions: any = [];
|
||||
|
||||
transactionType: TransactionType = {
|
||||
holdamount: false,
|
||||
blockaccount: false,
|
||||
blockdeposit: false,
|
||||
blockwithdrawal: false
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {FormBuilder} formBuilder Form Builder
|
||||
* @param {CurrentAccountsService} currentAccountsService Current Accounts Service
|
||||
* @param {Dates} dateUtils Date Utils
|
||||
* @param {ActivatedRoute} route Activated Route
|
||||
* @param {Router} router Router
|
||||
* @param {SettingsService} settingsService Setting service
|
||||
*/
|
||||
constructor() {
|
||||
this.transactionCommand = this.route.snapshot.params['name'].toLowerCase().replaceAll(' ', '');
|
||||
this.transactionType[this.transactionCommand] = true;
|
||||
this.currentAccountId = this.route.snapshot.params['currentAccountId'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the post interest current account form.
|
||||
*/
|
||||
ngOnInit() {
|
||||
this.maxDate = this.settingsService.businessDate;
|
||||
this.createManageCurrentAccountForm();
|
||||
if (
|
||||
this.transactionType.holdamount ||
|
||||
this.transactionType.blockaccount ||
|
||||
this.transactionType.blockdeposit ||
|
||||
this.transactionType.blockwithdrawal
|
||||
) {
|
||||
this.getCodeValues();
|
||||
}
|
||||
}
|
||||
|
||||
getCodeValues() {
|
||||
let codeName = 'CurrentAccountTransactionFreezeReasons'; // Default Hold Amount
|
||||
if (this.transactionType.blockaccount) {
|
||||
codeName = 'CurrentAccountBlockReasons';
|
||||
} else if (this.transactionType.blockdeposit) {
|
||||
codeName = 'CreditTransactionFreezeReasons';
|
||||
} else if (this.transactionType.blockwithdrawal) {
|
||||
codeName = 'DebitTransactionFreezeReasons';
|
||||
}
|
||||
|
||||
this.systemService.getCodes().subscribe((codes: any) => {
|
||||
codes.some((code: any) => {
|
||||
if (code.name === codeName) {
|
||||
this.systemService.getCodeValues(code.id).subscribe((codeValues: any) => {
|
||||
this.reasonOptions = codeValues;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the manage current account form.
|
||||
*/
|
||||
createManageCurrentAccountForm() {
|
||||
if (this.transactionType.holdamount) {
|
||||
this.manageCurrentAccountForm = this.formBuilder.group({
|
||||
reasonForBlock: [
|
||||
'',
|
||||
Validators.required
|
||||
],
|
||||
transactionDate: [
|
||||
'',
|
||||
Validators.required
|
||||
],
|
||||
transactionAmount: [
|
||||
0.0,
|
||||
Validators.required
|
||||
]
|
||||
});
|
||||
} else {
|
||||
this.manageCurrentAccountForm = this.formBuilder.group({
|
||||
reasonForBlock: [
|
||||
'',
|
||||
Validators.required
|
||||
]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
submit() {
|
||||
let command = '';
|
||||
let payload: { transactionAmount?: number; [key: string]: any } = {};
|
||||
|
||||
if (this.transactionType.holdamount) {
|
||||
const manageCurrentAccountFormData = this.manageCurrentAccountForm.value;
|
||||
const locale = this.settingsService.language.code;
|
||||
const dateFormat = this.settingsService.dateFormat;
|
||||
const prevTransactionDate: Date = this.manageCurrentAccountForm.value.transactionDate;
|
||||
if (manageCurrentAccountFormData.transactionDate instanceof Date) {
|
||||
manageCurrentAccountFormData.transactionDate = this.dateUtils.formatDate(prevTransactionDate, dateFormat);
|
||||
}
|
||||
payload = {
|
||||
...manageCurrentAccountFormData,
|
||||
dateFormat,
|
||||
locale
|
||||
};
|
||||
command = 'holdAmount';
|
||||
payload['transactionAmount'] = payload['transactionAmount'] * 1;
|
||||
|
||||
this.currentAccountsService
|
||||
.executeCurrentAccountTransactionsCommand(this.currentAccountId, command, payload)
|
||||
.subscribe((response: any) => {
|
||||
this.router.navigate(['../../transactions'], { relativeTo: this.route });
|
||||
});
|
||||
} else {
|
||||
payload = {
|
||||
...this.manageCurrentAccountForm.value
|
||||
};
|
||||
command = 'block';
|
||||
if (this.transactionType.blockdeposit) {
|
||||
command = 'blockCredit';
|
||||
} else if (this.transactionType.blockwithdrawal) {
|
||||
command = 'blockDebit';
|
||||
}
|
||||
|
||||
this.currentAccountsService
|
||||
.executeCurrentAccountCommand(this.currentAccountId, command, payload)
|
||||
.subscribe((response: any) => {
|
||||
this.router.navigate(['../../transactions'], { relativeTo: this.route });
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user