WEB-677: Improve Transfer Funds UX with vertical stepper (#3107)

- Refactored Transfer Funds page into a 3-step vertical stepper:
  Step 1: Beneficiary Selection
  Step 2: Transfer Details
  Step 3: Transfer Status (success/failure)
- Split single form into beneficiaryForm and transferDetailsForm
- Added MatStepper with custom icons and linear progression
- Added transfer status display with success/failure states
- Added missing i18n translation keys across all 13 locale files
- Fixed MatHint import for NG1010 compilation error
This commit is contained in:
Anvay
2026-02-08 13:12:52 -06:00
committed by GitHub
parent f25f82a004
commit 77e95c6146
16 changed files with 754 additions and 490 deletions
@@ -7,384 +7,471 @@
--> -->
<div class="container"> <div class="container">
@if (isLoading) { <mat-stepper orientation="vertical" [linear]="true" class="mat-elevation-z8" labelPosition="bottom" #transferStepper>
<div class="loader-wrapper"> <!-- Custom Step Icons -->
<div class="bottom triangle"></div> <ng-template matStepperIcon="number">
<div class="top triangle"></div> <fa-icon icon="pencil-alt" size="sm"></fa-icon>
<div class="left triangle"></div> </ng-template>
<div class="right triangle"></div> <ng-template matStepperIcon="edit">
</div> <fa-icon icon="pencil-alt" size="sm"></fa-icon>
} </ng-template>
<ng-template matStepperIcon="done">
<fa-icon icon="check" size="sm"></fa-icon>
</ng-template>
<ng-template matStepperIcon="error">
<fa-icon icon="exclamation-triangle" size="lg"></fa-icon>
</ng-template>
@if (!isLoading) { <!-- ==================== STEP 1: Beneficiary Selection ==================== -->
<mat-card class="transfer-card"> <mat-step [stepControl]="beneficiaryForm" [editable]="!transferComplete">
<mat-card-content> <ng-template matStepLabel>{{ 'labels.heading.Beneficiary Selection' | translate }}</ng-template>
<!-- Source Account Details Section -->
<div class="section-container"> <!-- Source Account Details (Read-Only) -->
<h3 class="section-title transfer-heading">{{ 'labels.heading.Transferring From Details' | translate }}</h3> <div class="section-container">
<mat-divider></mat-divider> <h3 class="section-title transfer-heading">{{ 'labels.heading.Transferring From Details' | translate }}</h3>
<div class="info-grid"> <mat-divider></mat-divider>
<div class="info-row"> <div class="info-grid">
<div class="info-label">{{ 'labels.inputs.Applicant' | translate }}</div> <div class="info-row">
<div class="info-value">{{ accountTransferTemplateData.fromClient.displayName }}</div> <div class="info-label">{{ 'labels.inputs.Applicant' | translate }}</div>
</div> <div class="info-value">{{ accountTransferTemplateData.fromClient.displayName }}</div>
<div class="info-row"> </div>
<div class="info-label">{{ 'labels.inputs.Office' | translate }}</div> <div class="info-row">
<div class="info-value">{{ accountTransferTemplateData.fromOffice.name }}</div> <div class="info-label">{{ 'labels.inputs.Office' | translate }}</div>
</div> <div class="info-value">{{ accountTransferTemplateData.fromOffice.name }}</div>
<div class="info-row"> </div>
<div class="info-label">{{ 'labels.inputs.From Account' | translate }}</div> <div class="info-row">
<div class="info-value"> <div class="info-label">{{ 'labels.inputs.From Account' | translate }}</div>
{{ accountTransferTemplateData.fromAccount.productName }}&nbsp;-&nbsp;#{{ <div class="info-value">
accountTransferTemplateData.fromAccount.accountNo {{ accountTransferTemplateData.fromAccount.productName }}&nbsp;-&nbsp;#{{
}} accountTransferTemplateData.fromAccount.accountNo
</div> }}
</div>
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.From Account Type' | translate }}</div>
<div class="info-value">{{ accountTransferTemplateData.fromAccountType.value }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.Currency' | translate }}</div>
<div class="info-value">{{ accountTransferTemplateData.currency.name }}</div>
</div> </div>
</div> </div>
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.From Account Type' | translate }}</div>
<div class="info-value">{{ accountTransferTemplateData.fromAccountType.value }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.Currency' | translate }}</div>
<div class="info-value">{{ accountTransferTemplateData.currency.name }}</div>
</div>
</div> </div>
<!-- Interbank Section --> </div>
@if (interbank) {
<div class="section-container"> <mat-divider></mat-divider>
<div class="interbank-section">
<h3 class="section-title transfer-heading">{{ 'labels.heading.Transferred To' | translate }}</h3> <!-- Beneficiary Form -->
<mat-form-field class="full-width"> @if (interbank) {
<!-- Interbank: Phone Number Search -->
<div class="section-container">
<h3 class="section-title transfer-heading">{{ 'labels.heading.Transferred To' | translate }}</h3>
<form [formGroup]="beneficiaryForm" class="transfer-form">
<div class="form-grid">
<mat-form-field class="form-field">
<mat-label>{{ 'labels.inputs.Phone Number' | translate }}</mat-label> <mat-label>{{ 'labels.inputs.Phone Number' | translate }}</mat-label>
<input <input
matInput matInput
[readonly]="interbankTransferForm" [readonly]="interbankTransferForm"
type="tel" type="tel"
#input formControlName="phoneNumber"
[(ngModel)]="phoneAccount"
maxlength="10" maxlength="10"
required required
placeholder="{{ 'labels.text.EnterPhoneNumber' | translate }}" placeholder="{{ 'labels.text.EnterPhoneNumber' | translate }}"
title="Phone number" title="Phone number"
/> />
<mat-hint align="end">{{ phoneAccount.length || 0 }}/10</mat-hint> <mat-hint align="end">{{ beneficiaryForm.get('phoneNumber')?.value?.length || 0 }}/10</mat-hint>
</mat-form-field> </mat-form-field>
</div> </div>
<!--interbank -->
@if (!interbankTransferForm) { @if (!interbankTransferForm) {
<mat-card-actions class="action-buttons"> <div class="action-buttons step-actions">
<ng-container *mifosxHasPermission="'CREATE_ACCOUNTTRANSFER'"> <ng-container *mifosxHasPermission="'CREATE_ACCOUNTTRANSFER'">
<button <button
mat-raised-button mat-raised-button
color="primary" color="primary"
[disabled]="phoneAccount.length !== 10" [disabled]="beneficiaryForm.get('phoneNumber')?.value?.length !== 10"
(click)="searchAccountByNumber()" (click)="searchAccountByNumber()"
id="search-button"
class="primary-button" class="primary-button"
> >
{{ 'labels.buttons.Search' | translate }} {{ 'labels.buttons.Search' | translate }}
</button> </button>
</ng-container> </ng-container>
</mat-card-actions> </div>
}
<!-- Interbank Beneficiary Preview (Read-Only) -->
@if (interbankTransferForm) {
<div class="info-grid beneficiary-preview">
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.Bank' | translate }}</div>
<div class="info-value">{{ beneficiaryForm.get('toBank')?.value }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.Client' | translate }}</div>
<div class="info-value">{{ beneficiaryForm.get('toClientId')?.value }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.Account Type' | translate }}</div>
<div class="info-value">{{ beneficiaryForm.get('toAccountType')?.value }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.Account' | translate }}</div>
<div class="info-value">{{ beneficiaryForm.get('toAccountId')?.value }}</div>
</div>
</div>
}
</form>
</div>
} @else {
<!-- Normal Transfer: Office/Client/Account Selection -->
<form [formGroup]="beneficiaryForm" class="transfer-form">
<h3 class="section-title transfer-heading">{{ 'labels.heading.Transferred To' | translate }}</h3>
<div class="form-grid">
<mat-form-field class="form-field">
<mat-label>{{ 'labels.inputs.Office' | translate }}</mat-label>
<mat-select required formControlName="toOfficeId" (selectionChange)="changeEvent()">
@for (toOfficeType of toOfficeTypeData; track toOfficeType) {
<mat-option [value]="toOfficeType.id">
{{ toOfficeType.name }}
</mat-option>
}
</mat-select>
@if (beneficiaryForm.controls['toOfficeId'].hasError('required')) {
<mat-error>
{{ 'labels.inputs.Office' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field class="form-field">
<mat-label>{{ 'labels.inputs.Client' | translate }}</mat-label>
<input
matInput
formControlName="toClientId"
[matAutocomplete]="clientsAutocomplete"
placeholder="{{ 'labels.text.SelectOrTypeClientName' | translate }}"
title="Client name"
/>
@if (beneficiaryForm.controls['toClientId'].hasError('required')) {
<mat-error>
{{ 'labels.inputs.Client' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-autocomplete
autoActiveFirstOption
#clientsAutocomplete="matAutocomplete"
[displayWith]="displayClient"
>
@for (client of clientsData; track client) {
<mat-option [value]="client"> {{ client.id }} - {{ client.displayName }} </mat-option>
}
</mat-autocomplete>
<mat-form-field class="form-field">
<mat-label>{{ 'labels.inputs.Account Type' | translate }}</mat-label>
<mat-select required formControlName="toAccountType" (selectionChange)="changeEvent()">
@for (toAccountType of toAccountTypeData; track toAccountType) {
<mat-option [value]="toAccountType.id">
{{ toAccountType.value }}
</mat-option>
}
</mat-select>
@if (beneficiaryForm.controls['toAccountType'].hasError('required')) {
<mat-error>
{{ 'labels.inputs.Account Type' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field class="form-field">
<mat-label>{{ 'labels.inputs.Account' | translate }}</mat-label>
<mat-select required formControlName="toAccountId" (selectionChange)="changeEvent()">
@for (toAccount of toAccountData; track toAccount) {
<mat-option [value]="toAccount.id">
{{ toAccount.productName }} - {{ toAccount.accountNo }}
</mat-option>
}
</mat-select>
@if (beneficiaryForm.controls['toAccountId'].hasError('required')) {
<mat-error>
{{ 'labels.inputs.Account' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
</div>
</form>
}
<!-- Step 1 Navigation -->
<div class="layout-row align-center gap-2percent margin-t responsive-column">
<button mat-raised-button matStepperPrevious disabled>
<fa-icon icon="arrow-left" class="m-r-10"></fa-icon>
{{ 'labels.buttons.Previous' | translate }}
</button>
<button
mat-raised-button
matStepperNext
[disabled]="interbank ? !interbankTransferForm : !beneficiaryForm.valid"
>
{{ 'labels.buttons.Next' | translate }}
<fa-icon icon="arrow-right" class="m-l-10"></fa-icon>
</button>
<button mat-raised-button [routerLink]="['../..']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
</div>
</mat-step>
<!-- ==================== STEP 2: Transfer Details ==================== -->
<mat-step [stepControl]="transferDetailsForm" [editable]="!transferComplete">
<ng-template matStepLabel>{{ 'labels.heading.Transfer Details' | translate }}</ng-template>
@if (isLoading) {
<div class="loader-wrapper">
<div class="bottom triangle"></div>
<div class="top triangle"></div>
<div class="left triangle"></div>
<div class="right triangle"></div>
</div>
}
@if (!isLoading) {
<!-- Beneficiary Summary (Read-Only) -->
<div class="section-container beneficiary-summary">
<h3 class="section-title transfer-heading">{{ 'labels.heading.Beneficiary' | translate }}</h3>
<div class="info-grid">
@if (interbank && interbankTransferForm) {
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.Bank' | translate }}</div>
<div class="info-value">{{ beneficiaryForm.get('toBank')?.value }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.Client' | translate }}</div>
<div class="info-value">{{ beneficiaryForm.get('toClientId')?.value }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.Account' | translate }}</div>
<div class="info-value">{{ beneficiaryForm.get('toAccountId')?.value }}</div>
</div>
} @else {
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.Office' | translate }}</div>
<div class="info-value">{{ getSelectedOfficeName() }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.Client' | translate }}</div>
<div class="info-value">{{ getSelectedClientName() }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.Account Type' | translate }}</div>
<div class="info-value">{{ getSelectedAccountTypeName() }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.Account' | translate }}</div>
<div class="info-value">{{ getSelectedAccountName() }}</div>
</div>
} }
</div> </div>
} </div>
@if (!interbank) {
<mat-divider></mat-divider> <mat-divider></mat-divider>
}
<!-- Transfer Form Section (Normal) --> <!-- Transfer Details Form -->
@if (!interbank && makeAccountTransferForm) { <form [formGroup]="transferDetailsForm" class="transfer-form">
<form [formGroup]="makeAccountTransferForm" class="transfer-form"> <h3 class="section-title transfer-heading">{{ 'labels.heading.Transfer Details' | translate }}</h3>
<h3 class="section-title transfer-heading">{{ 'labels.heading.Transfer Details' | translate }}</h3> <div class="form-grid">
<div class="form-grid"> <mat-form-field class="form-field" (click)="transferDatePicker.open()">
<mat-form-field class="form-field" (click)="transferDatePicker.open()"> <mat-label>{{ 'labels.inputs.Transaction Date' | translate }}</mat-label>
<mat-label>{{ 'labels.inputs.Transaction Date' | translate }}</mat-label> <input
<input matInput
matInput [min]="minDate"
[min]="minDate" [max]="maxDate"
[max]="maxDate" [matDatepicker]="transferDatePicker"
[matDatepicker]="transferDatePicker" required
required formControlName="transferDate"
formControlName="transferDate" placeholder="{{ 'labels.text.SelectDate' | translate }}"
placeholder="{{ 'labels.text.SelectDate' | translate }}" title="Transaction Date"
title="Transaction Date" />
/> <mat-datepicker-toggle matSuffix [for]="transferDatePicker"></mat-datepicker-toggle>
<mat-datepicker-toggle matSuffix [for]="transferDatePicker"></mat-datepicker-toggle> <mat-datepicker #transferDatePicker></mat-datepicker>
<mat-datepicker #transferDatePicker></mat-datepicker> @if (transferDetailsForm.controls['transferDate'].hasError('required')) {
@if (makeAccountTransferForm.controls.transferDate.hasError('required')) { <mat-error>
<mat-error> {{ 'labels.inputs.Transaction Date' | translate }} {{ 'labels.commons.is' | translate }}
{{ 'labels.inputs.Transaction Date' | translate }} {{ 'labels.commons.is' | translate }} <strong>{{ 'labels.commons.required' | translate }}</strong>
<strong>{{ 'labels.commons.required' | translate }}</strong> </mat-error>
</mat-error> }
} </mat-form-field>
</mat-form-field> <mat-form-field class="form-field">
<mat-form-field class="form-field"> <mat-label>{{ 'labels.inputs.Amount' | translate }}</mat-label>
<mat-label>{{ 'labels.inputs.Office' | translate }}</mat-label> <input
<mat-select required formControlName="toOfficeId" (selectionChange)="changeEvent()"> type="number"
@for (toOfficeType of toOfficeTypeData; track toOfficeType) { matInput
<mat-option [value]="toOfficeType.id"> required
{{ toOfficeType.name }} formControlName="transferAmount"
</mat-option> placeholder="{{ 'labels.text.EnterAmount' | translate }}"
} title="Transfer amount"
</mat-select> min="0.01"
@if (makeAccountTransferForm.controls.toOfficeId.hasError('required')) { step="0.01"
<mat-error> />
{{ 'labels.inputs.Office' | translate }} {{ 'labels.commons.is' | translate }} @if (transferDetailsForm.controls['transferAmount'].hasError('required')) {
<strong>{{ 'labels.commons.required' | translate }}</strong> <mat-error>
</mat-error> {{ 'labels.inputs.Amount' | translate }} {{ 'labels.commons.is' | translate }}
} <strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-form-field> </mat-error>
<mat-form-field class="form-field"> }
<mat-label>{{ 'labels.inputs.Client' | translate }}</mat-label> @if (transferDetailsForm.get('transferAmount')?.hasError('amountExceedsBalance')) {
<input <mat-error>
matInput <fa-icon icon="exclamation-triangle" size="md"></fa-icon>
formControlName="toClientId" {{ 'errors.validation.msg.savingsproduct.insufficient.balance' | translate: { balance } }}
[matAutocomplete]="clientsAutocomplete" </mat-error>
placeholder="{{ 'labels.text.SelectOrTypeClientName' | translate }}" }
title="Client name" </mat-form-field>
/> <mat-form-field class="form-field description-field">
@if (makeAccountTransferForm.controls.toClientId.hasError('required')) { <mat-label>{{ 'labels.inputs.Description' | translate }}</mat-label>
<mat-error> <textarea
{{ 'labels.inputs.Client' | translate }} {{ 'labels.commons.is' | translate }} matInput
<strong>{{ 'labels.commons.required' | translate }}</strong> formControlName="transferDescription"
</mat-error> cdkTextareaAutosize
} cdkAutosizeMinRows="2"
</mat-form-field> placeholder="{{ 'labels.text.EnterTransferDescription' | translate }}"
<mat-autocomplete title="Transfer description"
autoActiveFirstOption ></textarea>
#clientsAutocomplete="matAutocomplete" @if (transferDetailsForm.controls['transferDescription'].hasError('required')) {
[displayWith]="displayClient" <mat-error>
> {{ 'labels.inputs.Transfer Description' | translate }} {{ 'labels.commons.is' | translate }}
@for (client of clientsData; track client) { <strong>{{ 'labels.commons.required' | translate }}</strong>
<mat-option [value]="client"> {{ client.id }} - {{ client.displayName }} </mat-option> </mat-error>
} }
</mat-autocomplete> </mat-form-field>
<mat-form-field class="form-field"> </div>
<mat-label>{{ 'labels.inputs.Account Type' | translate }}</mat-label> </form>
<mat-select required formControlName="toAccountType" (selectionChange)="changeEvent()">
@for (toAccountType of toAccountTypeData; track toAccountType) { <!-- Step 2 Navigation -->
<mat-option [value]="toAccountType.id"> <div class="layout-row align-center gap-2percent margin-t responsive-column">
{{ toAccountType.value }} <button mat-raised-button matStepperPrevious>
</mat-option> <fa-icon icon="arrow-left" class="m-r-10"></fa-icon>
} {{ 'labels.buttons.Previous' | translate }}
</mat-select>
@if (makeAccountTransferForm.controls.toAccountType.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Account Type' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field class="form-field">
<mat-label>{{ 'labels.inputs.Account' | translate }}</mat-label>
<mat-select required formControlName="toAccountId" (selectionChange)="changeEvent()">
@for (toAccount of toAccountData; track toAccount) {
<mat-option [value]="toAccount.id">
{{ toAccount.productName }} - {{ toAccount.accountNo }}
</mat-option>
}
</mat-select>
@if (makeAccountTransferForm.controls.toAccountId.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Account' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field class="form-field">
<mat-label>{{ 'labels.inputs.Amount' | translate }}</mat-label>
<input
type="number"
matInput
required
formControlName="transferAmount"
placeholder="{{ 'labels.text.EnterAmount' | translate }}"
title="Transfer amount"
min="0.01"
step="0.01"
/>
@if (makeAccountTransferForm.controls.transferAmount.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Amount' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
@if (makeAccountTransferForm.get('transferAmount')?.hasError('amountExceedsBalance')) {
<mat-error>
<fa-icon icon="exclamation-triangle" size="md"></fa-icon>
{{ 'errors.validation.msg.savingsproduct.insufficient.balance' | translate: { balance } }}
</mat-error>
}
</mat-form-field>
<mat-form-field class="form-field description-field">
<mat-label>{{ 'labels.inputs.Description' | translate }}</mat-label>
<textarea
matInput
formControlName="transferDescription"
cdkTextareaAutosize
cdkAutosizeMinRows="2"
placeholder="{{ 'labels.text.EnterTransferDescription' | translate }}"
title="Transfer description"
></textarea>
@if (makeAccountTransferForm.controls.transferDescription.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Transfer Description' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
</div>
</form>
}
<!-- Interbank Transfer Form Section -->
@if (interbank && interbankTransferForm && makeAccountTransferForm) {
<form [formGroup]="makeAccountTransferForm" class="transfer-form">
<h3 class="section-title transfer-heading">{{ 'labels.heading.Transfer Details' | translate }}</h3>
<div class="form-grid">
<mat-form-field class="form-field" (click)="transferDatePicker.open()">
<mat-label>{{ 'labels.inputs.Transaction Date' | translate }}</mat-label>
<input
matInput
[min]="minDate"
[max]="maxDate"
[matDatepicker]="transferDatePicker"
required
formControlName="transferDate"
placeholder="{{ 'labels.text.SelectDate' | translate }}"
title="Transaction Date"
/>
<mat-datepicker-toggle matSuffix [for]="transferDatePicker"></mat-datepicker-toggle>
<mat-datepicker #transferDatePicker></mat-datepicker>
@if (makeAccountTransferForm.controls.transferDate.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-form-field class="form-field">
<mat-label>{{ 'labels.inputs.Bank' | translate }}</mat-label>
<input
matInput
formControlName="toBank"
[readonly]="true"
placeholder="{{ 'labels.inputs.Bank' | translate }}"
title="Bank"
/>
</mat-form-field>
<mat-form-field class="form-field">
<mat-label>{{ 'labels.inputs.Client' | translate }}</mat-label>
<input
matInput
formControlName="toClientId"
[readonly]="true"
placeholder="{{ 'labels.inputs.Client' | translate }}"
title="Client"
/>
</mat-form-field>
<mat-form-field class="form-field">
<mat-label>{{ 'labels.inputs.Account Type' | translate }}</mat-label>
<input
matInput
formControlName="toAccountType"
[readonly]="true"
placeholder="{{ 'labels.inputs.Account Type' | translate }}"
title="Account Type"
/>
</mat-form-field>
<mat-form-field class="form-field">
<mat-label>{{ 'labels.inputs.Account' | translate }}</mat-label>
<input
matInput
formControlName="toAccountId"
[readonly]="true"
placeholder="{{ 'labels.inputs.Account' | translate }}"
title="Account"
/>
</mat-form-field>
<mat-form-field class="form-field">
<mat-label>{{ 'labels.inputs.Amount' | translate }}</mat-label>
<input
type="number"
matInput
required
formControlName="transferAmount"
placeholder="{{ 'labels.text.EnterAmount' | translate }}"
title="Transfer amount"
min="0.01"
step="0.01"
/>
@if (makeAccountTransferForm.controls.transferAmount.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Amount' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
@if (makeAccountTransferForm.controls.transferAmount.hasError('min')) {
<mat-error>
{{ 'labels.inputs.Amount' | translate }} {{ 'labels.commons.mustBeAtLeast' | translate }} 0.01
</mat-error>
}
@if (makeAccountTransferForm.get('transferAmount')?.hasError('amountExceedsBalance')) {
<mat-error>
<fa-icon icon="exclamation-triangle" size="md"></fa-icon>
{{ 'errors.validation.msg.savingsproduct.insufficient.balance' | translate: { balance } }}
</mat-error>
}
</mat-form-field>
<mat-form-field class="form-field description-field">
<mat-label>{{ 'labels.inputs.Description' | translate }}</mat-label>
<textarea
matInput
formControlName="transferDescription"
cdkTextareaAutosize
cdkAutosizeMinRows="2"
placeholder="{{ 'labels.text.EnterTransferDescription' | translate }}"
title="Transfer description"
></textarea>
@if (makeAccountTransferForm.controls.transferDescription.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Transfer Description' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
</div>
</form>
}
</mat-card-content>
@if (!isLoading && makeAccountTransferForm) {
<mat-card-actions class="action-buttons">
<button type="button" mat-raised-button [routerLink]="['../..']" class="cancel-button">
{{ 'labels.buttons.Cancel' | translate }}
</button> </button>
<ng-container *mifosxHasPermission="'CREATE_ACCOUNTTRANSFER'"> <ng-container *mifosxHasPermission="'CREATE_ACCOUNTTRANSFER'">
@if (interbank && interbankTransferForm) { <button mat-raised-button color="primary" [disabled]="!transferDetailsForm.valid" (click)="submit()">
<button {{ 'labels.buttons.Submit' | translate }}
mat-raised-button </button>
color="primary"
[disabled]="!makeAccountTransferForm.valid"
(click)="submit()"
class="primary-button"
>
{{ 'labels.buttons.Submit' | translate }}
</button>
}
@if (!interbank) {
<button
mat-raised-button
color="primary"
[disabled]="!makeAccountTransferForm.valid"
(click)="submit()"
class="primary-button"
>
{{ 'labels.buttons.Submit' | translate }}
</button>
}
</ng-container> </ng-container>
</mat-card-actions> <button mat-raised-button [routerLink]="['../..']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
</div>
} }
</mat-card> </mat-step>
}
<!-- ==================== STEP 3: Transfer Status ==================== -->
<mat-step [editable]="false">
<ng-template matStepLabel>{{ 'labels.heading.Transfer Status' | translate }}</ng-template>
@if (isLoading) {
<div class="loader-wrapper">
<div class="bottom triangle"></div>
<div class="top triangle"></div>
<div class="left triangle"></div>
<div class="right triangle"></div>
</div>
}
@if (!isLoading && transferComplete) {
<div class="transfer-status-container">
@if (transferSuccess) {
<div class="status-icon success">
<fa-icon icon="check-circle" size="3x"></fa-icon>
</div>
<h3 class="status-title success-text">{{ 'labels.heading.Transfer Successful' | translate }}</h3>
} @else {
<div class="status-icon error">
<fa-icon icon="times-circle" size="3x"></fa-icon>
</div>
<h3 class="status-title error-text">{{ 'labels.heading.Transfer Failed' | translate }}</h3>
@if (transferErrorMessage) {
<p class="status-message error-text">{{ transferErrorMessage }}</p>
}
}
<!-- Transfer Summary -->
<div class="section-container transfer-summary">
<h3 class="section-title transfer-heading">{{ 'labels.heading.Transfer Summary' | translate }}</h3>
<mat-divider></mat-divider>
<div class="info-grid">
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.From Account' | translate }}</div>
<div class="info-value">
{{ accountTransferTemplateData.fromAccount.productName }}&nbsp;-&nbsp;#{{
accountTransferTemplateData.fromAccount.accountNo
}}
</div>
</div>
@if (interbank && interbankTransferForm) {
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.Bank' | translate }}</div>
<div class="info-value">{{ beneficiaryForm.get('toBank')?.value }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.Client' | translate }}</div>
<div class="info-value">{{ beneficiaryForm.get('toClientId')?.value }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.Account' | translate }}</div>
<div class="info-value">{{ beneficiaryForm.get('toAccountId')?.value }}</div>
</div>
} @else {
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.Office' | translate }}</div>
<div class="info-value">{{ getSelectedOfficeName() }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.Client' | translate }}</div>
<div class="info-value">{{ getSelectedClientName() }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.Account' | translate }}</div>
<div class="info-value">{{ getSelectedAccountName() }}</div>
</div>
}
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.Amount' | translate }}</div>
<div class="info-value">
{{ transferDetailsForm.get('transferAmount')?.value }} {{ accountTransferTemplateData.currency.code }}
</div>
</div>
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.Transaction Date' | translate }}</div>
<div class="info-value">{{ transferDetailsForm.get('transferDate')?.value | date }}</div>
</div>
@if (transferDetailsForm.get('transferDescription')?.value) {
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.Description' | translate }}</div>
<div class="info-value">{{ transferDetailsForm.get('transferDescription')?.value }}</div>
</div>
}
@if (transferReferenceId) {
<div class="info-row">
<div class="info-label">{{ 'labels.inputs.Transaction ID' | translate }}</div>
<div class="info-value">{{ transferReferenceId }}</div>
</div>
}
</div>
</div>
<!-- Step 3 Navigation -->
<div class="layout-row align-center gap-2percent margin-t responsive-column">
<button mat-raised-button [routerLink]="['../../transactions']">
<fa-icon icon="list" class="m-r-10"></fa-icon>
{{ 'labels.buttons.View Transactions' | translate }}
</button>
<button mat-raised-button [routerLink]="['../..']">
{{ 'labels.buttons.Back to Account' | translate }}
</button>
</div>
</div>
}
</mat-step>
</mat-stepper>
</div> </div>
@@ -12,14 +12,6 @@
padding: 1rem; padding: 1rem;
} }
// Card styling
.transfer-card {
border-radius: 8px;
box-shadow: 0 2px 10px rgb(0 0 0 / 8%);
margin-bottom: 1.5rem;
overflow: hidden;
}
// Section styling // Section styling
.section-container { .section-container {
margin-bottom: 2rem; margin-bottom: 2rem;
@@ -82,6 +74,12 @@ mat-divider {
margin-bottom: 1rem; margin-bottom: 1rem;
} }
// Beneficiary preview and summary
.beneficiary-preview,
.beneficiary-summary {
margin-top: 1rem;
}
// Form styling // Form styling
.transfer-form { .transfer-form {
margin-top: 1rem; margin-top: 1rem;
@@ -178,6 +176,53 @@ mat-divider {
} }
} }
// Step navigation buttons (matching loans stepper pattern)
.step-actions {
padding: 1rem 0;
}
// Transfer Status (Step 3)
.transfer-status-container {
text-align: center;
padding: 1.5rem 0;
}
.status-icon {
margin-bottom: 1rem;
&.success {
color: #4caf50;
}
&.error {
color: #f44336;
}
}
.status-title {
font-size: 1.5rem;
font-weight: 700;
margin: 0 0 0.5rem;
}
.success-text {
color: #4caf50;
}
.error-text {
color: #f44336;
}
.status-message {
font-size: 0.875rem;
margin-bottom: 1.5rem;
}
.transfer-summary {
text-align: left;
margin-top: 1.5rem;
}
// Loader styling // Loader styling
.loader-wrapper { .loader-wrapper {
display: flex; display: flex;
@@ -254,6 +299,14 @@ mat-divider {
} }
} }
} }
.status-icon.success {
color: #66bb6a;
}
.status-icon.error {
color: #ef5350;
}
} }
// Higher specificity selectors // Higher specificity selectors
@@ -7,7 +7,7 @@
*/ */
/** Angular Imports */ /** Angular Imports */
import { Component, OnInit, AfterViewInit, inject } from '@angular/core'; import { Component, OnInit, AfterViewInit, ViewChild, inject } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { import {
AbstractControl, AbstractControl,
@@ -27,8 +27,16 @@ import { Dates } from 'app/core/utils/dates';
/** Environment Configuration */ /** Environment Configuration */
import { environment } from '../../../environments/environment'; import { environment } from '../../../environments/environment';
import { MatDivider } from '@angular/material/divider'; import { MatDivider } from '@angular/material/divider';
import { MatFormField, MatLabel, MatHint, MatError } from '@angular/material/form-field'; import { MatHint } from '@angular/material/form-field';
import { MatAutocompleteTrigger, MatAutocomplete } from '@angular/material/autocomplete'; import { MatAutocompleteTrigger, MatAutocomplete } from '@angular/material/autocomplete';
import {
MatStepper,
MatStepperIcon,
MatStep,
MatStepLabel,
MatStepperNext,
MatStepperPrevious
} from '@angular/material/stepper';
import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { FaIconComponent } from '@fortawesome/angular-fontawesome';
import { CdkTextareaAutosize } from '@angular/cdk/text-field'; import { CdkTextareaAutosize } from '@angular/cdk/text-field';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
@@ -47,6 +55,12 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
MatHint, MatHint,
MatAutocompleteTrigger, MatAutocompleteTrigger,
MatAutocomplete, MatAutocomplete,
MatStepper,
MatStepperIcon,
MatStep,
MatStepLabel,
MatStepperNext,
MatStepperPrevious,
FaIconComponent, FaIconComponent,
CdkTextareaAutosize CdkTextareaAutosize
] ]
@@ -60,14 +74,19 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit {
private settingsService = inject(SettingsService); private settingsService = inject(SettingsService);
private clientsService = inject(ClientsService); private clientsService = inject(ClientsService);
/** Stepper reference */
@ViewChild('transferStepper') transferStepper: MatStepper;
/** Standing Instructions Data */ /** Standing Instructions Data */
accountTransferTemplateData: any; accountTransferTemplateData: any;
/** Minimum date allowed. */ /** Minimum date allowed. */
minDate = new Date(2000, 0, 1); minDate = new Date(2000, 0, 1);
/** Maximum date allowed. */ /** Maximum date allowed. */
maxDate = new Date(2100, 0, 1); maxDate = new Date(2100, 0, 1);
/** Edit Standing Instructions form. */ /** Beneficiary selection form (Step 1) */
makeAccountTransferForm: UntypedFormGroup; beneficiaryForm: UntypedFormGroup;
/** Transfer details form (Step 2) */
transferDetailsForm: UntypedFormGroup;
/** To Office Type Data */ /** To Office Type Data */
toOfficeTypeData: any; toOfficeTypeData: any;
/** To Client Type Data */ /** To Client Type Data */
@@ -86,22 +105,18 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit {
clientsData: any; clientsData: any;
/** interbank transfer */ /** interbank transfer */
interbank: boolean = false; interbank: boolean = false;
/** Reference of phoneAccount search */
phoneAccount = '';
/** Interbank transfer form flag */ /** Interbank transfer form flag */
interbankTransferForm: boolean = false; interbankTransferForm: boolean = false;
balance: number = 0; balance: number = 0;
isLoading: boolean = false; isLoading: boolean = false;
/** Transfer status flags (Step 3) */
transferComplete: boolean = false;
transferSuccess: boolean = false;
transferErrorMessage: string = '';
transferReferenceId: string = '';
/** /**
* Retrieves the standing instructions template from `resolve`. * Retrieves the standing instructions template from `resolve`.
* @param {ActivatedRoute} route Activated Route.
* @param {FormBuilder} formBuilder Form Builder
* @param {Router} router Router
* @param {AccountTransfersService} accountTransfersService Account Transfers Service
* @param {Dates} dateUtils Date Utils
* @param {SettingsService} settingsService Settings Service
* @param {ClientsService} clientsService Clients Service
*/ */
constructor() { constructor() {
this.route.data.subscribe((data: { accountTransferTemplate: any }) => { this.route.data.subscribe((data: { accountTransferTemplate: any }) => {
@@ -111,7 +126,6 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit {
}); });
} }
/** Sets the value from the URL */
/** Sets the value from the URL */ /** Sets the value from the URL */
setParams() { setParams() {
this.accountType = this.route.snapshot.queryParams['accountType']; this.accountType = this.route.snapshot.queryParams['accountType'];
@@ -139,62 +153,23 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit {
} }
/** /**
* Creates and sets the create standing instructions form. * Creates and sets the beneficiary and transfer details forms.
*/ */
ngOnInit() { ngOnInit() {
this.maxDate = this.settingsService.businessDate; this.maxDate = this.settingsService.businessDate;
if (!this.interbank) { if (!this.interbank) {
this.createMakeAccountTransferForm(); this.createNormalBeneficiaryForm();
} else { } else {
this.createEmptyInterbankForm(); this.createEmptyInterbankBeneficiaryForm();
} }
this.createTransferDetailsForm();
} }
/** /**
* Crea un formulario vacío para interbank mientras se carga * Creates the beneficiary form for normal (non-interbank) transfers.
*/ */
createEmptyInterbankForm() { createNormalBeneficiaryForm() {
this.makeAccountTransferForm = this.formBuilder.group({ this.beneficiaryForm = this.formBuilder.group({
toBank: [
'',
Validators.required
],
toClientId: [
'',
Validators.required
],
toAccountType: [
'',
Validators.required
],
toAccountId: [
'',
Validators.required
],
transferAmount: [
0,
[
Validators.required,
Validators.min(0.01),
this.amountExceedsBalanceValidator.bind(this)
]
],
transferDate: [
this.settingsService.businessDate,
Validators.required
],
transferDescription: [
'',
Validators.required
]
});
}
/**
* Creates the standing instruction form.
*/
createMakeAccountTransferForm() {
this.makeAccountTransferForm = this.formBuilder.group({
toOfficeId: [ toOfficeId: [
'', '',
Validators.required Validators.required
@@ -210,51 +185,61 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit {
toAccountId: [ toAccountId: [
'', '',
Validators.required Validators.required
],
transferAmount: [
this.accountTransferTemplateData.transferAmount,
[
Validators.required,
Validators.min(0.01),
this.amountExceedsBalanceValidator.bind(this)
]
],
transferDate: [
this.settingsService.businessDate,
Validators.required
],
transferDescription: [
'',
Validators.required
] ]
}); });
} }
createMakeAccountInterbankTransferForm(account: any) { /**
* Creates an empty beneficiary form for interbank transfers (phone search).
*/
createEmptyInterbankBeneficiaryForm() {
this.beneficiaryForm = this.formBuilder.group({
phoneNumber: [
'',
[
Validators.required,
Validators.minLength(10),
Validators.maxLength(10)
]
],
toBank: [''],
toClientId: [''],
toAccountType: [''],
toAccountId: ['']
});
}
/**
* Populates the interbank beneficiary form after phone search resolves an account.
*/
populateInterbankBeneficiary(account: any) {
if (!account) { if (!account) {
console.error('Account data is undefined'); console.error('Account data is undefined');
this.isLoading = false; this.isLoading = false;
return; return;
} }
const defaultAmount = this.beneficiaryForm.patchValue({
this.accountTransferTemplateData?.transferAmount > 0 ? this.accountTransferTemplateData.transferAmount : 1; toBank: account.destinationFspId || '',
toClientId: (account.firstName || account.firsName || '') + ' ' + (account.lastName || ''),
toAccountType: 'Saving Account',
toAccountId: account.partyId || ''
});
this.makeAccountTransferForm = this.formBuilder.group({ this.interbankTransferForm = true;
toBank: [ this.isLoading = false;
account.destinationFspId || '', }
Validators.required
], /**
toClientId: [ * Creates the transfer details form (Step 2).
(account.firstName || account.firsName || '') + ' ' + (account.lastName || ''), */
Validators.required createTransferDetailsForm() {
], const defaultAmount =
toAccountType: [ this.accountTransferTemplateData?.transferAmount > 0 ? this.accountTransferTemplateData.transferAmount : '';
'Saving Account',
Validators.required this.transferDetailsForm = this.formBuilder.group({
], transferDate: [
toAccountId: [ this.settingsService.businessDate,
account.partyId || '',
Validators.required Validators.required
], ],
transferAmount: [ transferAmount: [
@@ -265,16 +250,11 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit {
this.amountExceedsBalanceValidator.bind(this) this.amountExceedsBalanceValidator.bind(this)
] ]
], ],
transferDate: [
this.settingsService.businessDate,
Validators.required
],
transferDescription: [ transferDescription: [
'Transferencia interbancaria', '',
Validators.required Validators.required
] ]
}); });
this.isLoading = false;
} }
amountExceedsBalanceValidator(control: AbstractControl): ValidationErrors | null { amountExceedsBalanceValidator(control: AbstractControl): ValidationErrors | null {
@@ -291,7 +271,7 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit {
/** Executes on change of various select options */ /** Executes on change of various select options */
changeEvent() { changeEvent() {
const formValue = this.refineObject(this.makeAccountTransferForm.value); const formValue = this.refineObject({ ...this.beneficiaryForm.value });
this.accountTransfersService this.accountTransfersService
.newAccountTranferResource(this.id, this.accountTypeId, formValue) .newAccountTranferResource(this.id, this.accountTypeId, formValue)
.subscribe((response: any) => { .subscribe((response: any) => {
@@ -304,10 +284,7 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit {
/** Refine Object /** Refine Object
* Removes the object param with null or '' values * Removes the object param with null or '' values
*/ */
refineObject(dataObj: { [x: string]: any; transferAmount: any; transferDate: any; transferDescription: any }) { refineObject(dataObj: any) {
delete dataObj.transferAmount;
delete dataObj.transferDate;
delete dataObj.transferDescription;
if (dataObj.toClientId && typeof dataObj.toClientId === 'object') { if (dataObj.toClientId && typeof dataObj.toClientId === 'object') {
dataObj.toClientId = dataObj.toClientId.id; dataObj.toClientId = dataObj.toClientId.id;
} }
@@ -325,8 +302,8 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit {
* Subscribes to Clients search filter: * Subscribes to Clients search filter:
*/ */
ngAfterViewInit() { ngAfterViewInit() {
if (!this.interbank && this.makeAccountTransferForm) { if (!this.interbank && this.beneficiaryForm) {
this.makeAccountTransferForm.controls.toClientId.valueChanges.subscribe((value: any) => { this.beneficiaryForm.controls.toClientId.valueChanges.subscribe((value: any) => {
if (typeof value === 'string' && value.length >= 2) { if (typeof value === 'string' && value.length >= 2) {
this.clientsService.getFilteredClients('displayName', 'ASC', true, value).subscribe((data: any) => { this.clientsService.getFilteredClients('displayName', 'ASC', true, value).subscribe((data: any) => {
this.clientsData = data.pageItems; this.clientsData = data.pageItems;
@@ -346,8 +323,35 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit {
return client ? client.displayName : undefined; return client ? client.displayName : undefined;
} }
/** Helper methods for displaying selected beneficiary info in Step 2 summary */
getSelectedOfficeName(): string {
const officeId = this.beneficiaryForm?.get('toOfficeId')?.value;
const office = this.toOfficeTypeData?.find((o: any) => o.id === officeId);
return office ? office.name : '';
}
getSelectedClientName(): string {
const client = this.beneficiaryForm?.get('toClientId')?.value;
if (typeof client === 'object' && client) {
return client.displayName;
}
return client || '';
}
getSelectedAccountTypeName(): string {
const typeId = this.beneficiaryForm?.get('toAccountType')?.value;
const type = this.toAccountTypeData?.find((t: any) => t.id === typeId);
return type ? type.value : '';
}
getSelectedAccountName(): string {
const accountId = this.beneficiaryForm?.get('toAccountId')?.value;
const account = this.toAccountData?.find((a: any) => a.id === accountId);
return account ? `${account.productName} - ${account.accountNo}` : '';
}
/** /**
* Submits the standing instructions form * Submits the transfer
*/ */
submit() { submit() {
this.interbank ? this.makeInterbankTransfer() : this.makeTransfer(); this.interbank ? this.makeInterbankTransfer() : this.makeTransfer();
@@ -359,15 +363,16 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit {
const locale = this.settingsService.language.code; const locale = this.settingsService.language.code;
let toClientIdValue: any; let toClientIdValue: any;
if (typeof this.makeAccountTransferForm.controls.toClientId.value === 'object') { if (typeof this.beneficiaryForm.controls.toClientId.value === 'object') {
toClientIdValue = this.makeAccountTransferForm.controls.toClientId.value.id; toClientIdValue = this.beneficiaryForm.controls.toClientId.value.id;
} else { } else {
toClientIdValue = this.makeAccountTransferForm.controls.toClientId.value; toClientIdValue = this.beneficiaryForm.controls.toClientId.value;
} }
const makeAccountTransferData = { const makeAccountTransferData = {
...this.makeAccountTransferForm.value, ...this.beneficiaryForm.value,
transferDate: this.dateUtils.formatDate(this.makeAccountTransferForm.value.transferDate, dateFormat), ...this.transferDetailsForm.value,
transferDate: this.dateUtils.formatDate(this.transferDetailsForm.value.transferDate, dateFormat),
dateFormat, dateFormat,
locale, locale,
toClientId: toClientIdValue, toClientId: toClientIdValue,
@@ -377,21 +382,28 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit {
fromOfficeId: this.accountTransferTemplateData.fromClient.officeId fromOfficeId: this.accountTransferTemplateData.fromClient.officeId
}; };
this.accountTransfersService.createAccountTransfer(makeAccountTransferData).subscribe(() => { this.accountTransfersService.createAccountTransfer(makeAccountTransferData).subscribe(
this.isLoading = false; (response: any) => {
this.router.navigate(['../../transactions'], { relativeTo: this.route }); this.isLoading = false;
}); this.transferComplete = true;
this.transferSuccess = true;
this.transferReferenceId = response?.resourceId || response?.transactionId || '';
this.transferStepper.next();
},
(error: any) => {
this.isLoading = false;
this.transferComplete = true;
this.transferSuccess = false;
this.transferErrorMessage =
error?.error?.defaultUserMessage || error?.message || 'An unexpected error occurred.';
this.transferStepper.next();
}
);
} }
makeInterbankTransfer() { makeInterbankTransfer() {
this.isLoading = true; this.isLoading = true;
if (!this.makeAccountTransferForm.valid) {
console.error('Interbank form is not valid');
this.isLoading = false;
return;
}
const payload = { const payload = {
homeTransactionId: crypto.randomUUID(), homeTransactionId: crypto.randomUUID(),
from: { from: {
@@ -400,14 +412,14 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit {
idValue: this.accountTransferTemplateData.fromAccount.externalId?.trim() || '' idValue: this.accountTransferTemplateData.fromAccount.externalId?.trim() || ''
}, },
to: { to: {
fspId: this.makeAccountTransferForm.controls.toBank.value, fspId: this.beneficiaryForm.controls.toBank.value,
idType: 'MSISDN', idType: 'MSISDN',
idValue: this.makeAccountTransferForm.controls.toAccountId.value idValue: this.beneficiaryForm.controls.toAccountId.value
}, },
amountType: 'SEND', amountType: 'SEND',
amount: { amount: {
currencyCode: this.accountTransferTemplateData.currency.code, currencyCode: this.accountTransferTemplateData.currency.code,
amount: this.makeAccountTransferForm.controls.transferAmount.value amount: this.transferDetailsForm.controls.transferAmount.value
}, },
transactionType: { transactionType: {
scenario: 'TRANSFER', scenario: 'TRANSFER',
@@ -415,35 +427,41 @@ export class MakeAccountTransfersComponent implements OnInit, AfterViewInit {
initiator: 'PAYER', initiator: 'PAYER',
initiatorType: 'CUSTOMER' initiatorType: 'CUSTOMER'
}, },
note: this.makeAccountTransferForm.controls.transferDescription.value note: this.transferDetailsForm.controls.transferDescription.value
}; };
this.accountTransfersService.sendInterbankTransfer(JSON.stringify(payload)).subscribe( this.accountTransfersService.sendInterbankTransfer(JSON.stringify(payload)).subscribe(
(trnsfr) => { (trnsfr) => {
if (trnsfr.systemMessage) { this.isLoading = false;
this.isLoading = false; this.transferComplete = true;
this.router.navigate(['../../transactions'], { relativeTo: this.route }); this.transferSuccess = true;
} this.transferReferenceId = trnsfr?.systemMessage || '';
this.transferStepper.next();
}, },
(error) => { (error) => {
console.error('Interbank transfer error:', error); console.error('Interbank transfer error:', error);
this.isLoading = false; this.isLoading = false;
this.transferComplete = true;
this.transferSuccess = false;
this.transferErrorMessage =
error?.error?.defaultUserMessage || error?.message || 'An unexpected error occurred.';
this.transferStepper.next();
} }
); );
} }
searchAccountByNumber() { searchAccountByNumber() {
if (!this.phoneAccount || this.phoneAccount.length !== 10) { const phoneNumber = this.beneficiaryForm.get('phoneNumber')?.value;
if (!phoneNumber || phoneNumber.length !== 10) {
return; return;
} }
this.isLoading = true; this.isLoading = true;
this.accountTransfersService this.accountTransfersService
.getAccountByNumber(this.phoneAccount, this.accountTransferTemplateData.currency.code) .getAccountByNumber(phoneNumber, this.accountTransferTemplateData.currency.code)
.subscribe( .subscribe(
(acc) => { (acc) => {
this.interbankTransferForm = true; this.populateInterbankBeneficiary(acc);
this.createMakeAccountInterbankTransferForm(acc);
}, },
(error) => { (error) => {
console.error('searching account error:', error); console.error('searching account error:', error);
+8
View File
@@ -347,6 +347,7 @@
"Attach Meeting": "Připojit schůzku", "Attach Meeting": "Připojit schůzku",
"Attendance": "Účast", "Attendance": "Účast",
"Back": "Zadní", "Back": "Zadní",
"Back to Account": "Zpět na účet",
"Bar Chart": "Sloupcový graf", "Bar Chart": "Sloupcový graf",
"Browse": "Procházet", "Browse": "Procházet",
"Bulk JLG Loan Application": "Hromadná žádost o půjčku JLG", "Bulk JLG Loan Application": "Hromadná žádost o půjčku JLG",
@@ -548,6 +549,7 @@
"View Journal Entries": "Zobrazit záznamy deníku", "View Journal Entries": "Zobrazit záznamy deníku",
"View Standing Instructions": "Prohlédněte si stálé pokyny", "View Standing Instructions": "Prohlédněte si stálé pokyny",
"View Transactions History": "Zobrazit historii transakcí", "View Transactions History": "Zobrazit historii transakcí",
"View Transactions": "Zobrazit transakce",
"Waive": "vzdát se", "Waive": "vzdát se",
"Waive Charge": "Zřeknutí se poplatku", "Waive Charge": "Zřeknutí se poplatku",
"Week": "Týden", "Week": "Týden",
@@ -926,6 +928,8 @@
"Assets / Liability": "Aktiva / pasiva", "Assets / Liability": "Aktiva / pasiva",
"Audit Trails": "Audit Trails", "Audit Trails": "Audit Trails",
"Balance": "Zůstatek", "Balance": "Zůstatek",
"Beneficiary": "Příjemce",
"Beneficiary Selection": "Výběr příjemce",
"Block Savings Account": "Blokovat spořicí účet", "Block Savings Account": "Blokovat spořicí účet",
"Bulk Import": "Hromadný import", "Bulk Import": "Hromadný import",
"Bulk Loan Reassignment": "Hromadné přeřazení půjčky", "Bulk Loan Reassignment": "Hromadné přeřazení půjčky",
@@ -1231,6 +1235,10 @@
"Transaction Reverted": "Transakce vrácena", "Transaction Reverted": "Transakce vrácena",
"Transactions": "Transakce", "Transactions": "Transakce",
"Transfer Details": "Podrobnosti o převodu", "Transfer Details": "Podrobnosti o převodu",
"Transfer Failed": "Převod se nezdařil",
"Transfer Status": "Stav převodu",
"Transfer Successful": "Převod úspěšný",
"Transfer Summary": "Souhrn převodu",
"Transferred From": "Převedeno z", "Transferred From": "Převedeno z",
"Transferred To": "Převeden k", "Transferred To": "Převeden k",
"Transferring From Details": "Přenos z podrobností", "Transferring From Details": "Přenos z podrobností",
+8
View File
@@ -347,6 +347,7 @@
"Attach Meeting": "Besprechung anhängen", "Attach Meeting": "Besprechung anhängen",
"Attendance": "Teilnahme", "Attendance": "Teilnahme",
"Back": "Zurück", "Back": "Zurück",
"Back to Account": "Zurück zum Konto",
"Bar Chart": "Balkendiagramm", "Bar Chart": "Balkendiagramm",
"Browse": "Durchsuche", "Browse": "Durchsuche",
"Bulk JLG Loan Application": "Massenantrag für einen JLG-Kredit", "Bulk JLG Loan Application": "Massenantrag für einen JLG-Kredit",
@@ -548,6 +549,7 @@
"View Journal Entries": "Journaleinträge anzeigen", "View Journal Entries": "Journaleinträge anzeigen",
"View Standing Instructions": "Ständige Anweisungen anzeigen", "View Standing Instructions": "Ständige Anweisungen anzeigen",
"View Transactions History": "Transaktionsverlauf anzeigen", "View Transactions History": "Transaktionsverlauf anzeigen",
"View Transactions": "Transaktionen anzeigen",
"Waive": "Verzichten", "Waive": "Verzichten",
"Waive Charge": "Auf Gebühr verzichten", "Waive Charge": "Auf Gebühr verzichten",
"Week": "Woche", "Week": "Woche",
@@ -927,6 +929,8 @@
"Assets / Liability": "Vermögenswerte / Verbindlichkeiten", "Assets / Liability": "Vermögenswerte / Verbindlichkeiten",
"Audit Trails": "Buchungsprotokolle", "Audit Trails": "Buchungsprotokolle",
"Balance": "Gleichgewicht", "Balance": "Gleichgewicht",
"Beneficiary": "Begünstigter",
"Beneficiary Selection": "Begünstigtenauswahl",
"Block Savings Account": "Sparkonto sperren", "Block Savings Account": "Sparkonto sperren",
"Bulk Import": "Massenimport", "Bulk Import": "Massenimport",
"Bulk Loan Reassignment": "Neuzuweisung von Massenkrediten", "Bulk Loan Reassignment": "Neuzuweisung von Massenkrediten",
@@ -1232,6 +1236,10 @@
"Transaction Reverted": "Transaktion rückgängig gemacht", "Transaction Reverted": "Transaktion rückgängig gemacht",
"Transactions": "Transaktionen", "Transactions": "Transaktionen",
"Transfer Details": "Transferdetails", "Transfer Details": "Transferdetails",
"Transfer Failed": "Überweisung fehlgeschlagen",
"Transfer Status": "Überweisungsstatus",
"Transfer Successful": "Überweisung erfolgreich",
"Transfer Summary": "Überweisungszusammenfassung",
"Transferred From": "Transferiert von", "Transferred From": "Transferiert von",
"Transferred To": "Übertragen auf", "Transferred To": "Übertragen auf",
"Transferring From Details": "Von Details übertragen", "Transferring From Details": "Von Details übertragen",
+9
View File
@@ -351,6 +351,7 @@
"Attach Meeting": "Attach Meeting", "Attach Meeting": "Attach Meeting",
"Attendance": "Attendance", "Attendance": "Attendance",
"Back": "Back", "Back": "Back",
"Back to Account": "Back to Account",
"Bar Chart": "Bar Chart", "Bar Chart": "Bar Chart",
"Browse": "Browse", "Browse": "Browse",
"Bulk JLG Loan Application": "Bulk JLG Loan Application", "Bulk JLG Loan Application": "Bulk JLG Loan Application",
@@ -552,6 +553,7 @@
"View Journal Entries": "View Journal Entries", "View Journal Entries": "View Journal Entries",
"View Standing Instructions": "View Standing Instructions", "View Standing Instructions": "View Standing Instructions",
"View Transactions History": "View Transactions History", "View Transactions History": "View Transactions History",
"View Transactions": "View Transactions",
"Waive": "Waive", "Waive": "Waive",
"Waive Charge": "Waive Charge", "Waive Charge": "Waive Charge",
"Week": "Week", "Week": "Week",
@@ -932,6 +934,8 @@
"Assets / Liability": "Assets / Liability", "Assets / Liability": "Assets / Liability",
"Audit Trails": "Audit Trails", "Audit Trails": "Audit Trails",
"Balance": "Balance", "Balance": "Balance",
"Beneficiary": "Beneficiary",
"Beneficiary Selection": "Beneficiary Selection",
"Block Savings Account": "Block Savings Account", "Block Savings Account": "Block Savings Account",
"Bulk Import": "Bulk Import", "Bulk Import": "Bulk Import",
"Bulk Loan Reassignment": "Bulk Loan Reassignment", "Bulk Loan Reassignment": "Bulk Loan Reassignment",
@@ -1245,6 +1249,10 @@
"Transaction Reverted": "Transaction Reverted", "Transaction Reverted": "Transaction Reverted",
"Transactions": "Transactions", "Transactions": "Transactions",
"Transfer Details": "Transfer Details", "Transfer Details": "Transfer Details",
"Transfer Failed": "Transfer Failed",
"Transfer Status": "Transfer Status",
"Transfer Successful": "Transfer Successful",
"Transfer Summary": "Transfer Summary",
"Transferred From": "Transferred From", "Transferred From": "Transferred From",
"Transferred To": "Transferred To", "Transferred To": "Transferred To",
"Transferring From Details": "Transferring From Details", "Transferring From Details": "Transferring From Details",
@@ -1438,6 +1446,7 @@
"Base Price": "Base Price", "Base Price": "Base Price",
"Base Percentage": "Base Percentage", "Base Percentage": "Base Percentage",
"Beneficiary": "Beneficiary", "Beneficiary": "Beneficiary",
"Beneficiary Selection": "Beneficiary Selection",
"Branch": "Branch", "Branch": "Branch",
"Branch Office": "Branch Office", "Branch Office": "Branch Office",
"Breakdown": "Breakdown", "Breakdown": "Breakdown",
+8
View File
@@ -347,6 +347,7 @@
"Attach Meeting": "Adjuntar reunión", "Attach Meeting": "Adjuntar reunión",
"Attendance": "Asistencia", "Attendance": "Asistencia",
"Back": "Atrás", "Back": "Atrás",
"Back to Account": "Volver a la Cuenta",
"Bar Chart": "Gráfico de barras", "Bar Chart": "Gráfico de barras",
"Browse": "Buscar", "Browse": "Buscar",
"Bulk JLG Loan Application": "Solicitud de Crédito JLG a granel", "Bulk JLG Loan Application": "Solicitud de Crédito JLG a granel",
@@ -548,6 +549,7 @@
"View Journal Entries": "Ver entradas de diario", "View Journal Entries": "Ver entradas de diario",
"View Standing Instructions": "Ver instrucciones permanentes", "View Standing Instructions": "Ver instrucciones permanentes",
"View Transactions History": "Ver historial de transacciones", "View Transactions History": "Ver historial de transacciones",
"View Transactions": "Ver transacciones",
"Waive": "Renunciar", "Waive": "Renunciar",
"Waive Charge": "Renunciar a Comisión", "Waive Charge": "Renunciar a Comisión",
"Week": "Semana", "Week": "Semana",
@@ -926,6 +928,8 @@
"Assets / Liability": "Activo / Pasivo", "Assets / Liability": "Activo / Pasivo",
"Audit Trails": "Pistas de auditoría", "Audit Trails": "Pistas de auditoría",
"Balance": "Saldo", "Balance": "Saldo",
"Beneficiary": "Beneficiario",
"Beneficiary Selection": "Selección de Beneficiario",
"Block Savings Account": "Bloquear Cuenta de Ahorros", "Block Savings Account": "Bloquear Cuenta de Ahorros",
"Bulk Import": "Importación masiva", "Bulk Import": "Importación masiva",
"Bulk Loan Reassignment": "Reasignación de Créditos másiva", "Bulk Loan Reassignment": "Reasignación de Créditos másiva",
@@ -1232,6 +1236,10 @@
"Transaction Reverted": "Transacción revertida", "Transaction Reverted": "Transacción revertida",
"Transactions": "Transacciones", "Transactions": "Transacciones",
"Transfer Details": "Detalles de la transferencia", "Transfer Details": "Detalles de la transferencia",
"Transfer Failed": "Transferencia fallida",
"Transfer Status": "Estado de la transferencia",
"Transfer Successful": "Transferencia exitosa",
"Transfer Summary": "Resumen de la transferencia",
"Transferred From": "Transferido desde", "Transferred From": "Transferido desde",
"Transferred To": "Transferido a", "Transferred To": "Transferido a",
"Transferring From Details": "Transferir desde detalles", "Transferring From Details": "Transferir desde detalles",
+8
View File
@@ -347,6 +347,7 @@
"Attach Meeting": "Adjuntar reunión", "Attach Meeting": "Adjuntar reunión",
"Attendance": "Asistencia", "Attendance": "Asistencia",
"Back": "Atrás", "Back": "Atrás",
"Back to Account": "Volver a la Cuenta",
"Bar Chart": "Gráfico de barras", "Bar Chart": "Gráfico de barras",
"Browse": "Buscar", "Browse": "Buscar",
"Bulk JLG Loan Application": "Solicitud de Crédito JLG a granel", "Bulk JLG Loan Application": "Solicitud de Crédito JLG a granel",
@@ -548,6 +549,7 @@
"View Journal Entries": "Ver entradas de diario", "View Journal Entries": "Ver entradas de diario",
"View Standing Instructions": "Ver instrucciones permanentes", "View Standing Instructions": "Ver instrucciones permanentes",
"View Transactions History": "Ver historial de transacciones", "View Transactions History": "Ver historial de transacciones",
"View Transactions": "Ver transacciones",
"Waive": "Renunciar", "Waive": "Renunciar",
"Waive Charge": "Renunciar a Comisión", "Waive Charge": "Renunciar a Comisión",
"Week": "Semana", "Week": "Semana",
@@ -926,6 +928,8 @@
"Assets / Liability": "Activo / Pasivo", "Assets / Liability": "Activo / Pasivo",
"Audit Trails": "Pistas de auditoría", "Audit Trails": "Pistas de auditoría",
"Balance": "Saldo", "Balance": "Saldo",
"Beneficiary": "Beneficiario",
"Beneficiary Selection": "Selección de Beneficiario",
"Block Savings Account": "Bloquear Cuenta de Ahorros", "Block Savings Account": "Bloquear Cuenta de Ahorros",
"Bulk Import": "Importación masiva", "Bulk Import": "Importación masiva",
"Bulk Loan Reassignment": "Reasignación de Créditos másiva", "Bulk Loan Reassignment": "Reasignación de Créditos másiva",
@@ -1231,6 +1235,10 @@
"Transaction Reverted": "Transacción revertida", "Transaction Reverted": "Transacción revertida",
"Transactions": "Transacciones", "Transactions": "Transacciones",
"Transfer Details": "Detalles de la transferencia", "Transfer Details": "Detalles de la transferencia",
"Transfer Failed": "Transferencia fallida",
"Transfer Status": "Estado de la transferencia",
"Transfer Successful": "Transferencia exitosa",
"Transfer Summary": "Resumen de la transferencia",
"Transferred From": "Transferido desde", "Transferred From": "Transferido desde",
"Transferred To": "Transferido a", "Transferred To": "Transferido a",
"Transferring From Details": "Transferir desde detalles", "Transferring From Details": "Transferir desde detalles",
+8
View File
@@ -347,6 +347,7 @@
"Attach Meeting": "Joindre une réunion", "Attach Meeting": "Joindre une réunion",
"Attendance": "Présence", "Attendance": "Présence",
"Back": "Dos", "Back": "Dos",
"Back to Account": "Retour au compte",
"Bar Chart": "Diagramme à bandes", "Bar Chart": "Diagramme à bandes",
"Browse": "Parcourir", "Browse": "Parcourir",
"Bulk JLG Loan Application": "Demande de prêt JLG en masse", "Bulk JLG Loan Application": "Demande de prêt JLG en masse",
@@ -548,6 +549,7 @@
"View Journal Entries": "Afficher les entrées de journal", "View Journal Entries": "Afficher les entrées de journal",
"View Standing Instructions": "Voir les instructions permanentes", "View Standing Instructions": "Voir les instructions permanentes",
"View Transactions History": "Afficher l'historique des transactions", "View Transactions History": "Afficher l'historique des transactions",
"View Transactions": "Voir les transactions",
"Waive": "Renoncer à", "Waive": "Renoncer à",
"Waive Charge": "Renoncer aux frais", "Waive Charge": "Renoncer aux frais",
"Week": "Semaine", "Week": "Semaine",
@@ -927,6 +929,8 @@
"Assets / Liability": "Actif / Passif", "Assets / Liability": "Actif / Passif",
"Audit Trails": "Des pistes de vérification", "Audit Trails": "Des pistes de vérification",
"Balance": "Équilibre", "Balance": "Équilibre",
"Beneficiary": "Bénéficiaire",
"Beneficiary Selection": "Sélection du bénéficiaire",
"Block Savings Account": "Bloquer le compte d'épargne", "Block Savings Account": "Bloquer le compte d'épargne",
"Bulk Import": "Importation en masse", "Bulk Import": "Importation en masse",
"Bulk Loan Reassignment": "Réaffectation groupée de prêts", "Bulk Loan Reassignment": "Réaffectation groupée de prêts",
@@ -1232,6 +1236,10 @@
"Transaction Reverted": "Transaction annulée", "Transaction Reverted": "Transaction annulée",
"Transactions": "Transactions", "Transactions": "Transactions",
"Transfer Details": "Détails du transfert", "Transfer Details": "Détails du transfert",
"Transfer Failed": "Transfert échoué",
"Transfer Status": "Statut du transfert",
"Transfer Successful": "Transfert réussi",
"Transfer Summary": "Résumé du transfert",
"Transferred From": "Transféré de", "Transferred From": "Transféré de",
"Transferred To": "Transféré à", "Transferred To": "Transféré à",
"Transferring From Details": "Transfert depuis les détails", "Transferring From Details": "Transfert depuis les détails",
+8
View File
@@ -347,6 +347,7 @@
"Attach Meeting": "Allega riunione", "Attach Meeting": "Allega riunione",
"Attendance": "Partecipazione", "Attendance": "Partecipazione",
"Back": "Indietro", "Back": "Indietro",
"Back to Account": "Torna al conto",
"Bar Chart": "Grafico a barre", "Bar Chart": "Grafico a barre",
"Browse": "Navigare", "Browse": "Navigare",
"Bulk JLG Loan Application": "Richiesta di prestito JLG in blocco", "Bulk JLG Loan Application": "Richiesta di prestito JLG in blocco",
@@ -548,6 +549,7 @@
"View Journal Entries": "Visualizza le voci del diario", "View Journal Entries": "Visualizza le voci del diario",
"View Standing Instructions": "Visualizza le istruzioni per la posizione in piedi", "View Standing Instructions": "Visualizza le istruzioni per la posizione in piedi",
"View Transactions History": "Visualizza la cronologia delle transazioni", "View Transactions History": "Visualizza la cronologia delle transazioni",
"View Transactions": "Visualizza transazioni",
"Waive": "Rinuncia", "Waive": "Rinuncia",
"Waive Charge": "Rinuncia all'addebito", "Waive Charge": "Rinuncia all'addebito",
"Week": "Settimana", "Week": "Settimana",
@@ -926,6 +928,8 @@
"Assets / Liability": "Attività/Passività", "Assets / Liability": "Attività/Passività",
"Audit Trails": "Percorsi di controllo", "Audit Trails": "Percorsi di controllo",
"Balance": "Bilancia", "Balance": "Bilancia",
"Beneficiary": "Beneficiario",
"Beneficiary Selection": "Selezione del beneficiario",
"Block Savings Account": "Bloccare il conto di risparmio", "Block Savings Account": "Bloccare il conto di risparmio",
"Bulk Import": "Importazione in blocco", "Bulk Import": "Importazione in blocco",
"Bulk Loan Reassignment": "Riassegnazione del prestito in blocco", "Bulk Loan Reassignment": "Riassegnazione del prestito in blocco",
@@ -1231,6 +1235,10 @@
"Transaction Reverted": "Transazione annullata", "Transaction Reverted": "Transazione annullata",
"Transactions": "Transazioni", "Transactions": "Transazioni",
"Transfer Details": "Dettagli del trasferimento", "Transfer Details": "Dettagli del trasferimento",
"Transfer Failed": "Trasferimento fallito",
"Transfer Status": "Stato del trasferimento",
"Transfer Successful": "Trasferimento riuscito",
"Transfer Summary": "Riepilogo del trasferimento",
"Transferred From": "Trasferito da", "Transferred From": "Trasferito da",
"Transferred To": "Trasferito a", "Transferred To": "Trasferito a",
"Transferring From Details": "Trasferimento dai dettagli", "Transferring From Details": "Trasferimento dai dettagli",
+8
View File
@@ -347,6 +347,7 @@
"Attach Meeting": "회의 첨부", "Attach Meeting": "회의 첨부",
"Attendance": "출석", "Attendance": "출석",
"Back": "뒤쪽에", "Back": "뒤쪽에",
"Back to Account": "계좌로 돌아가기",
"Bar Chart": "막대 차트", "Bar Chart": "막대 차트",
"Browse": "검색", "Browse": "검색",
"Bulk JLG Loan Application": "대량 JLG 대출 신청", "Bulk JLG Loan Application": "대량 JLG 대출 신청",
@@ -548,6 +549,7 @@
"View Journal Entries": "저널 항목 보기", "View Journal Entries": "저널 항목 보기",
"View Standing Instructions": "기립 지침 보기", "View Standing Instructions": "기립 지침 보기",
"View Transactions History": "거래 내역 보기", "View Transactions History": "거래 내역 보기",
"View Transactions": "거래 보기",
"Waive": "면제", "Waive": "면제",
"Waive Charge": "요금 면제", "Waive Charge": "요금 면제",
"Week": "주", "Week": "주",
@@ -927,6 +929,8 @@
"Assets / Liability": "자산/부채", "Assets / Liability": "자산/부채",
"Audit Trails": "감사 추적", "Audit Trails": "감사 추적",
"Balance": "균형", "Balance": "균형",
"Beneficiary": "수익자",
"Beneficiary Selection": "수익자 선택",
"Block Savings Account": "블록저축계좌", "Block Savings Account": "블록저축계좌",
"Bulk Import": "대량 가져오기", "Bulk Import": "대량 가져오기",
"Bulk Loan Reassignment": "대량대출 재할당", "Bulk Loan Reassignment": "대량대출 재할당",
@@ -1233,6 +1237,10 @@
"Transaction Reverted": "거래가 되돌려졌습니다.", "Transaction Reverted": "거래가 되돌려졌습니다.",
"Transactions": "업무", "Transactions": "업무",
"Transfer Details": "전송 세부 정보", "Transfer Details": "전송 세부 정보",
"Transfer Failed": "이체 실패",
"Transfer Status": "이체 상태",
"Transfer Successful": "이체 성공",
"Transfer Summary": "이체 요약",
"Transferred From": "다음에서 전송됨", "Transferred From": "다음에서 전송됨",
"Transferred To": "로 전송", "Transferred To": "로 전송",
"Transferring From Details": "세부정보에서 전송 중", "Transferring From Details": "세부정보에서 전송 중",
+8
View File
@@ -347,6 +347,7 @@
"Attach Meeting": "Pridėti susitikimą", "Attach Meeting": "Pridėti susitikimą",
"Attendance": "Lankomumas", "Attendance": "Lankomumas",
"Back": "Atgal", "Back": "Atgal",
"Back to Account": "Grįžti į sąskaitą",
"Bar Chart": "Juostinė diagrama", "Bar Chart": "Juostinė diagrama",
"Browse": "Naršyti", "Browse": "Naršyti",
"Bulk JLG Loan Application": "Masinės JLG paskolos paraiška", "Bulk JLG Loan Application": "Masinės JLG paskolos paraiška",
@@ -548,6 +549,7 @@
"View Journal Entries": "Peržiūrėkite žurnalo įrašus", "View Journal Entries": "Peržiūrėkite žurnalo įrašus",
"View Standing Instructions": "Peržiūrėkite nuolatines instrukcijas", "View Standing Instructions": "Peržiūrėkite nuolatines instrukcijas",
"View Transactions History": "Peržiūrėkite operacijų istoriją", "View Transactions History": "Peržiūrėkite operacijų istoriją",
"View Transactions": "Peržiūrėti operacijas",
"Waive": "Atsisakyti", "Waive": "Atsisakyti",
"Waive Charge": "Atsisakyti mokesčio", "Waive Charge": "Atsisakyti mokesčio",
"Week": "Savaitė", "Week": "Savaitė",
@@ -925,6 +927,8 @@
"Assets / Liability": "Turtas / įsipareigojimai", "Assets / Liability": "Turtas / įsipareigojimai",
"Audit Trails": "Audito takai", "Audit Trails": "Audito takai",
"Balance": "Balansas", "Balance": "Balansas",
"Beneficiary": "Gavėjas",
"Beneficiary Selection": "Gavėjo pasirinkimas",
"Block Savings Account": "Blokuoti taupomąją sąskaitą", "Block Savings Account": "Blokuoti taupomąją sąskaitą",
"Bulk Import": "Masinis importas", "Bulk Import": "Masinis importas",
"Bulk Loan Reassignment": "Masinės paskolos perskirstymas", "Bulk Loan Reassignment": "Masinės paskolos perskirstymas",
@@ -1230,6 +1234,10 @@
"Transaction Reverted": "Sandoris grąžintas", "Transaction Reverted": "Sandoris grąžintas",
"Transactions": "Sandoriai", "Transactions": "Sandoriai",
"Transfer Details": "Pervedimo informacija", "Transfer Details": "Pervedimo informacija",
"Transfer Failed": "Pervedimas nepavyko",
"Transfer Status": "Pervedimo būsena",
"Transfer Successful": "Pervedimas sėkmingas",
"Transfer Summary": "Pervedimo santrauka",
"Transferred From": "Perkelta iš", "Transferred From": "Perkelta iš",
"Transferred To": "Perkelta į", "Transferred To": "Perkelta į",
"Transferring From Details": "Perkėlimas iš detalių", "Transferring From Details": "Perkėlimas iš detalių",
+8
View File
@@ -347,6 +347,7 @@
"Attach Meeting": "Pievienot sapulci", "Attach Meeting": "Pievienot sapulci",
"Attendance": "Apmeklējums", "Attendance": "Apmeklējums",
"Back": "Atpakaļ", "Back": "Atpakaļ",
"Back to Account": "Atpakaļ uz kontu",
"Bar Chart": "Joslu diagramma", "Bar Chart": "Joslu diagramma",
"Browse": "Pārlūkot", "Browse": "Pārlūkot",
"Bulk JLG Loan Application": "Lielapjoma JLG aizdevuma pieteikums", "Bulk JLG Loan Application": "Lielapjoma JLG aizdevuma pieteikums",
@@ -548,6 +549,7 @@
"View Journal Entries": "Skatīt žurnāla ierakstus", "View Journal Entries": "Skatīt žurnāla ierakstus",
"View Standing Instructions": "Skatiet pastāvīgās instrukcijas", "View Standing Instructions": "Skatiet pastāvīgās instrukcijas",
"View Transactions History": "Skatiet darījumu vēsturi", "View Transactions History": "Skatiet darījumu vēsturi",
"View Transactions": "Skatīt darījumus",
"Waive": "Atteikties", "Waive": "Atteikties",
"Waive Charge": "Atteikties no maksas", "Waive Charge": "Atteikties no maksas",
"Week": "nedēļa", "Week": "nedēļa",
@@ -927,6 +929,8 @@
"Assets / Liability": "Aktīvi / Pasīvi", "Assets / Liability": "Aktīvi / Pasīvi",
"Audit Trails": "Revīzijas pēdas", "Audit Trails": "Revīzijas pēdas",
"Balance": "Līdzsvars", "Balance": "Līdzsvars",
"Beneficiary": "Saņēmējs",
"Beneficiary Selection": "Saņēmēja izvēle",
"Block Savings Account": "Bloķēt krājkontu", "Block Savings Account": "Bloķēt krājkontu",
"Bulk Import": "Lielapjoma importēšana", "Bulk Import": "Lielapjoma importēšana",
"Bulk Loan Reassignment": "Lielapjoma aizdevuma pārcelšana", "Bulk Loan Reassignment": "Lielapjoma aizdevuma pārcelšana",
@@ -1232,6 +1236,10 @@
"Transaction Reverted": "Darījums ir atsaukts", "Transaction Reverted": "Darījums ir atsaukts",
"Transactions": "Darījumi", "Transactions": "Darījumi",
"Transfer Details": "Pārskaitījuma informācija", "Transfer Details": "Pārskaitījuma informācija",
"Transfer Failed": "Pārskaitījums neizdevās",
"Transfer Status": "Pārskaitījuma statuss",
"Transfer Successful": "Pārskaitījums veiksmīgs",
"Transfer Summary": "Pārskaitījuma kopsavilkums",
"Transferred From": "Pārsūtīts no", "Transferred From": "Pārsūtīts no",
"Transferred To": "Pārsūtīts uz", "Transferred To": "Pārsūtīts uz",
"Transferring From Details": "Pārsūtīšana no detaļām", "Transferring From Details": "Pārsūtīšana no detaļām",
+8
View File
@@ -347,6 +347,7 @@
"Attach Meeting": "बैठक संलग्न गर्नुहोस्", "Attach Meeting": "बैठक संलग्न गर्नुहोस्",
"Attendance": "उपस्थित", "Attendance": "उपस्थित",
"Back": "पछाडि", "Back": "पछाडि",
"Back to Account": "खातामा फर्कनुहोस्",
"Bar Chart": "बार चार्ट", "Bar Chart": "बार चार्ट",
"Browse": "ब्राउज गर्नुहोस्", "Browse": "ब्राउज गर्नुहोस्",
"Bulk JLG Loan Application": "थोक JLG ऋण आवेदन", "Bulk JLG Loan Application": "थोक JLG ऋण आवेदन",
@@ -548,6 +549,7 @@
"View Journal Entries": "जर्नल प्रविष्टिहरू हेर्नुहोस्", "View Journal Entries": "जर्नल प्रविष्टिहरू हेर्नुहोस्",
"View Standing Instructions": "स्थायी निर्देशनहरू हेर्नुहोस्", "View Standing Instructions": "स्थायी निर्देशनहरू हेर्नुहोस्",
"View Transactions History": "लेनदेन इतिहास हेर्नुहोस्", "View Transactions History": "लेनदेन इतिहास हेर्नुहोस्",
"View Transactions": "लेनदेन हेर्नुहोस्",
"Waive": "छुट", "Waive": "छुट",
"Waive Charge": "शुल्क छुट", "Waive Charge": "शुल्क छुट",
"Week": "हप्ता", "Week": "हप्ता",
@@ -925,6 +927,8 @@
"Assets / Liability": "सम्पत्ति / दायित्व", "Assets / Liability": "सम्पत्ति / दायित्व",
"Audit Trails": "अडिट ट्रेलहरू", "Audit Trails": "अडिट ट्रेलहरू",
"Balance": "सन्तुलन", "Balance": "सन्तुलन",
"Beneficiary": "लाभग्राही",
"Beneficiary Selection": "लाभग्राही छनोट",
"Block Savings Account": "बचत खाता रोक्नुहोस्", "Block Savings Account": "बचत खाता रोक्नुहोस्",
"Bulk Import": "थोक आयात", "Bulk Import": "थोक आयात",
"Bulk Loan Reassignment": "बल्क ऋण पुन: असाइनमेन्ट", "Bulk Loan Reassignment": "बल्क ऋण पुन: असाइनमेन्ट",
@@ -1230,6 +1234,10 @@
"Transaction Reverted": "कारोबार फिर्ता गरियो", "Transaction Reverted": "कारोबार फिर्ता गरियो",
"Transactions": "लेनदेन", "Transactions": "लेनदेन",
"Transfer Details": "स्थानान्तरण विवरणहरू", "Transfer Details": "स्थानान्तरण विवरणहरू",
"Transfer Failed": "स्थानान्तरण असफल भयो",
"Transfer Status": "स्थानान्तरण स्थिति",
"Transfer Successful": "स्थानान्तरण सफल भयो",
"Transfer Summary": "स्थानान्तरण सारांश",
"Transferred From": "बाट स्थानान्तरण गरियो", "Transferred From": "बाट स्थानान्तरण गरियो",
"Transferred To": "मा हस्तान्तरण गरियो", "Transferred To": "मा हस्तान्तरण गरियो",
"Transferring From Details": "विवरणहरूबाट स्थानान्तरण गर्दै", "Transferring From Details": "विवरणहरूबाट स्थानान्तरण गर्दै",
+8
View File
@@ -347,6 +347,7 @@
"Attach Meeting": "Anexar reunião", "Attach Meeting": "Anexar reunião",
"Attendance": "Comparecimento", "Attendance": "Comparecimento",
"Back": "Voltar", "Back": "Voltar",
"Back to Account": "Voltar para a Conta",
"Bar Chart": "Gráfico de barras", "Bar Chart": "Gráfico de barras",
"Browse": "Navegar", "Browse": "Navegar",
"Bulk JLG Loan Application": "Solicitação de empréstimo JLG em massa", "Bulk JLG Loan Application": "Solicitação de empréstimo JLG em massa",
@@ -548,6 +549,7 @@
"View Journal Entries": "Ver lançamentos contábeis manuais", "View Journal Entries": "Ver lançamentos contábeis manuais",
"View Standing Instructions": "Ver instruções permanentes", "View Standing Instructions": "Ver instruções permanentes",
"View Transactions History": "Ver histórico de transações", "View Transactions History": "Ver histórico de transações",
"View Transactions": "Ver transações",
"Waive": "Renunciar", "Waive": "Renunciar",
"Waive Charge": "Isenção de cobrança", "Waive Charge": "Isenção de cobrança",
"Week": "Semana", "Week": "Semana",
@@ -927,6 +929,8 @@
"Assets / Liability": "Ativos/Passivos", "Assets / Liability": "Ativos/Passivos",
"Audit Trails": "Trilhas de auditoria", "Audit Trails": "Trilhas de auditoria",
"Balance": "Equilíbrio", "Balance": "Equilíbrio",
"Beneficiary": "Beneficiário",
"Beneficiary Selection": "Seleção de Beneficiário",
"Block Savings Account": "Bloquear conta poupança", "Block Savings Account": "Bloquear conta poupança",
"Bulk Import": "Importação em massa", "Bulk Import": "Importação em massa",
"Bulk Loan Reassignment": "Reatribuição de empréstimo em massa", "Bulk Loan Reassignment": "Reatribuição de empréstimo em massa",
@@ -1231,6 +1235,10 @@
"Transaction Reverted": "Transação revertida", "Transaction Reverted": "Transação revertida",
"Transactions": "Transações", "Transactions": "Transações",
"Transfer Details": "Detalhes da transferência", "Transfer Details": "Detalhes da transferência",
"Transfer Failed": "Transferência falhou",
"Transfer Status": "Status da transferência",
"Transfer Successful": "Transferência bem-sucedida",
"Transfer Summary": "Resumo da transferência",
"Transferred From": "Transferido de", "Transferred From": "Transferido de",
"Transferred To": "Transferido para", "Transferred To": "Transferido para",
"Transferring From Details": "Transferindo de detalhes", "Transferring From Details": "Transferindo de detalhes",
+9
View File
@@ -347,6 +347,7 @@
"Attach Meeting": "Ambatanisha Mkutano", "Attach Meeting": "Ambatanisha Mkutano",
"Attendance": "Mahudhurio", "Attendance": "Mahudhurio",
"Back": "Nyuma", "Back": "Nyuma",
"Back to Account": "Rudi kwa Akaunti",
"Bar Chart": "Chati ya Baa", "Bar Chart": "Chati ya Baa",
"Browse": "Vinjari", "Browse": "Vinjari",
"Bulk JLG Loan Application": "Maombi ya Mkopo wa Wingi wa JLG", "Bulk JLG Loan Application": "Maombi ya Mkopo wa Wingi wa JLG",
@@ -548,6 +549,7 @@
"View Journal Entries": "Tazama Maingizo ya Jarida", "View Journal Entries": "Tazama Maingizo ya Jarida",
"View Standing Instructions": "Tazama Maagizo ya Kudumu", "View Standing Instructions": "Tazama Maagizo ya Kudumu",
"View Transactions History": "Tazama Historia ya Shughuli", "View Transactions History": "Tazama Historia ya Shughuli",
"View Transactions": "Tazama Shughuli",
"Waive": "Acha", "Waive": "Acha",
"Waive Charge": "Kuondoa Malipo", "Waive Charge": "Kuondoa Malipo",
"Week": "Wiki", "Week": "Wiki",
@@ -925,6 +927,8 @@
"Assets / Liability": "Mali / Dhima", "Assets / Liability": "Mali / Dhima",
"Audit Trails": "Njia za Ukaguzi", "Audit Trails": "Njia za Ukaguzi",
"Balance": "Mizani", "Balance": "Mizani",
"Beneficiary": "Mnufaika",
"Beneficiary Selection": "Uchaguzi wa Mnufaika",
"Block Savings Account": "Zuia Akaunti ya Akiba", "Block Savings Account": "Zuia Akaunti ya Akiba",
"Bulk Import": "Ingiza Wingi", "Bulk Import": "Ingiza Wingi",
"Bulk Loan Reassignment": "Ugawaji upya wa mkopo kwa wingi", "Bulk Loan Reassignment": "Ugawaji upya wa mkopo kwa wingi",
@@ -1228,6 +1232,11 @@
"Transaction Details": "Maelezo ya Muamala", "Transaction Details": "Maelezo ya Muamala",
"Transaction Reverted": "Muamala Umerejeshwa", "Transaction Reverted": "Muamala Umerejeshwa",
"Transactions": "Shughuli", "Transactions": "Shughuli",
"Transfer Details": "Maelezo ya Uhamisho",
"Transfer Failed": "Uhamisho Umeshindwa",
"Transfer Status": "Hali ya Uhamisho",
"Transfer Successful": "Uhamisho Umefanikiwa",
"Transfer Summary": "Muhtasari wa Uhamisho",
"Transferred From": "Imehamishwa Kutoka", "Transferred From": "Imehamishwa Kutoka",
"Transferred To": "Imehamishwa Kwa", "Transferred To": "Imehamishwa Kwa",
"Transferring From Details": "Kuhamisha Kutoka kwa Maelezo", "Transferring From Details": "Kuhamisha Kutoka kwa Maelezo",