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:
Aditya
2026-03-17 18:23:37 +05:30
co-authored by Claude Opus 4.6
parent 73aa69ee02
commit 0a32d7135e
210 changed files with 15048 additions and 155 deletions
@@ -0,0 +1,46 @@
<!--
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>
<form [formGroup]="activateCurrentAccountForm" (ngSubmit)="submit()">
<mat-card-content>
<div class="layout-column">
<mat-form-field class="flex-fill" (click)="activatedOnDatePicker.open()">
<mat-label>{{ 'labels.inputs.Activated On Date' | translate }}</mat-label>
<input
matInput
[min]="minDate"
[max]="maxDate"
[matDatepicker]="activatedOnDatePicker"
required
formControlName="activatedOnDate"
/>
<mat-datepicker-toggle matSuffix [for]="activatedOnDatePicker"></mat-datepicker-toggle>
<mat-datepicker #activatedOnDatePicker></mat-datepicker>
@if (activateCurrentAccountForm.controls.activatedOnDate.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Activated On Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
</div>
</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]="!activateCurrentAccountForm.valid">
{{ 'labels.buttons.Confirm' | translate }}
</button>
</mat-card-actions>
</form>
</mat-card>
</div>
@@ -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 {
max-width: 37rem;
}
@@ -0,0 +1,101 @@
/**
* 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, inject } from '@angular/core';
import { UntypedFormGroup, UntypedFormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { Dates } from 'app/core/utils/dates';
/** Custom Services */
import { CurrentAccountsService } from 'app/current-accounts/current-accounts.service';
import { SettingsService } from 'app/settings/settings.service';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
/**
* Activate Current Account Component
*/
@Component({
selector: 'mifosx-activate-current-account',
templateUrl: './activate-current-account.component.html',
styleUrls: ['./activate-current-account.component.scss'],
imports: [
...STANDALONE_SHARED_IMPORTS
]
})
export class ActivateCurrentAccountComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private currentAccountsService = inject(CurrentAccountsService);
private dateUtils = inject(Dates);
private route = inject(ActivatedRoute);
private router = inject(Router);
private settingsService = inject(SettingsService);
/** Minimum date allowed. */
minDate = new Date(2000, 0, 1);
/** Maximum date allowed. */
maxDate = new Date();
/** Activate Current Account form. */
activateCurrentAccountForm: UntypedFormGroup;
/** Current Account Id */
accountId: any;
/**
* @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.accountId = this.route.snapshot.params['currentAccountId'];
}
/**
* Creates the activate current account form.
*/
ngOnInit() {
this.maxDate = this.settingsService.businessDate;
this.createActivateCurrentAccountForm();
}
/**
* Creates the activate current account form.
*/
createActivateCurrentAccountForm() {
this.activateCurrentAccountForm = this.formBuilder.group({
activatedOnDate: [
'',
Validators.required
]
});
}
/**
* Submits the form and activates the current account,
* if successful redirects to the current account.
*/
submit() {
const activateCurrentAccountFormData = this.activateCurrentAccountForm.value;
const locale = this.settingsService.language.code;
const dateFormat = this.settingsService.dateFormat;
const prevActivatedOnDate: Date = this.activateCurrentAccountForm.value.activatedOnDate;
if (activateCurrentAccountFormData.activatedOnDate instanceof Date) {
activateCurrentAccountFormData.activatedOnDate = this.dateUtils.formatDate(prevActivatedOnDate, dateFormat);
}
const data = {
...activateCurrentAccountFormData,
dateFormat,
locale
};
this.currentAccountsService.executeCurrentAccountCommand(this.accountId, 'activate', data).subscribe(() => {
this.router.navigate(['../../transactions'], { relativeTo: this.route });
});
}
}
@@ -0,0 +1,126 @@
<!--
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>
<form [formGroup]="currentAccountChargeForm" (ngSubmit)="submit()">
<mat-card-content>
<div class="layout-column">
<mat-form-field>
<mat-label>{{ 'labels.inputs.Charge' | translate }}</mat-label>
<mat-select required formControlName="chargeId">
@for (currentAccountCharge of currentAccountChargeOptions; track currentAccountCharge) {
<mat-option [value]="currentAccountCharge.id">
{{ currentAccountCharge.name + ' (' + currentAccountCharge.currency.name + ')' }}
</mat-option>
}
</mat-select>
@if (currentAccountChargeForm.controls.chargeId.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Charge' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
@if (chargeDetails) {
<div class="layout-column">
<mat-form-field>
<mat-label>{{ 'labels.inputs.Amount' | translate }}</mat-label>
<input type="number" required matInput formControlName="amount" />
@if (currentAccountChargeForm.controls.amount.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Amount' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Charge Calculation' | translate }}</mat-label>
<mat-select formControlName="chargeCalculationType">
@for (chargeCalculation of chargeDetails.chargeCalculationTypeOptions; track chargeCalculation) {
<mat-option [value]="chargeCalculation.id">
{{ chargeCalculation.value }}
</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Charge time type' | translate }}</mat-label>
<mat-select formControlName="chargeTimeType">
@for (chargeTime of chargeDetails.chargeTimeTypeOptions; track chargeTime) {
<mat-option [value]="chargeTime.id">
{{ chargeTime.value }}
</mat-option>
}
</mat-select>
</mat-form-field>
@if (currentAccountChargeForm.contains('dueDate')) {
<mat-form-field (click)="dueDatePicker.open()">
<mat-label>{{ 'labels.inputs.Due for collection on' | translate }}</mat-label>
<input
matInput
[min]="minDate"
[max]="maxDate"
[matDatepicker]="dueDatePicker"
required
formControlName="dueDate"
/>
<mat-datepicker-toggle matSuffix [for]="dueDatePicker"></mat-datepicker-toggle>
<mat-datepicker #dueDatePicker></mat-datepicker>
@if (currentAccountChargeForm.controls.dueDate.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Due for collection on' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
}
@if (currentAccountChargeForm.contains('feeOnMonthDay')) {
<mat-form-field (click)="feeOnMonthDayPicker.open()">
<mat-label>{{ 'labels.inputs.Due On' | translate }}</mat-label>
<input
matInput
[min]="minDate"
[max]="maxDate"
[matDatepicker]="feeOnMonthDayPicker"
required
formControlName="feeOnMonthDay"
/>
<mat-datepicker-toggle matSuffix [for]="feeOnMonthDayPicker"></mat-datepicker-toggle>
<mat-datepicker #feeOnMonthDayPicker></mat-datepicker>
@if (currentAccountChargeForm.controls.feeOnMonthDay.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Due Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
}
@if (currentAccountChargeForm.contains('feeInterval')) {
<mat-form-field>
<mat-label>{{ 'labels.inputs.Repeats Every' | translate }}</mat-label>
<input matInput formControlName="feeInterval" />
</mat-form-field>
}
</div>
}
</div>
<mat-card-actions class="layout-row layout-xs-column layout-align-center gap-5px">
<button type="button" mat-raised-button [routerLink]="['../../transactions']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
<button mat-raised-button color="primary" [disabled]="!currentAccountChargeForm.valid">
{{ 'labels.buttons.Submit' | translate }}
</button>
</mat-card-actions>
</mat-card-content>
</form>
</mat-card>
</div>
@@ -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;
}
@@ -0,0 +1,174 @@
/**
* 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, inject } from '@angular/core';
import {
UntypedFormGroup,
UntypedFormBuilder,
Validators,
UntypedFormControl,
ReactiveFormsModule
} from '@angular/forms';
import { Router, ActivatedRoute, RouterLink } from '@angular/router';
/** Custom Services */
import { CurrentAccountsService } from '../../current-accounts.service';
import { SettingsService } from 'app/settings/settings.service';
import { Dates } from 'app/core/utils/dates';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
/**
* Add Current Account Charge component.
*/
@Component({
selector: 'mifosx-add-charge-current-account',
templateUrl: './add-charge-current-account.component.html',
styleUrls: ['./add-charge-current-account.component.scss'],
imports: [
...STANDALONE_SHARED_IMPORTS
]
})
export class AddChargeCurrentAccountComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private route = inject(ActivatedRoute);
private router = inject(Router);
private dateUtils = inject(Dates);
private currentAccountsService = inject(CurrentAccountsService);
private settingsService = inject(SettingsService);
/** Minimum Due Date allowed. */
minDate = new Date(2000, 0, 1);
/** Maximum Due Date allowed. */
maxDate = new Date();
/** Add Current Account Charge form. */
currentAccountChargeForm: UntypedFormGroup;
/** current account charge options. */
currentAccountChargeOptions: any;
/** current account Id of the current account. */
currentAccountId: string;
/** charge details */
chargeDetails: any;
/**
* Retrieves charge template data from `resolve`
* @param {FormBuilder} formBuilder Form Builder
* @param {ActivatedRoute} route Activated Route
* @param {Router} router Router
* @param {Dates} dateUtils Date Utils
* @param {CurrentAccountsService} currentAccountsService Current Accounts Service
* @param {SettingsService} settingsService Settings Service
*/
constructor() {
this.route.data.subscribe((data: { currentAccountActionData: any }) => {
this.currentAccountChargeOptions = data.currentAccountActionData.chargeOptions;
});
this.currentAccountId = this.route.snapshot.params['currentAccountId'];
}
/**
* Creates the Current Account Charge form.
*/
ngOnInit() {
this.maxDate = this.settingsService.businessDate;
this.createCurrentAccountChargeForm();
this.buildDependencies();
}
buildDependencies() {
this.currentAccountChargeForm.controls.chargeId.valueChanges.subscribe((chargeId) => {
this.currentAccountsService.getChargeTemplate(chargeId).subscribe((data: any) => {
this.chargeDetails = data;
const chargeTimeType = data.chargeTimeType.id;
if (
data.chargeTimeType.value === 'Withdrawal Fee' ||
data.chargeTimeType.value === 'Current Account No Activity Fee'
) {
this.chargeDetails.dueDateNotRequired = true;
}
if (data.chargeTimeType.value === 'Annual Fee' || data.chargeTimeType.value === 'Monthly Fee') {
this.chargeDetails.chargeTimeTypeAnnualOrMonth = true;
}
if (!this.chargeDetails.dueDateNotRequired && !this.chargeDetails.chargeTimeTypeAnnualOrMonth) {
this.currentAccountChargeForm.addControl('dueDate', new UntypedFormControl('', Validators.required));
} else {
this.currentAccountChargeForm.removeControl('dueDate');
}
if (!this.chargeDetails.dueDateNotRequired && this.chargeDetails.chargeTimeTypeAnnualOrMonth) {
this.currentAccountChargeForm.addControl('feeOnMonthDay', new UntypedFormControl('', Validators.required));
} else {
this.currentAccountChargeForm.removeControl('feeOnMonthDay');
}
if (chargeTimeType.value === 'Monthly Fee') {
this.currentAccountChargeForm.addControl(
'feeInterval',
new UntypedFormControl(data.feeInterval, Validators.required)
);
} else {
this.currentAccountChargeForm.removeControl('feeInterval');
}
this.currentAccountChargeForm.patchValue({
amount: data.amount,
chargeCalculationType: data.chargeCalculationType.id,
chargeTimeType: data.chargeTimeType.id
});
});
});
}
/**
* Creates the Current Account Charge form.
*/
createCurrentAccountChargeForm() {
this.currentAccountChargeForm = this.formBuilder.group({
chargeId: [
'',
Validators.required
],
amount: [
'',
Validators.required
],
chargeCalculationType: [{ value: '', disabled: true }],
chargeTimeType: [{ value: '', disabled: true }]
});
}
/**
* Submits current account charge.
*/
submit() {
const currentAccountCharge = this.currentAccountChargeForm.value;
currentAccountCharge.locale = this.settingsService.language.code;
if (!currentAccountCharge.feeInterval) {
currentAccountCharge.feeInterval = this.chargeDetails.feeInterval;
}
if (this.chargeDetails.dueDateNotRequired !== true) {
if (this.chargeDetails.chargeTimeTypeAnnualOrMonth) {
const monthDayFormat = 'MMMM-dd'; // TODO: Update once language and date settings are setup
currentAccountCharge.monthDayFormat = monthDayFormat;
if (currentAccountCharge.feeOnMonthDay) {
const prevDate = this.currentAccountChargeForm.value.feeOnMonthDay;
currentAccountCharge.feeOnMonthDay = this.dateUtils.formatDate(prevDate, monthDayFormat);
}
} else {
const dateFormat = this.settingsService.dateFormat;
currentAccountCharge.dateFormat = dateFormat;
if (currentAccountCharge.dueDate) {
const prevDate = this.currentAccountChargeForm.value.dueDate;
currentAccountCharge.dueDate = this.dateUtils.formatDate(prevDate, dateFormat);
}
}
}
this.currentAccountsService
.createCurrentAccountCharge(this.currentAccountId, 'charges', currentAccountCharge)
.subscribe(() => {
this.router.navigate(['../../transactions'], { relativeTo: this.route });
});
}
}
@@ -0,0 +1,57 @@
<!--
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>
<form [formGroup]="applyAnnualFeesForm" (ngSubmit)="submit()">
<mat-card-content>
<div class="layout-column">
<mat-form-field (click)="dueDatePicker.open()">
<mat-label>{{ 'labels.inputs.Annual Fees Transaction Date' | translate }}</mat-label>
<input
matInput
[min]="minDate"
[max]="maxDate"
[matDatepicker]="dueDatePicker"
required
formControlName="dueDate"
/>
<mat-datepicker-toggle matSuffix [for]="dueDatePicker"></mat-datepicker-toggle>
<mat-datepicker #dueDatePicker></mat-datepicker>
@if (applyAnnualFeesForm.controls.dueDate.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Due Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Amount' | translate }}</mat-label>
<input type="number" formControlName="amount" required matInput />
@if (applyAnnualFeesForm.controls.amount.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Amount' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
</div>
</mat-card-content>
<mat-card-actions class="layout-row align-center gap-5px responsive-column">
<button type="button" mat-raised-button [routerLink]="['../../']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
<button mat-raised-button color="primary" [disabled]="!applyAnnualFeesForm.valid">
{{ 'labels.buttons.Confirm' | translate }}
</button>
</mat-card-actions>
</form>
</mat-card>
</div>
@@ -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 {
max-width: 37rem;
}
@@ -0,0 +1,125 @@
/**
* 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, inject } from '@angular/core';
import { UntypedFormGroup, UntypedFormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { Dates } from 'app/core/utils/dates';
/** Custom Services */
import { CurrentAccountsService } from 'app/current-accounts/current-accounts.service';
import { SettingsService } from 'app/settings/settings.service';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
/**
* Apply Annual Fees Component
*/
@Component({
selector: 'mifosx-apply-annual-fees-current-account',
templateUrl: './apply-annual-fees-current-account.component.html',
styleUrls: ['./apply-annual-fees-current-account.component.scss'],
imports: [
...STANDALONE_SHARED_IMPORTS
]
})
export class ApplyAnnualFeesCurrentAccountComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private currentAccountsService = inject(CurrentAccountsService);
private dateUtils = inject(Dates);
private route = inject(ActivatedRoute);
private router = inject(Router);
private settingsService = inject(SettingsService);
/** Minimum date allowed. */
minDate = new Date(2000, 0, 1);
/** Maximum date allowed. */
maxDate = new Date();
/** Apply annual fees form. */
applyAnnualFeesForm: UntypedFormGroup;
/** Current Account Id */
accountId: any;
/** Annual Fees charge Id */
chargeId: any;
/** Current Account Data */
currentAccountData: any;
/**
* @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.accountId = this.route.snapshot.params['currentAccountId'];
this.route.data.subscribe((data: { currentAccountActionData: any }) => {
this.currentAccountData = data.currentAccountActionData;
});
}
/**
* Creates the apply annual fees form.
*/
ngOnInit() {
this.maxDate = this.settingsService.businessDate;
this.createApplyAnnualFeesForm();
this.applyCharge();
}
/**
* Creates the apply annual fees form.
*/
createApplyAnnualFeesForm() {
this.applyAnnualFeesForm = this.formBuilder.group({
dueDate: [
'',
Validators.required
],
amount: ['']
});
}
/**
* Retireves apply annual fees charge for ID and amount.
*/
applyCharge() {
const charges: any[] = this.currentAccountData.charges;
charges.forEach((charge: any) => {
if (charge.name === 'Annual fee - INR') {
this.chargeId = charge.id;
this.applyAnnualFeesForm.get('amount').patchValue(charge.amount);
}
});
}
/**
* Submits the form and applies the annual fees,
* if successful redirects to the current account.
*/
submit() {
const applyAnnualFeesFormData = this.applyAnnualFeesForm.value;
const locale = this.settingsService.language.code;
const dateFormat = this.settingsService.dateFormat;
const prevApprovedOnDate: Date = this.applyAnnualFeesForm.value.dueDate;
if (applyAnnualFeesFormData.dueDate instanceof Date) {
applyAnnualFeesFormData.dueDate = this.dateUtils.formatDate(prevApprovedOnDate, dateFormat);
}
const data = {
...applyAnnualFeesFormData,
dateFormat,
locale
};
this.currentAccountsService
.executeCurrentAccountChargesCommand(this.accountId, 'paycharge', data, this.chargeId)
.subscribe(() => {
this.router.navigate(['../../'], { relativeTo: this.route });
});
}
}
@@ -0,0 +1,51 @@
<!--
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>
<form [formGroup]="approveCurrentAccountForm" (ngSubmit)="submit()">
<mat-card-content>
<div class="layout-column">
<mat-form-field (click)="approvedOnDatePicker.open()">
<mat-label>{{ 'labels.inputs.Approved On Date' | translate }}</mat-label>
<input
matInput
[min]="minDate"
[max]="maxDate"
[matDatepicker]="approvedOnDatePicker"
required
formControlName="approvedOnDate"
/>
<mat-datepicker-toggle matSuffix [for]="approvedOnDatePicker"></mat-datepicker-toggle>
<mat-datepicker #approvedOnDatePicker></mat-datepicker>
@if (approveCurrentAccountForm.controls.approvedOnDate.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Approved On Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Note' | translate }}</mat-label>
<textarea matInput formControlName="note" cdkTextareaAutosize cdkAutosizeMinRows="2"></textarea>
</mat-form-field>
</div>
</mat-card-content>
<mat-card-actions class="layout-row align-center gap-5px responsive-column">
<button type="button" mat-raised-button [routerLink]="['../../']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
<button mat-raised-button color="primary" [disabled]="!approveCurrentAccountForm.valid">
{{ 'labels.buttons.Confirm' | translate }}
</button>
</mat-card-actions>
</form>
</mat-card>
</div>
@@ -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 {
max-width: 37rem;
}
@@ -0,0 +1,104 @@
/**
* 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, inject } from '@angular/core';
import { UntypedFormGroup, UntypedFormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { Dates } from 'app/core/utils/dates';
/** Custom Services */
import { CurrentAccountsService } from 'app/current-accounts/current-accounts.service';
import { SettingsService } from 'app/settings/settings.service';
import { CdkTextareaAutosize } from '@angular/cdk/text-field';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
/**
* Approve Current Account Component
*/
@Component({
selector: 'mifosx-approve-current-account',
templateUrl: './approve-current-account.component.html',
styleUrls: ['./approve-current-account.component.scss'],
imports: [
...STANDALONE_SHARED_IMPORTS,
CdkTextareaAutosize
]
})
export class ApproveCurrentAccountComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private currentAccountsService = inject(CurrentAccountsService);
private dateUtils = inject(Dates);
private route = inject(ActivatedRoute);
private router = inject(Router);
private settingsService = inject(SettingsService);
/** Minimum date allowed. */
minDate = new Date(2000, 0, 1);
/** Maximum date allowed. */
maxDate = new Date();
/** Approve Current Account form. */
approveCurrentAccountForm: UntypedFormGroup;
/** Current Account Id */
accountId: any;
/**
* @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.accountId = this.route.snapshot.params['currentAccountId'];
}
/**
* Creates the approve current account form.
*/
ngOnInit() {
this.maxDate = this.settingsService.businessDate;
this.createApproveCurrentAccountForm();
}
/**
* Creates the approve current account form.
*/
createApproveCurrentAccountForm() {
this.approveCurrentAccountForm = this.formBuilder.group({
approvedOnDate: [
'',
Validators.required
],
note: ['']
});
}
/**
* Submits the form and approves the current account,
* if successful redirects to the current account.
*/
submit() {
const approveCurrentAccountFormData = this.approveCurrentAccountForm.value;
const locale = this.settingsService.language.code;
const dateFormat = this.settingsService.dateFormat;
const prevApprovedOnDate: Date = this.approveCurrentAccountForm.value.approvedOnDate;
if (approveCurrentAccountFormData.approvedOnDate instanceof Date) {
approveCurrentAccountFormData.approvedOnDate = this.dateUtils.formatDate(prevApprovedOnDate, dateFormat);
}
const data = {
...approveCurrentAccountFormData,
dateFormat,
locale
};
this.currentAccountsService.executeCurrentAccountCommand(this.accountId, 'approve', data).subscribe(() => {
this.router.navigate(['../../transactions'], { relativeTo: this.route });
});
}
}
@@ -0,0 +1,121 @@
<!--
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>
<form [formGroup]="closeCurrentAccountForm" (ngSubmit)="submit()">
<mat-card-content>
<div class="layout-column">
<mat-form-field (click)="closedOnDatePicker.open()">
<mat-label>{{ 'labels.inputs.Closed On Date' | translate }}</mat-label>
<input
matInput
[min]="minDate"
[max]="maxDate"
[matDatepicker]="closedOnDatePicker"
required
formControlName="closedOnDate"
/>
<mat-datepicker-toggle matSuffix [for]="closedOnDatePicker"></mat-datepicker-toggle>
<mat-datepicker #closedOnDatePicker></mat-datepicker>
@if (closeCurrentAccountForm.controls.closedOnDate.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Closed On Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-checkbox class="m-b-25 m-t-15" formControlName="withdrawBalance">
{{ 'labels.inputs.Withdraw Balance' | translate }}
</mat-checkbox>
<mat-checkbox formControlName="postInterestValidationOnClosure">
{{ 'labels.inputs.Is Interest Posting required on closure date' | translate }}?
</mat-checkbox>
@if (closeCurrentAccountForm.controls['withdrawBalance'].value) {
<div class="layout-column">
@if (closeCurrentAccountForm.controls['amount']) {
<mat-form-field class="m-t-20">
<mat-label>{{ 'labels.inputs.Transaction Amount' | translate }}</mat-label>
<input type="number" required matInput formControlName="amount" />
</mat-form-field>
}
@if (closeCurrentAccountForm.controls['paymentTypeId']) {
<mat-form-field>
<mat-label>{{ 'labels.inputs.Payment Type' | translate }}</mat-label>
<mat-select formControlName="paymentTypeId">
@for (paymentType of paymentTypeOptions; track paymentType) {
<mat-option [value]="paymentType.id">
{{ paymentType.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
}
<div class="flex-fill">
<span class="expandcollapsebutton m-l-10 m-t-40 flex-75" (click)="addPaymentDetails()">
<mat-slide-toggle>
<div [className]="showPaymentDetails ? 'enabled' : 'disabled'">
<span class="m-l-10">{{ 'labels.inputs.Show Payment Details' | translate }}</span>
</div>
</mat-slide-toggle>
</span>
</div>
@if (closeCurrentAccountForm.controls['accountNumber']) {
<mat-form-field>
<mat-label>{{ 'labels.inputs.Account Number' | translate }}</mat-label>
<input type="number" formControlName="accountNumber" matInput />
</mat-form-field>
}
@if (closeCurrentAccountForm.controls['checkNumber']) {
<mat-form-field>
<mat-label>{{ 'labels.inputs.Cheque' | translate }}</mat-label>
<input type="number" formControlName="checkNumber" matInput />
</mat-form-field>
}
@if (closeCurrentAccountForm.controls['routingCode']) {
<mat-form-field>
<mat-label>{{ 'labels.inputs.Routing Code' | translate }}</mat-label>
<input formControlName="routingCode" matInput />
</mat-form-field>
}
@if (closeCurrentAccountForm.controls['receiptNumber']) {
<mat-form-field>
<mat-label>{{ 'labels.inputs.Receipt Number' | translate }}</mat-label>
<input formControlName="receiptNumber" matInput />
</mat-form-field>
}
@if (closeCurrentAccountForm.controls['bankNumber']) {
<mat-form-field>
<mat-label>{{ 'labels.inputs.Bank' | translate }}</mat-label>
<input formControlName="bankNumber" matInput />
</mat-form-field>
}
</div>
}
<mat-form-field>
<mat-label>{{ 'labels.inputs.Note' | translate }}</mat-label>
<textarea matInput formControlName="note" cdkTextareaAutosize cdkAutosizeMinRows="2"></textarea>
</mat-form-field>
</div>
</mat-card-content>
<mat-card-actions class="layout-row align-center gap-5px responsive-column">
<button type="button" mat-raised-button [routerLink]="['../../']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
<button mat-raised-button color="warn" [disabled]="!closeCurrentAccountForm.valid">
{{ 'labels.buttons.Confirm' | translate }}
</button>
</mat-card-actions>
</form>
</mat-card>
</div>
@@ -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 {
max-width: 37rem;
}
@@ -0,0 +1,165 @@
/**
* 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, inject } from '@angular/core';
import {
UntypedFormGroup,
UntypedFormBuilder,
Validators,
UntypedFormControl,
ReactiveFormsModule
} from '@angular/forms';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { Dates } from 'app/core/utils/dates';
/** Custom Services */
import { CurrentAccountsService } from 'app/current-accounts/current-accounts.service';
import { SettingsService } from 'app/settings/settings.service';
import { MatCheckbox } from '@angular/material/checkbox';
import { MatSlideToggle } from '@angular/material/slide-toggle';
import { CdkTextareaAutosize } from '@angular/cdk/text-field';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
/**
* Close Current Account Component
*/
@Component({
selector: 'mifosx-close-current-account',
templateUrl: './close-current-account.component.html',
styleUrls: ['./close-current-account.component.scss'],
imports: [
...STANDALONE_SHARED_IMPORTS,
MatCheckbox,
MatSlideToggle,
CdkTextareaAutosize
]
})
export class CloseCurrentAccountComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private currentAccountsService = inject(CurrentAccountsService);
private dateUtils = inject(Dates);
private route = inject(ActivatedRoute);
private router = inject(Router);
private settingsService = inject(SettingsService);
/** Minimum date allowed. */
minDate = new Date(2000, 0, 1);
/** Maximum date allowed. */
maxDate = new Date();
/** Close Current Account form. */
closeCurrentAccountForm: UntypedFormGroup;
/** Current Account Id */
accountId: any;
/** Flag to enable payment details fields. */
addPaymentDetailsFlag = false;
/** Payment Type Options */
paymentTypeOptions: any;
/** Transaction Amount */
transactionAmount: any;
/**
* @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.route.data.subscribe((data: { currentAccountActionData: any }) => {
this.paymentTypeOptions = data.currentAccountActionData[0].paymentTypeOptions;
this.transactionAmount = data.currentAccountActionData[1].summary.accountBalance;
});
this.accountId = this.route.snapshot.params['currentAccountId'];
}
/**
* Creates the close current account form.
*/
ngOnInit() {
this.maxDate = this.settingsService.businessDate;
this.createCloseCurrentAccountForm();
this.buildDependencies();
}
/**
* Creates the close current account form.
*/
createCloseCurrentAccountForm() {
this.closeCurrentAccountForm = this.formBuilder.group({
closedOnDate: [
'',
Validators.required
],
withdrawBalance: [false],
postInterestValidationOnClosure: [false],
note: ['']
});
}
/**
* Subscribe to value changes of withdraw balance checkbox.
*/
buildDependencies() {
this.closeCurrentAccountForm.get('withdrawBalance').valueChanges.subscribe((value: boolean) => {
if (value) {
this.closeCurrentAccountForm.addControl(
'amount',
new UntypedFormControl({ value: this.transactionAmount, disabled: true })
);
this.closeCurrentAccountForm.addControl('paymentTypeId', new UntypedFormControl(''));
} else {
this.closeCurrentAccountForm.removeControl('amount');
this.closeCurrentAccountForm.removeControl('paymentTypeId');
}
});
}
/**
* Method to add payment detail fields to the UI.
*/
addPaymentDetails() {
this.addPaymentDetailsFlag = !this.addPaymentDetailsFlag;
if (this.addPaymentDetailsFlag) {
this.closeCurrentAccountForm.addControl('accountNumber', new UntypedFormControl(''));
this.closeCurrentAccountForm.addControl('checkNumber', new UntypedFormControl(''));
this.closeCurrentAccountForm.addControl('routingCode', new UntypedFormControl(''));
this.closeCurrentAccountForm.addControl('receiptNumber', new UntypedFormControl(''));
this.closeCurrentAccountForm.addControl('bankNumber', new UntypedFormControl(''));
} else {
this.closeCurrentAccountForm.removeControl('accountNumber');
this.closeCurrentAccountForm.removeControl('checkNumber');
this.closeCurrentAccountForm.removeControl('routingCode');
this.closeCurrentAccountForm.removeControl('receiptNumber');
this.closeCurrentAccountForm.removeControl('bankNumber');
}
}
/**
* Submits the form and closes the current account,
* if successful redirects to the current account.
*/
submit() {
const closeCurrentAccountFormData = this.closeCurrentAccountForm.value;
const locale = this.settingsService.language.code;
const dateFormat = this.settingsService.dateFormat;
const prevClosedOnDate: Date = this.closeCurrentAccountForm.value.closedOnDate;
if (closeCurrentAccountFormData.closedOnDate instanceof Date) {
closeCurrentAccountFormData.closedOnDate = this.dateUtils.formatDate(prevClosedOnDate, dateFormat);
}
const data = {
...closeCurrentAccountFormData,
dateFormat,
locale
};
this.currentAccountsService.executeCurrentAccountCommand(this.accountId, 'close', data).subscribe(() => {
this.router.navigate(['../../transactions'], { relativeTo: this.route });
});
}
}
@@ -0,0 +1,47 @@
<!--
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/.
-->
@if (actions['Approve']) {
<mifosx-approve-current-account></mifosx-approve-current-account>
}
@if (actions['Reject']) {
<mifosx-reject-current-account></mifosx-reject-current-account>
}
@if (actions['Activate']) {
<mifosx-activate-current-account></mifosx-activate-current-account>
}
@if (actions['Undo Approval']) {
<mifosx-undo-approval-current-account></mifosx-undo-approval-current-account>
}
@if (actions['Post Interest As On']) {
<mifosx-post-interest-as-on-current-account></mifosx-post-interest-as-on-current-account>
}
@if (actions['Assign Staff']) {
<mifosx-current-account-assign-staff></mifosx-current-account-assign-staff>
}
@if (actions['Unassign Staff']) {
<mifosx-current-account-unassign-staff></mifosx-current-account-unassign-staff>
}
@if (actions['Withdrawn by Client']) {
<mifosx-withdraw-by-client-current-account></mifosx-withdraw-by-client-current-account>
}
@if (actions['Add Charge']) {
<mifosx-add-charge-current-account></mifosx-add-charge-current-account>
}
@if (actions['Withdrawal'] || actions['Deposit']) {
<mifosx-current-account-transactions></mifosx-current-account-transactions>
}
@if (actions['Close']) {
<mifosx-close-current-account></mifosx-close-current-account>
}
@if (actions['Apply Annual Fees']) {
<mifosx-apply-annual-fees-current-account></mifosx-apply-annual-fees-current-account>
}
@if (actions['Hold Amount'] || actions['Block Account'] || actions['Block Deposit'] || actions['Block Withdrawal']) {
<mifosx-manage-current-account [currency]="currency"> </mifosx-manage-current-account>
}
@@ -0,0 +1,7 @@
/**
* 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/.
*/
@@ -0,0 +1,116 @@
/**
* 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, inject } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Currency } from 'app/shared/models/general.model';
import { ApproveCurrentAccountComponent } from './approve-current-account/approve-current-account.component';
import { RejectCurrentAccountComponent } from './reject-current-account/reject-current-account.component';
import { ActivateCurrentAccountComponent } from './activate-current-account/activate-current-account.component';
import { UndoApprovalCurrentAccountComponent } from './undo-approval-current-account/undo-approval-current-account.component';
import { PostInterestAsOnCurrentAccountComponent } from './post-interest-as-on-current-account/post-interest-as-on-current-account.component';
import { CurrentAccountAssignStaffComponent } from './current-account-assign-staff/current-account-assign-staff.component';
import { CurrentAccountUnassignStaffComponent } from './current-account-unassign-staff/current-account-unassign-staff.component';
import { WithdrawByClientCurrentAccountComponent } from './withdraw-by-client-current-account/withdraw-by-client-current-account.component';
import { AddChargeCurrentAccountComponent } from './add-charge-current-account/add-charge-current-account.component';
import { CurrentAccountTransactionsComponent } from './current-account-transactions/current-account-transactions.component';
import { CloseCurrentAccountComponent } from './close-current-account/close-current-account.component';
import { ApplyAnnualFeesCurrentAccountComponent } from './apply-annual-fees-current-account/apply-annual-fees-current-account.component';
import { ManageCurrentAccountComponent } from './manage-current-account/manage-current-account.component';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
/**
* Current account actions component.
*/
@Component({
selector: 'mifosx-current-account-account-actions',
templateUrl: './current-account-actions.component.html',
styleUrls: ['./current-account-actions.component.scss'],
imports: [
...STANDALONE_SHARED_IMPORTS,
ApproveCurrentAccountComponent,
RejectCurrentAccountComponent,
ActivateCurrentAccountComponent,
UndoApprovalCurrentAccountComponent,
PostInterestAsOnCurrentAccountComponent,
CurrentAccountAssignStaffComponent,
CurrentAccountUnassignStaffComponent,
WithdrawByClientCurrentAccountComponent,
AddChargeCurrentAccountComponent,
CurrentAccountTransactionsComponent,
CloseCurrentAccountComponent,
ApplyAnnualFeesCurrentAccountComponent,
ManageCurrentAccountComponent
]
})
export class CurrentAccountActionsComponent {
private route = inject(ActivatedRoute);
/** Flag object to store possible actions and render appropriate UI to the user */
actions: {
Approve: boolean;
Reject: boolean;
Withdrawal: boolean;
Deposit: boolean;
Activate: boolean;
Close: boolean;
'Undo Approval': boolean;
'Post Interest As On': boolean;
'Assign Staff': boolean;
'Add Charge': boolean;
'Unassign Staff': boolean;
'Withdrawn by Client': boolean;
'Apply Annual Fees': boolean;
'Hold Amount': boolean;
'Block Account': boolean;
'Unblock Account': boolean;
'Block Deposit': boolean;
'Unblock Deposit': boolean;
'Block Withdrawal': boolean;
'Unblock Withdrawal': boolean;
} = {
Approve: false,
Reject: false,
Withdrawal: false,
Deposit: false,
Activate: false,
Close: false,
'Undo Approval': false,
'Post Interest As On': false,
'Assign Staff': false,
'Add Charge': false,
'Unassign Staff': false,
'Withdrawn by Client': false,
'Apply Annual Fees': false,
'Hold Amount': false,
'Block Account': false,
'Unblock Account': false,
'Block Deposit': false,
'Unblock Deposit': false,
'Block Withdrawal': false,
'Unblock Withdrawal': false
};
currency: Currency;
/**
* @param {ActivatedRoute} route Activated Route
*/
constructor() {
this.route.data.subscribe((data: { currentAccountActionData: any }) => {
if (data.currentAccountActionData) {
this.currency = data.currentAccountActionData.currency;
}
});
const name = this.route.snapshot.params['name'] as string;
if (name in this.actions) {
this.actions[name as keyof typeof this.actions] = true;
}
}
}
@@ -0,0 +1,63 @@
<!--
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>
<form [formGroup]="currentAccountAssignStaffForm" (ngSubmit)="submit()">
<mat-card-content>
<div class="layout-column">
<mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.To Current Account Officer' | translate }}</mat-label>
<mat-select formControlName="toCurrentAccountOfficerId">
@for (officer of fieldOfficerData; track officer) {
<mat-option [value]="officer.id">
{{ officer.displayName }}
</mat-option>
}
</mat-select>
@if (currentAccountAssignStaffForm.controls.toCurrentAccountOfficerId.hasError('required')) {
<mat-error>
{{ 'labels.inputs.To Current Account Officer' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field (click)="assignmentDatePicker.open()">
<mat-label>{{ 'labels.inputs.Assignment Date' | translate }}</mat-label>
<input
matInput
[min]="minDate"
[max]="maxDate"
[matDatepicker]="assignmentDatePicker"
required
formControlName="assignmentDate"
/>
<mat-datepicker-toggle matSuffix [for]="assignmentDatePicker"></mat-datepicker-toggle>
<mat-datepicker #assignmentDatePicker></mat-datepicker>
@if (currentAccountAssignStaffForm.controls.assignmentDate.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Assignment Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
</div>
</mat-card-content>
<mat-card-actions class="layout-row align-center gap-5px responsive-column">
<button type="button" mat-raised-button [routerLink]="['../../']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
<button mat-raised-button color="primary" [disabled]="!currentAccountAssignStaffForm.valid">
{{ 'labels.buttons.Confirm' | translate }}
</button>
</mat-card-actions>
</form>
</mat-card>
</div>
@@ -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 {
max-width: 37rem;
}
@@ -0,0 +1,116 @@
/**
* 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, inject } from '@angular/core';
import { UntypedFormGroup, UntypedFormBuilder, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { Dates } from 'app/core/utils/dates';
/** Custom Services */
import { CurrentAccountsService } from 'app/current-accounts/current-accounts.service';
import { SettingsService } from 'app/settings/settings.service';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
/**
* Current Account Assign Staff Component
*/
@Component({
selector: 'mifosx-current-account-account-assign-staff',
templateUrl: './current-account-assign-staff.component.html',
styleUrls: ['./current-account-assign-staff.component.scss'],
imports: [
...STANDALONE_SHARED_IMPORTS
]
})
export class CurrentAccountAssignStaffComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private currentAccountsService = inject(CurrentAccountsService);
private dateUtils = inject(Dates);
private route = inject(ActivatedRoute);
private router = inject(Router);
private settingsService = inject(SettingsService);
/** Minimum date allowed. */
minDate = new Date(2000, 0, 1);
/** Maximum date allowed. */
maxDate = new Date();
/** Current Account Assign Staff form. */
currentAccountAssignStaffForm: UntypedFormGroup;
/** Current Account Id */
accountId: any;
/** Field Officer Data */
fieldOfficerData: any;
/** Current Account Data */
currentAccountData: any;
/**
* @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.accountId = this.route.snapshot.params['currentAccountId'];
this.route.data.subscribe((data: { currentAccountActionData: any }) => {
this.currentAccountData = data.currentAccountActionData;
});
}
/**
* Creates the current account assign staff form.
*/
ngOnInit() {
this.maxDate = this.settingsService.businessDate;
this.fieldOfficerData = this.currentAccountData.fieldOfficerOptions;
this.createCurrentAccountAssignStaffForm();
}
/**
* Creates the current account assign staff form.
*/
createCurrentAccountAssignStaffForm() {
this.currentAccountAssignStaffForm = this.formBuilder.group({
toCurrentAccountOfficerId: [
'',
Validators.required
],
assignmentDate: [
'',
Validators.required
]
});
}
/**
* Submits the form and assigns staff the current account,
* if successful redirects to the current account.
*/
submit() {
const locale = this.settingsService.language.code;
const dateFormat = this.settingsService.dateFormat;
const formValue = this.currentAccountAssignStaffForm.value;
const assignmentDate =
formValue.assignmentDate instanceof Date
? this.dateUtils.formatDate(formValue.assignmentDate, dateFormat)
: formValue.assignmentDate;
const data = {
toCurrentAccountOfficerId: formValue.toCurrentAccountOfficerId,
assignmentDate,
dateFormat,
locale
};
this.currentAccountsService
.executeCurrentAccountCommand(this.accountId, 'assignCurrentAccountOfficer', data)
.subscribe(() => {
this.router.navigate(['../../transactions'], { relativeTo: this.route });
});
}
}
@@ -0,0 +1,132 @@
<!--
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.withdrawal) {
<mat-card-title class="form-heading">
{{ 'labels.heading.Withdraw Money From Current Account' | translate }}
</mat-card-title>
}
@if (transactionType.deposit) {
<mat-card-title class="form-heading">
{{ 'labels.heading.Deposit Money To Current Account' | translate }}
</mat-card-title>
}
<form [formGroup]="currentAccountTransactionForm" (ngSubmit)="submit()">
<mat-card-content>
<div class="layout-column">
<mat-form-field (click)="dueDatePicker.open()">
<mat-label>{{ 'labels.inputs.Transaction Date' | translate }}</mat-label>
<input
matInput
[min]="minDate"
[max]="maxDate"
[matDatepicker]="dueDatePicker"
formControlName="transactionDate"
required
/>
<mat-datepicker-toggle matSuffix [for]="dueDatePicker"></mat-datepicker-toggle>
<mat-datepicker #dueDatePicker></mat-datepicker>
@if (currentAccountTransactionForm.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>
<mifosx-input-amount
[currency]="currency"
[isRequired]="true"
[inputFormControl]="currentAccountTransactionForm.controls.transactionAmount"
[inputLabel]="'Transaction Amount'"
>
</mifosx-input-amount>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Payment Type' | translate }}</mat-label>
<mat-select required formControlName="paymentTypeId">
@for (paymentType of paymentTypeOptions; track paymentType) {
<mat-option [value]="paymentType.id">
{{ paymentType.name }}
</mat-option>
}
</mat-select>
@if (currentAccountTransactionForm.controls.paymentTypeId.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Payment Type' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<div class="flex-fill">
<span class="expandcollapsebutton m-l-10 m-t-40 flex-75" (click)="addPaymentDetails()">
<mat-slide-toggle>
<div [className]="addPaymentDetailsFlag ? 'enabled' : 'disabled'">
<span class="m-l-10">{{ 'labels.inputs.Show Payment Details' | translate }}</span>
</div>
</mat-slide-toggle>
</span>
</div>
@if (addPaymentDetailsFlag) {
<mat-form-field>
<mat-label>{{ 'labels.inputs.Account Number' | translate }}</mat-label>
<input type="number" formControlName="accountNumber" matInput />
</mat-form-field>
}
@if (addPaymentDetailsFlag) {
<mat-form-field>
<mat-label>{{ 'labels.inputs.Cheque' | translate }}</mat-label>
<input type="number" formControlName="checkNumber" matInput />
</mat-form-field>
}
@if (addPaymentDetailsFlag) {
<mat-form-field>
<mat-label>{{ 'labels.inputs.Routing Code' | translate }}</mat-label>
<input formControlName="routingCode" matInput />
</mat-form-field>
}
@if (addPaymentDetailsFlag) {
<mat-form-field>
<mat-label>{{ 'labels.inputs.Receipt Number' | translate }}</mat-label>
<input formControlName="receiptNumber" matInput />
</mat-form-field>
}
@if (addPaymentDetailsFlag) {
<mat-form-field>
<mat-label>{{ 'labels.inputs.Bank' | translate }}</mat-label>
<input formControlName="bankNumber" matInput />
</mat-form-field>
}
<mat-form-field>
<mat-label>{{ 'labels.inputs.Notes' | translate }}</mat-label>
<textarea formControlName="note" matInput cdkTextareaAutosize cdkAutosizeMinRows="2"></textarea>
</mat-form-field>
<mat-card-actions class="layout-row layout-xs-column layout-align-center gap-5px">
<button type="button" mat-raised-button [routerLink]="['../../transactions']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
<button mat-raised-button color="primary" [disabled]="!currentAccountTransactionForm.valid">
{{ 'labels.buttons.Submit' | translate }}
</button>
</mat-card-actions>
</div>
</mat-card-content>
</form>
</mat-card>
</div>
@@ -0,0 +1,29 @@
/**
* 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/.
*/
.expandcollapsebutton {
margin-top: -7px;
}
.container {
max-width: 37rem;
}
.right-input {
text-align: right;
}
.right-label {
padding-right: 25px !important;
}
.form-heading {
font-size: 1.25rem;
font-weight: 500;
margin-bottom: 0.5rem;
}
@@ -0,0 +1,169 @@
/**
* 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, inject } from '@angular/core';
import {
UntypedFormGroup,
UntypedFormBuilder,
Validators,
UntypedFormControl,
ReactiveFormsModule
} from '@angular/forms';
import { Router, ActivatedRoute, RouterLink } from '@angular/router';
/** Custom Services */
import { CurrentAccountsService } from '../../current-accounts.service';
import { SettingsService } from 'app/settings/settings.service';
import { Dates } from 'app/core/utils/dates';
import { Currency } from 'app/shared/models/general.model';
import { InputAmountComponent } from '../../../shared/input-amount/input-amount.component';
import { MatSlideToggle } from '@angular/material/slide-toggle';
import { CdkTextareaAutosize } from '@angular/cdk/text-field';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
/**
* Create current account transactions component.
*/
@Component({
selector: 'mifosx-current-account-transactions',
templateUrl: './current-account-transactions.component.html',
styleUrls: ['./current-account-transactions.component.scss'],
imports: [
...STANDALONE_SHARED_IMPORTS,
InputAmountComponent,
MatSlideToggle,
CdkTextareaAutosize
]
})
export class CurrentAccountTransactionsComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private route = inject(ActivatedRoute);
private router = inject(Router);
private dateUtils = inject(Dates);
private currentAccountsService = inject(CurrentAccountsService);
private settingsService = inject(SettingsService);
/** Minimum Due Date allowed. */
minDate = new Date(2000, 0, 1);
/** Maximum Due Date allowed. */
maxDate = new Date();
/** Current account transaction form. */
currentAccountTransactionForm: UntypedFormGroup;
/** current account transaction payment options. */
paymentTypeOptions: {
id: number;
name: string;
description: string;
isCashPayment: boolean;
position: number;
}[];
/** Flag to enable payment details fields. */
addPaymentDetailsFlag: Boolean = false;
/** transaction type flag to render required UI */
transactionType: { deposit: boolean; withdrawal: boolean } = { deposit: false, withdrawal: false };
/** transaction command for submit request */
transactionCommand: string;
/** current account's Id */
currentAccountId: string;
currency: Currency | null = null;
/**
* Retrieves the Current Account transaction template data from `resolve`.
* @param {FormBuilder} formBuilder Form Builder.
* @param {CurrentAccountsService} currentAccountsService Current Accounts Service.
* @param {ActivatedRoute} route Activated Route.
* @param {Dates} dateUtils Date Utils.
* @param {Router} router Router for navigation.
* @param {SettingsService} settingsService Settings Service
*/
constructor() {
this.route.data.subscribe((data: { currentAccountActionData: any }) => {
this.paymentTypeOptions = data.currentAccountActionData.paymentTypeOptions;
if (data.currentAccountActionData.currency) {
this.currency = data.currentAccountActionData.currency;
}
});
this.transactionCommand = this.route.snapshot.params['name'].toLowerCase();
this.transactionType[this.transactionCommand as 'deposit' | 'withdrawal'] = true;
this.currentAccountId = this.route.snapshot.params['currentAccountId'];
}
/**
* Creates the Current Account account transaction form when component loads.
*/
ngOnInit() {
this.maxDate = this.settingsService.businessDate;
this.createCurrentAccountTransactionForm();
}
/**
* Method to create the Current Account Transaction Form.
*/
createCurrentAccountTransactionForm() {
this.currentAccountTransactionForm = this.formBuilder.group({
transactionDate: [
this.settingsService.businessDate,
Validators.required
],
transactionAmount: [
0,
Validators.required
],
paymentTypeId: [
'',
Validators.required
],
note: ['']
});
}
/**
* Method to add payment detail fields to the UI.
*/
addPaymentDetails() {
this.addPaymentDetailsFlag = !this.addPaymentDetailsFlag;
if (this.addPaymentDetailsFlag) {
this.currentAccountTransactionForm.addControl('accountNumber', new UntypedFormControl(''));
this.currentAccountTransactionForm.addControl('checkNumber', new UntypedFormControl(''));
this.currentAccountTransactionForm.addControl('routingCode', new UntypedFormControl(''));
this.currentAccountTransactionForm.addControl('receiptNumber', new UntypedFormControl(''));
this.currentAccountTransactionForm.addControl('bankNumber', new UntypedFormControl(''));
} else {
this.currentAccountTransactionForm.removeControl('accountNumber');
this.currentAccountTransactionForm.removeControl('checkNumber');
this.currentAccountTransactionForm.removeControl('routingCode');
this.currentAccountTransactionForm.removeControl('receiptNumber');
this.currentAccountTransactionForm.removeControl('bankNumber');
}
}
/**
* Method to submit the transaction details.
*/
submit() {
const currentAccountTransactionFormData = this.currentAccountTransactionForm.value;
const locale = this.settingsService.language.code;
const dateFormat = this.settingsService.dateFormat;
const prevTransactionDate: Date = this.currentAccountTransactionForm.value.transactionDate;
if (currentAccountTransactionFormData.transactionDate instanceof Date) {
currentAccountTransactionFormData.transactionDate = this.dateUtils.formatDate(prevTransactionDate, dateFormat);
}
const data = {
...currentAccountTransactionFormData,
dateFormat,
locale
};
data['transactionAmount'] = data['transactionAmount'] * 1;
this.currentAccountsService
.executeCurrentAccountTransactionsCommand(this.currentAccountId, this.transactionCommand, data)
.subscribe((res) => {
this.router.navigate(['../../transactions'], { relativeTo: this.route });
});
}
}
@@ -0,0 +1,44 @@
<!--
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>
<form [formGroup]="currentAccountUnassignStaffForm" (ngSubmit)="submit()">
<mat-card-content>
<mat-form-field class="flex-fill" (click)="unassignedDatePicker.open()">
<mat-label>{{ 'labels.inputs.Unassignment Date' | translate }}</mat-label>
<input
matInput
[min]="minDate"
[max]="maxDate"
[matDatepicker]="unassignedDatePicker"
required
formControlName="unassignedDate"
/>
<mat-datepicker-toggle matSuffix [for]="unassignedDatePicker"></mat-datepicker-toggle>
<mat-datepicker #unassignedDatePicker></mat-datepicker>
@if (currentAccountUnassignStaffForm.controls.unassignedDate.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Unassignment Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
</mat-card-content>
<mat-card-actions class="layout-row align-center gap-5px responsive-column">
<button type="button" mat-raised-button [routerLink]="['../../']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
<button mat-raised-button color="primary" [disabled]="!currentAccountUnassignStaffForm.valid">
{{ 'labels.buttons.Confirm' | translate }}
</button>
</mat-card-actions>
</form>
</mat-card>
</div>
@@ -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 {
max-width: 37rem;
}
@@ -0,0 +1,103 @@
/**
* 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, Input, inject } from '@angular/core';
import { UntypedFormGroup, UntypedFormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { Dates } from 'app/core/utils/dates';
/** Custom Services */
import { CurrentAccountsService } from 'app/current-accounts/current-accounts.service';
import { SettingsService } from 'app/settings/settings.service';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
/**
* Current Account Unassign Staff Component
*/
@Component({
selector: 'mifosx-current-account-account-unassign-staff',
templateUrl: './current-account-unassign-staff.component.html',
styleUrls: ['./current-account-unassign-staff.component.scss'],
imports: [
...STANDALONE_SHARED_IMPORTS
]
})
export class CurrentAccountUnassignStaffComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private currentAccountsService = inject(CurrentAccountsService);
private dateUtils = inject(Dates);
private route = inject(ActivatedRoute);
private router = inject(Router);
private settingsService = inject(SettingsService);
/** Minimum date allowed. */
minDate = new Date(2000, 0, 1);
/** Maximum date allowed. */
maxDate = new Date();
/** Current Account Unassign Staff form. */
currentAccountUnassignStaffForm: UntypedFormGroup;
/** Current Account Id */
accountId: any;
/**
* @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.accountId = this.route.snapshot.params['currentAccountId'];
}
/**
* Creates the current account unassign staff form.
*/
ngOnInit() {
this.maxDate = this.settingsService.businessDate;
this.createCurrentAccountUnassignStaffForm();
}
/**
* Creates the current account unassign staff form.
*/
createCurrentAccountUnassignStaffForm() {
this.currentAccountUnassignStaffForm = this.formBuilder.group({
unassignedDate: [
'',
Validators.required
]
});
}
/**
* Submits the form and unassigns staff of the current account,
* if successful redirects to the current account.
*/
submit() {
const currentAccountUnassignStaffFormData = this.currentAccountUnassignStaffForm.value;
const locale = this.settingsService.language.code;
const dateFormat = this.settingsService.dateFormat;
const prevUnassignmentDate: Date = this.currentAccountUnassignStaffForm.value.unassignedDate;
if (currentAccountUnassignStaffFormData.unassignedDate instanceof Date) {
currentAccountUnassignStaffFormData.unassignedDate = this.dateUtils.formatDate(prevUnassignmentDate, dateFormat);
}
const data = {
...currentAccountUnassignStaffFormData,
dateFormat,
locale
};
this.currentAccountsService
.executeCurrentAccountCommand(this.accountId, 'unassignCurrentAccountOfficer', data)
.subscribe(() => {
this.router.navigate(['../../transactions'], { relativeTo: this.route });
});
}
}
@@ -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>
@@ -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;
}
@@ -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 });
});
}
}
}
@@ -0,0 +1,44 @@
<!--
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>
<form [formGroup]="postInterestCurrentAccountForm" (ngSubmit)="submit()">
<mat-card-content>
<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 (postInterestCurrentAccountForm.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>
</mat-card-content>
<mat-card-actions class="layout-row align-center gap-5px responsive-column">
<button type="button" mat-raised-button [routerLink]="['../../']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
<button mat-raised-button color="primary" [disabled]="!postInterestCurrentAccountForm.valid">
{{ 'labels.buttons.Confirm' | translate }}
</button>
</mat-card-actions>
</form>
</mat-card>
</div>
@@ -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 {
max-width: 37rem;
}
@@ -0,0 +1,104 @@
/**
* 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, inject } from '@angular/core';
import { UntypedFormGroup, UntypedFormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { Dates } from 'app/core/utils/dates';
/** Custom Services */
import { CurrentAccountsService } from 'app/current-accounts/current-accounts.service';
import { SettingsService } from 'app/settings/settings.service';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
/**
* Post Interest Current Account Component
*/
@Component({
selector: 'mifosx-post-interest-as-on-current-account',
templateUrl: './post-interest-as-on-current-account.component.html',
styleUrls: ['./post-interest-as-on-current-account.component.scss'],
imports: [
...STANDALONE_SHARED_IMPORTS
]
})
export class PostInterestAsOnCurrentAccountComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private currentAccountsService = inject(CurrentAccountsService);
private dateUtils = inject(Dates);
private route = inject(ActivatedRoute);
private router = inject(Router);
private settingsService = inject(SettingsService);
/** Minimum date allowed. */
minDate = new Date(2000, 0, 1);
/** Maximum date allowed. */
maxDate = new Date();
/** Post Interest Current Account form. */
postInterestCurrentAccountForm: UntypedFormGroup;
/** Current Account Id */
accountId: any;
/**
* @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.accountId = this.route.snapshot.params['currentAccountId'];
}
/**
* Creates the post interest current account form.
*/
ngOnInit() {
this.maxDate = this.settingsService.businessDate;
this.createPostInterestCurrentAccountForm();
}
/**
* Creates the post interest current account form.
*/
createPostInterestCurrentAccountForm() {
this.postInterestCurrentAccountForm = this.formBuilder.group({
transactionDate: [
'',
Validators.required
]
});
}
/**
* Submits the form and post interests of the current account,
* if successful redirects to the current account.
*/
submit() {
const postInterestCurrentAccountFormData = this.postInterestCurrentAccountForm.value;
const locale = this.settingsService.language.code;
const dateFormat = this.settingsService.dateFormat;
const prevTransactionDate: Date = this.postInterestCurrentAccountForm.value.transactionDate;
if (postInterestCurrentAccountFormData.transactionDate instanceof Date) {
postInterestCurrentAccountFormData.transactionDate = this.dateUtils.formatDate(prevTransactionDate, dateFormat);
}
const data = {
...postInterestCurrentAccountFormData,
IsPostInterestAsOn: true,
dateFormat,
locale
};
this.currentAccountsService
.executeCurrentAccountTransactionsCommand(this.accountId, 'postInterestAsOn', data)
.subscribe(() => {
this.router.navigate(['../../transactions'], { relativeTo: this.route });
});
}
}
@@ -0,0 +1,51 @@
<!--
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>
<form [formGroup]="rejectCurrentAccountForm" (ngSubmit)="submit()">
<mat-card-content>
<div class="layout-column">
<mat-form-field (click)="rejectedOnDatePicker.open()">
<mat-label>{{ 'labels.inputs.Rejected On Date' | translate }}</mat-label>
<input
matInput
[min]="minDate"
[max]="maxDate"
[matDatepicker]="rejectedOnDatePicker"
required
formControlName="rejectedOnDate"
/>
<mat-datepicker-toggle matSuffix [for]="rejectedOnDatePicker"></mat-datepicker-toggle>
<mat-datepicker #rejectedOnDatePicker></mat-datepicker>
@if (rejectCurrentAccountForm.controls.rejectedOnDate.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Rejected On Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Note' | translate }}</mat-label>
<textarea matInput formControlName="note" cdkTextareaAutosize cdkAutosizeMinRows="2"></textarea>
</mat-form-field>
</div>
</mat-card-content>
<mat-card-actions class="layout-row align-center gap-5px responsive-column">
<button type="button" mat-raised-button [routerLink]="['../../']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
<button mat-raised-button color="warn" [disabled]="!rejectCurrentAccountForm.valid">
{{ 'labels.buttons.Confirm' | translate }}
</button>
</mat-card-actions>
</form>
</mat-card>
</div>
@@ -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 {
max-width: 37rem;
}
@@ -0,0 +1,104 @@
/**
* 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, inject } from '@angular/core';
import { UntypedFormGroup, UntypedFormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { Dates } from 'app/core/utils/dates';
/** Custom Services */
import { CurrentAccountsService } from 'app/current-accounts/current-accounts.service';
import { SettingsService } from 'app/settings/settings.service';
import { CdkTextareaAutosize } from '@angular/cdk/text-field';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
/**
* Reject Current Account Component
*/
@Component({
selector: 'mifosx-reject-current-account',
templateUrl: './reject-current-account.component.html',
styleUrls: ['./reject-current-account.component.scss'],
imports: [
...STANDALONE_SHARED_IMPORTS,
CdkTextareaAutosize
]
})
export class RejectCurrentAccountComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private currentAccountsService = inject(CurrentAccountsService);
private dateUtils = inject(Dates);
private route = inject(ActivatedRoute);
private router = inject(Router);
private settingsService = inject(SettingsService);
/** Minimum date allowed. */
minDate = new Date(2000, 0, 1);
/** Maximum date allowed. */
maxDate = new Date();
/** Reject Current Account form. */
rejectCurrentAccountForm: UntypedFormGroup;
/** Current Account Id */
accountId: any;
/**
* @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.accountId = this.route.snapshot.params['currentAccountId'];
}
/**
* Creates the reject current account form.
*/
ngOnInit() {
this.maxDate = this.settingsService.businessDate;
this.createRejectCurrentAccountForm();
}
/**
* Creates the reject current account form.
*/
createRejectCurrentAccountForm() {
this.rejectCurrentAccountForm = this.formBuilder.group({
rejectedOnDate: [
'',
Validators.required
],
note: ['']
});
}
/**
* Submits the form and rejects the current account,
* if successful redirects to the current account.
*/
submit() {
const rejectCurrentAccountFormData = this.rejectCurrentAccountForm.value;
const locale = this.settingsService.language.code;
const dateFormat = this.settingsService.dateFormat;
const prevRejectedOnDate: Date = this.rejectCurrentAccountForm.value.rejectedOnDate;
if (rejectCurrentAccountFormData.rejectedOnDate instanceof Date) {
rejectCurrentAccountFormData.rejectedOnDate = this.dateUtils.formatDate(prevRejectedOnDate, dateFormat);
}
const data = {
...rejectCurrentAccountFormData,
dateFormat,
locale
};
this.currentAccountsService.executeCurrentAccountCommand(this.accountId, 'reject', data).subscribe(() => {
this.router.navigate(['../../'], { relativeTo: this.route });
});
}
}
@@ -0,0 +1,29 @@
<!--
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>
<form [formGroup]="undoApprovalCurrentAccountForm" (ngSubmit)="submit()">
<mat-card-content>
<mat-form-field class="flex-fill">
<mat-label>{{ 'labels.inputs.Note' | translate }}</mat-label>
<textarea matInput formControlName="note" cdkTextareaAutosize cdkAutosizeMinRows="2"></textarea>
</mat-form-field>
</mat-card-content>
<mat-card-actions class="layout-row align-center gap-5px responsive-column">
<button type="button" mat-raised-button [routerLink]="['../../']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
<button mat-raised-button color="warn" [disabled]="!undoApprovalCurrentAccountForm.valid">
{{ 'labels.buttons.Confirm' | translate }}
</button>
</mat-card-actions>
</form>
</mat-card>
</div>
@@ -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 {
max-width: 37rem;
}
@@ -0,0 +1,80 @@
/**
* 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, inject } from '@angular/core';
import { UntypedFormGroup, UntypedFormBuilder, ReactiveFormsModule } from '@angular/forms';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
/** Custom Services */
import { CurrentAccountsService } from 'app/current-accounts/current-accounts.service';
import { CdkTextareaAutosize } from '@angular/cdk/text-field';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
/**
* Undo Approval Current Account Component
*/
@Component({
selector: 'mifosx-undo-approval-current-account',
templateUrl: './undo-approval-current-account.component.html',
styleUrls: ['./undo-approval-current-account.component.scss'],
imports: [
...STANDALONE_SHARED_IMPORTS,
CdkTextareaAutosize
]
})
export class UndoApprovalCurrentAccountComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private currentAccountsService = inject(CurrentAccountsService);
private route = inject(ActivatedRoute);
private router = inject(Router);
/** Undo Approval Current Account form. */
undoApprovalCurrentAccountForm: UntypedFormGroup;
/** Current Account Id */
accountId: any;
/**
* @param {FormBuilder} formBuilder Form Builder
* @param {CurrentAccountsService} currentAccountsService Current Accounts Service
* @param {ActivatedRoute} route Activated Route
* @param {Router} router Router
*/
constructor() {
this.accountId = this.route.snapshot.params['currentAccountId'];
}
/**
* Creates the undo-approval current account form.
*/
ngOnInit() {
this.createUndoApprovalCurrentAccountForm();
}
/**
* Creates the undo-approval current account form.
*/
createUndoApprovalCurrentAccountForm() {
this.undoApprovalCurrentAccountForm = this.formBuilder.group({
note: ['']
});
}
/**
* Submits the form and undo the approval of share account,
* if successful redirects to the share account.
*/
submit() {
const data = {
...this.undoApprovalCurrentAccountForm.value
};
this.currentAccountsService.executeCurrentAccountCommand(this.accountId, 'undoapproval', data).subscribe(() => {
this.router.navigate(['../../transactions'], { relativeTo: this.route });
});
}
}
@@ -0,0 +1,51 @@
<!--
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>
<form [formGroup]="withdrawCurrentAccountForm" (ngSubmit)="submit()">
<mat-card-content>
<div class="layout-column">
<mat-form-field (click)="withdrawnOnDatePicker.open()">
<mat-label>{{ 'labels.inputs.Withdrawn On Date' | translate }}</mat-label>
<input
matInput
[min]="minDate"
[max]="maxDate"
[matDatepicker]="withdrawnOnDatePicker"
required
formControlName="withdrawnOnDate"
/>
<mat-datepicker-toggle matSuffix [for]="withdrawnOnDatePicker"></mat-datepicker-toggle>
<mat-datepicker #withdrawnOnDatePicker></mat-datepicker>
@if (withdrawCurrentAccountForm.controls.withdrawnOnDate.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Withdrawn On Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Note' | translate }}</mat-label>
<textarea matInput formControlName="note" cdkTextareaAutosize cdkAutosizeMinRows="2"></textarea>
</mat-form-field>
</div>
</mat-card-content>
<mat-card-actions class="layout-row align-center gap-5px responsive-column">
<button type="button" mat-raised-button [routerLink]="['../../']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
<button mat-raised-button color="primary" [disabled]="!withdrawCurrentAccountForm.valid">
{{ 'labels.buttons.Confirm' | translate }}
</button>
</mat-card-actions>
</form>
</mat-card>
</div>
@@ -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 {
max-width: 37rem;
}
@@ -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/.
*/
/** Angular Imports */
import { Component, OnInit, inject } from '@angular/core';
import { UntypedFormGroup, UntypedFormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { Dates } from 'app/core/utils/dates';
/** Custom Services */
import { CurrentAccountsService } from 'app/current-accounts/current-accounts.service';
import { SettingsService } from 'app/settings/settings.service';
import { CdkTextareaAutosize } from '@angular/cdk/text-field';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
/**
* Withdrawn by Client Current Account Component
*/
@Component({
selector: 'mifosx-withdraw-by-client-current-account',
templateUrl: './withdraw-by-client-current-account.component.html',
styleUrls: ['./withdraw-by-client-current-account.component.scss'],
imports: [
...STANDALONE_SHARED_IMPORTS,
CdkTextareaAutosize
]
})
export class WithdrawByClientCurrentAccountComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private currentAccountsService = inject(CurrentAccountsService);
private dateUtils = inject(Dates);
private route = inject(ActivatedRoute);
private router = inject(Router);
private settingsService = inject(SettingsService);
/** Minimum date allowed. */
minDate = new Date(2000, 0, 1);
/** Maximum date allowed. */
maxDate = new Date();
/** Withdraw Current Account form. */
withdrawCurrentAccountForm: UntypedFormGroup;
/** Current Account Id */
accountId: any;
/**
* @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.accountId = this.route.snapshot.params['currentAccountId'];
}
/**
* Creates the withdraw current account form.
*/
ngOnInit() {
this.maxDate = this.settingsService.businessDate;
this.createWithdrawCurrentAccountForm();
}
/**
* Creates the withdraw current account form.
*/
createWithdrawCurrentAccountForm() {
this.withdrawCurrentAccountForm = this.formBuilder.group({
withdrawnOnDate: [
'',
Validators.required
],
note: ['']
});
}
/**
* Submits the form and withdraws the current account by client,
* if successful redirects to the current account.
*/
submit() {
const withdrawCurrentAccountFormData = this.withdrawCurrentAccountForm.value;
const locale = this.settingsService.language.code;
const dateFormat = this.settingsService.dateFormat;
const prevWithdrawnOnDate: Date = this.withdrawCurrentAccountForm.value.withdrawnOnDate;
if (withdrawCurrentAccountFormData.withdrawnOnDate instanceof Date) {
withdrawCurrentAccountFormData.withdrawnOnDate = this.dateUtils.formatDate(prevWithdrawnOnDate, dateFormat);
}
const data = {
...withdrawCurrentAccountFormData,
dateFormat,
locale
};
this.currentAccountsService
.executeCurrentAccountCommand(this.accountId, 'withdrawnByApplicant', data)
.subscribe(() => {
this.router.navigate(['../../'], { relativeTo: this.route });
});
}
}