Upgrading to Angular 20:

Replaced checked in package-lock.json by regenerated one.
Ran ng update @angular/core@20 @angular/cli@20
Ran npm install @angular-builders/jest@^20.0.0 @fortawesome/angular-fontawesome@^3.0.0 @swimlane/ngx-graph@^11
Ran npm install ngx-mat-select-search@^8.0.2.
Ran ng update @angular/material@20.
Updated all eslint and typescript to the latest versions.
Removed @angular-devkit/schematics.
Updated fontawesome.
Updated rxjs and tslib.
Moved required node version from 16 to 20.
Updated jest-preset-angular.
Set preserveWhitespaces to false.
Corrected two type declarations in two typescript files to make ng serve run without errors.
Removed unused angular-devkit/schematics from view-user.component.ts .
Updated list of supported browsers.
Upgraded prettier.
Ran prettier . --write the first time.
Ran prettier . --write the second time.
Ran ng generate @angular/core:inject with defaults, excepted a handful of files.
Fixed remaining eslint problems.
Added dist directory to ignores in eslint.config.js.
Let prettier fix formatting, almost everything is just line breaks.
Made htmlhint ignore @if and @for Angular constructs.
Updated node version in Github workflow to 22.12.0 (build.yml).
Updated .env.ts.
Updated Angular datetime format strings from YYYY-MM-DD to yyyy-MM-dd.
Merged changes from dev into angular20 branch.
This commit is contained in:
Felix van Hove
2025-12-08 11:01:01 +01:00
parent f1b4ec2cf2
commit 7fd1486c08
1516 changed files with 39367 additions and 36037 deletions
@@ -1,4 +1,4 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { ExternalAssetOwnerService } from '../services/external-asset-owner.service';
@@ -7,10 +7,7 @@ import { ExternalAssetOwnerService } from '../services/external-asset-owner.serv
providedIn: 'root'
})
export class ExternalAssetOwnerActiveTransferResolver {
/**
* @param {ExternalAssetOwnerService} externalAssetOwnerService External Asset Owner service.
*/
constructor(private externalAssetOwnerService: ExternalAssetOwnerService) {}
private externalAssetOwnerService = inject(ExternalAssetOwnerService);
/**
* Returns the Loans with Association data.
@@ -1,4 +1,4 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
import { Observable, of } from 'rxjs';
import { ExternalAssetOwnerService } from '../services/external-asset-owner.service';
@@ -7,10 +7,7 @@ import { ExternalAssetOwnerService } from '../services/external-asset-owner.serv
providedIn: 'root'
})
export class ExternalAssetOwnerJournalEntryResolver {
/**
* @param {ExternalAssetOwnerService} externalAssetOwnerService External Asset Owner service.
*/
constructor(private externalAssetOwnerService: ExternalAssetOwnerService) {}
private externalAssetOwnerService = inject(ExternalAssetOwnerService);
/**
* Returns the Loans with Association data.
@@ -1,4 +1,4 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { ExternalAssetOwnerService } from '../services/external-asset-owner.service';
@@ -7,10 +7,7 @@ import { ExternalAssetOwnerService } from '../services/external-asset-owner.serv
providedIn: 'root'
})
export class ExternalAssetOwnerResolver {
/**
* @param {ExternalAssetOwnerService} externalAssetOwnerService External Asset Owner service.
*/
constructor(private externalAssetOwnerService: ExternalAssetOwnerService) {}
private externalAssetOwnerService = inject(ExternalAssetOwnerService);
/**
* Returns the Loans with Association data.
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
@@ -13,10 +13,7 @@ import { LoansService } from '../loans.service';
*/
@Injectable()
export class GLIMLoanTemplateResolver {
/**
* @param {ProductsService} loansService Loan service.
*/
constructor(private loansService: LoansService) {}
private loansService = inject(LoansService);
/**
* Returns the loan account template data.
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
@@ -13,10 +13,7 @@ import { LoansService } from '../loans.service';
*/
@Injectable()
export class LoanActionButtonResolver {
/**
* @param {LoansService} LoansService Loans service.
*/
constructor(private loansService: LoansService) {}
private loansService = inject(LoansService);
/**
* Returns the Loans Notes Data.
@@ -1,4 +1,4 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
import { SystemService } from 'app/system/system.service';
import { Observable } from 'rxjs';
@@ -7,10 +7,7 @@ import { Observable } from 'rxjs';
providedIn: 'root'
})
export class LoanArrearDelinquencyResolver {
/**
* @param {SystemService} systemService System service.
*/
constructor(private systemService: SystemService) {}
private systemService = inject(SystemService);
/**
* Returns the loan-arrears-delinquency-display-data configuration data.
@@ -1,11 +1,11 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { LoansService } from '../loans.service';
@Injectable()
export class LoanBuyDownFeesDataResolver implements Resolve<Object> {
constructor(private loansService: LoansService) {}
private loansService = inject(LoansService);
resolve(route: ActivatedRouteSnapshot): Observable<any> {
const loanId = route.paramMap.get('loanId') || route.parent.paramMap.get('loanId');
@@ -1,4 +1,4 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { LoansService } from '../loans.service';
@@ -7,10 +7,7 @@ import { LoansService } from '../loans.service';
providedIn: 'root'
})
export class LoanCollateralsResolver {
/**
* @param {LoansService} LoansService Loans service.
*/
constructor(private loansService: LoansService) {}
private loansService = inject(LoansService);
/**
* Returns the Loans data.
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
@@ -13,10 +13,7 @@ import { LoansService } from '../loans.service';
*/
@Injectable()
export class LoanDatatableResolver {
/**
* @param {LoansService} LoansService Loans service.
*/
constructor(private loansService: LoansService) {}
private loansService = inject(LoansService);
/**
* Returns the Loans Notes Data.
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
/** rxjs Imports */
import { Observable } from 'rxjs';
@@ -12,10 +12,7 @@ import { LoansService } from '../loans.service';
*/
@Injectable()
export class LoanDatatablesResolver {
/**
* @param {loansService} loansService loans service.
*/
constructor(private loansService: LoansService) {}
private loansService = inject(LoansService);
/**
* Returns the loan datatables.
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
@@ -13,10 +13,7 @@ import { LoansService } from '../loans.service';
*/
@Injectable()
export class LoanDeferredIncomeDataResolver {
/**
* @param {LoansService} LoansService Loans service.
*/
constructor(private loansService: LoansService) {}
private loansService = inject(LoansService);
/**
* Returns the Loans with Association data.
@@ -1,4 +1,4 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { LoansService } from '../loans.service';
@@ -7,10 +7,7 @@ import { LoansService } from '../loans.service';
providedIn: 'root'
})
export class LoanDelinquencyActionsResolver {
/**
* @param {LoansService} LoansService Loans service.
*/
constructor(private loansService: LoansService) {}
private loansService = inject(LoansService);
/**
* Returns the Loans with Association data.
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
@@ -13,10 +13,7 @@ import { LoansService } from '../loans.service';
*/
@Injectable()
export class LoanDelinquencyDataResolver {
/**
* @param {LoansService} LoansService Loans service.
*/
constructor(private loansService: LoansService) {}
private loansService = inject(LoansService);
/**
* Returns the Loans with Association data.
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
@@ -13,10 +13,7 @@ import { LoansService } from '../loans.service';
*/
@Injectable()
export class LoanDelinquencyTagsResolver {
/**
* @param {LoansService} LoansService Loans service.
*/
constructor(private loansService: LoansService) {}
private loansService = inject(LoansService);
/**
* Returns the Loans with Association data.
@@ -16,6 +16,7 @@ export class LoanDetailsChargesResolver implements Resolve<Object> {
/**
* @param {LoansService} LoansService Loans service.
*/
// eslint-disable-next-line @angular-eslint/prefer-inject
constructor(private loansService: LoansService) {}
/**
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
@@ -13,10 +13,7 @@ import { LoansService } from '../loans.service';
*/
@Injectable()
export class LoanDetailsResolver {
/**
* @param {LoansService} LoansService Loans service.
*/
constructor(private loansService: LoansService) {}
private loansService = inject(LoansService);
/**
* Returns the Loans with Association data.
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
@@ -13,10 +13,7 @@ import { LoansService } from '../loans.service';
*/
@Injectable()
export class LoanDocumentsResolver {
/**
* @param {LoansService} LoansService Loans service.
*/
constructor(private loansService: LoansService) {}
private loansService = inject(LoansService);
/**
* Returns the Loans data.
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
@@ -13,10 +13,7 @@ import { LoansService } from '../loans.service';
*/
@Injectable()
export class LoanNotesResolver {
/**
* @param {LoansService} LoansService Loans service.
*/
constructor(private loansService: LoansService) {}
private loansService = inject(LoansService);
/**
* Returns the Loans data.
@@ -1,4 +1,4 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { Router, RouterStateSnapshot, ActivatedRouteSnapshot } from '@angular/router';
import { Observable, of } from 'rxjs';
import { LoansService } from '../loans.service';
@@ -7,10 +7,7 @@ import { LoansService } from '../loans.service';
providedIn: 'root'
})
export class LoanReschedulesResolver {
/**
* @param {LoansService} LoansService Loans service.
*/
constructor(private loansService: LoansService) {}
private loansService = inject(LoansService);
/**
* Returns the Loans data.
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
@@ -13,10 +13,7 @@ import { LoansService } from '../loans.service';
*/
@Injectable()
export class LoanTermVariationsResolver {
/**
* @param {LoansService} LoansService Loans service.
*/
constructor(private loansService: LoansService) {}
private loansService = inject(LoansService);
/**
* Returns the Loans with Association data.
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
@@ -13,10 +13,7 @@ import { LoansService } from '../loans.service';
*/
@Injectable()
export class LoansAccountAndTemplateResolver {
/**
* @param {ProductsService} productsService Products service.
*/
constructor(private loansService: LoansService) {}
private loansService = inject(LoansService);
/**
* Returns the loan account template data.
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
@@ -13,10 +13,7 @@ import { LoansService } from '../loans.service';
*/
@Injectable()
export class LoansAccountChargeResolver {
/**
* @param {LoansService} LoansService Loans service.
*/
constructor(private loansService: LoansService) {}
private loansService = inject(LoansService);
/**
* Returns the Loans Account Charge data.
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
@@ -13,10 +13,7 @@ import { LoansService } from '../loans.service';
*/
@Injectable()
export class LoansAccountTemplateResolver {
/**
* @param {ProductsService} productsService Products service.
*/
constructor(private loansService: LoansService) {}
private loansService = inject(LoansService);
/**
* Returns the loan account template data.
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
@@ -13,10 +13,7 @@ import { LoansService } from '../loans.service';
*/
@Injectable()
export class LoansAccountTransactionTemplateResolver {
/**
* @param {LoansService} LoansService Loans service.
*/
constructor(private loansService: LoansService) {}
private loansService = inject(LoansService);
/**
* Returns the Loans Account Transaction Template data.
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
@@ -13,10 +13,7 @@ import { LoansService } from '../loans.service';
*/
@Injectable()
export class LoansAccountTransactionResolver {
/**
* @param {LoansService} LoansService Loans service.
*/
constructor(private loansService: LoansService) {}
private loansService = inject(LoansService);
/**
* Returns the Loans Account Transaction data.
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
@@ -13,10 +13,7 @@ import { ReportsService } from 'app/reports/reports.service';
*/
@Injectable()
export class LoansTransactionRecieptResolver {
/**
* @param {ReportsService} reportsService Reports service.
*/
constructor(private reportsService: ReportsService) {}
private reportsService = inject(ReportsService);
/**
* Returns the Loans Transaction Reciept
@@ -64,35 +64,38 @@
</mifosx-loans-account-charges-step>
</mat-step>
<mat-step state="repayment" *ngIf="loansAccountFormValid" completed>
<ng-template matStepLabel>{{ 'labels.inputs.REPAYMENT SCHEDULE' | translate }}</ng-template>
@if (loansAccountFormValid) {
<mat-step state="repayment" completed>
<ng-template matStepLabel>{{ 'labels.inputs.REPAYMENT SCHEDULE' | translate }}</ng-template>
<mifosx-loans-account-schedule-step
#loanAccountSchedule
[loansAccountTemplate]="loansAccountTemplate"
[loansAccountProductTemplate]="loansAccountProductTemplate"
[loansAccount]="loansAccount"
[currencyCode]="currencyCode"
>
</mifosx-loans-account-schedule-step>
</mat-step>
}
<mifosx-loans-account-schedule-step
#loanAccountSchedule
[loansAccountTemplate]="loansAccountTemplate"
[loansAccountProductTemplate]="loansAccountProductTemplate"
[loansAccount]="loansAccount"
[currencyCode]="currencyCode"
>
</mifosx-loans-account-schedule-step>
</mat-step>
@for (datatable of datatables; track datatable) {
<mat-step>
<ng-template matStepLabel>{{ datatable.registeredTableName }}</ng-template>
<mifosx-loans-account-datatable-step [datatableData]="datatable" #dtloan></mifosx-loans-account-datatable-step>
</mat-step>
}
<mat-step *ngFor="let datatable of datatables">
<ng-template matStepLabel>{{ datatable.registeredTableName }}</ng-template>
<mifosx-loans-account-datatable-step [datatableData]="datatable" #dtloan></mifosx-loans-account-datatable-step>
</mat-step>
<mat-step state="preview" *ngIf="loansAccountFormValid" completed>
<ng-template matStepLabel>{{ 'labels.inputs.PREVIEW' | translate }}</ng-template>
<mifosx-loans-account-preview-step
[loansAccountTemplate]="loansAccountTemplate"
[loansAccountProductTemplate]="loansAccountProductTemplate"
[loansAccount]="loansAccount"
(submitEvent)="submit()"
>
</mifosx-loans-account-preview-step>
</mat-step>
@if (loansAccountFormValid) {
<mat-step state="preview" completed>
<ng-template matStepLabel>{{ 'labels.inputs.PREVIEW' | translate }}</ng-template>
<mifosx-loans-account-preview-step
[loansAccountTemplate]="loansAccountTemplate"
[loansAccountProductTemplate]="loansAccountProductTemplate"
[loansAccount]="loansAccount"
(submitEvent)="submit()"
>
</mifosx-loans-account-preview-step>
</mat-step>
}
</mat-stepper>
</div>
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Component, QueryList, ViewChild, ViewChildren } from '@angular/core';
import { Component, QueryList, ViewChild, ViewChildren, inject } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
/** Custom Services */
@@ -41,6 +41,12 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class CreateLoansAccountComponent {
private route = inject(ActivatedRoute);
private router = inject(Router);
private loansService = inject(LoansService);
private settingsService = inject(SettingsService);
private clientService = inject(ClientsService);
/** Imports all the step component */
@ViewChild(LoansAccountDetailsStepComponent, { static: true })
loansAccountDetailsStep: LoansAccountDetailsStepComponent;
@@ -72,13 +78,7 @@ export class CreateLoansAccountComponent {
* @param {SettingsService} settingsService Settings Service
* @param {ClientsService} clientService Client Service
*/
constructor(
private route: ActivatedRoute,
private router: Router,
private loansService: LoansService,
private settingsService: SettingsService,
private clientService: ClientsService
) {
constructor() {
this.route.data.subscribe((data: { loansAccountTemplate: any }) => {
this.loansAccountTemplate = data.loansAccountTemplate;
});
@@ -13,10 +13,12 @@
/>
<mat-datepicker-toggle matSuffix [for]="validFromDatePicker"></mat-datepicker-toggle>
<mat-datepicker #validFromDatePicker></mat-datepicker>
<mat-error *ngIf="delinquencyActionForm.controls.startDate.hasError('required')">
{{ 'labels.inputs.Start Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (delinquencyActionForm.controls.startDate.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Start Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field class="flex-48" (click)="validTillDatePicker.open()">
@@ -31,10 +33,12 @@
/>
<mat-datepicker-toggle matSuffix [for]="validTillDatePicker"></mat-datepicker-toggle>
<mat-datepicker #validTillDatePicker></mat-datepicker>
<mat-error *ngIf="delinquencyActionForm.controls.endDate.hasError('required')">
{{ 'labels.inputs.End Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (delinquencyActionForm.controls.endDate.hasError('required')) {
<mat-error>
{{ 'labels.inputs.End Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
</div>
@@ -1,4 +1,4 @@
import { Component, Inject } from '@angular/core';
import { Component, inject } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
import {
MAT_DIALOG_DATA,
@@ -25,17 +25,17 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class LoanDelinquencyActionDialogComponent {
dialogRef = inject<MatDialogRef<LoanDelinquencyActionDialogComponent>>(MatDialogRef);
data = inject(MAT_DIALOG_DATA);
private formBuilder = inject(UntypedFormBuilder);
delinquencyActionForm: UntypedFormGroup;
/** Minimum date allowed. */
minDate = new Date(2000, 0, 1);
/** Maximum date allowed. */
maxDate = new Date(2100, 0, 1);
constructor(
public dialogRef: MatDialogRef<LoanDelinquencyActionDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any,
private formBuilder: UntypedFormBuilder
) {
constructor() {
this.createDelinquencyActionForm();
}
@@ -4,9 +4,11 @@
<mat-form-field>
<mat-label>{{ 'labels.inputs.Collateral' | translate }}</mat-label>
<mat-select formControlName="collateral" required>
<mat-option *ngFor="let collateralType of collateralTypeData" [value]="collateralType">
{{ collateralType.name }}
</mat-option>
@for (collateralType of collateralTypeData; track collateralType) {
<mat-option [value]="collateralType">
{{ collateralType.name }}
</mat-option>
}
</mat-select>
<mat-error>
{{ 'labels.inputs.Collateral' | translate }} {{ 'labels.commons.is' | translate }}
@@ -17,13 +19,17 @@
<mat-form-field>
<mat-label>{{ 'labels.inputs.Quantity' | translate }}</mat-label>
<input type="number" [max]="maxQuantity" [min]="0" matInput formControlName="quantity" required />
<mat-error *ngIf="addCollateralForm.controls.quantity.hasError('required')">
{{ 'labels.inputs.Quantity' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
<mat-error *ngIf="addCollateralForm.controls.quantity.hasError('max')">
{{ 'labels.inputs.Quantity can not be more than' | translate }} <strong>{{ maxQuantity }}</strong>
</mat-error>
@if (addCollateralForm.controls.quantity.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Quantity' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
@if (addCollateralForm.controls.quantity.hasError('max')) {
<mat-error>
{{ 'labels.inputs.Quantity can not be more than' | translate }} <strong>{{ maxQuantity }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field>
@@ -1,4 +1,4 @@
import { Component, OnInit, Inject } from '@angular/core';
import { Component, OnInit, inject } from '@angular/core';
import {
MatDialogRef,
MAT_DIALOG_DATA,
@@ -25,6 +25,10 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class LoansAccountAddCollateralDialogComponent implements OnInit {
dialogRef = inject<MatDialogRef<LoansAccountAddCollateralDialogComponent>>(MatDialogRef);
data = inject(MAT_DIALOG_DATA);
private formBuilder = inject(UntypedFormBuilder);
layout: {
addButtonText?: string;
} = {
@@ -39,11 +43,7 @@ export class LoansAccountAddCollateralDialogComponent implements OnInit {
/** Maximum ALlowed Quantity of selected collateral */
maxQuantity: any = 0;
constructor(
public dialogRef: MatDialogRef<LoansAccountAddCollateralDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any,
private formBuilder: UntypedFormBuilder
) {
constructor() {
this.createAddCollateralForm();
}
@@ -25,20 +25,28 @@
<div class="flex-fill">
<span class="flex-50">{{ 'labels.inputs.Status' | translate }}:</span>
<span class="flex-50">
<span *ngIf="data.guarantorData.status">
{{ 'labels.inputs.Active' | translate }}
</span>
<span *ngIf="!data.guarantorData.status">
{{ 'labels.inputs.Deleted' | translate }}
</span></span
>
</div>
<div class="flex-fill" *ngIf="data.loanData?.delinquent?.availableDisbursementAmountWithOverApplied !== undefined">
<span class="flex-50">{{ 'labels.inputs.Available Disbursement Amount (with Over Applied)' | translate }}:</span>
<span class="flex-50">{{
data.loanData.delinquent.availableDisbursementAmountWithOverApplied | formatNumber
}}</span>
@if (data.guarantorData.status) {
<span>
{{ 'labels.inputs.Active' | translate }}
</span>
}
@if (!data.guarantorData.status) {
<span>
{{ 'labels.inputs.Deleted' | translate }}
</span>
}
</span>
</div>
@if (data.loanData?.delinquent?.availableDisbursementAmountWithOverApplied !== undefined) {
<div class="flex-fill">
<span class="flex-50"
>{{ 'labels.inputs.Available Disbursement Amount (with Over Applied)' | translate }}:</span
>
<span class="flex-50">{{
data.loanData.delinquent.availableDisbursementAmountWithOverApplied | formatNumber
}}</span>
</div>
}
</div>
</div>
@@ -1,4 +1,4 @@
import { Component, OnInit, Inject } from '@angular/core';
import { Component, OnInit, inject } from '@angular/core';
import {
MatDialogRef,
MAT_DIALOG_DATA,
@@ -24,10 +24,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class LoansAccountViewGuarantorDetailsDialogComponent implements OnInit {
constructor(
public dialogRef: MatDialogRef<LoansAccountViewGuarantorDetailsDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any
) {}
dialogRef = inject<MatDialogRef<LoansAccountViewGuarantorDetailsDialogComponent>>(MatDialogRef);
data = inject(MAT_DIALOG_DATA);
ngOnInit() {
this.dialogRef.updateSize('400px');
@@ -70,16 +70,17 @@
</mifosx-loans-account-schedule-step>
</mat-step>
<mat-step state="preview" *ngIf="loansAccountFormValidAndNotPristine" completed>
<ng-template matStepLabel>{{ 'labels.inputs.PREVIEW' | translate }}</ng-template>
<mifosx-loans-account-preview-step
[loansAccountTemplate]="loansAccountAndTemplate"
[loansAccountProductTemplate]="loansAccountProductTemplate"
[loansAccount]="loansAccount"
(submitEvent)="submit()"
>
</mifosx-loans-account-preview-step>
</mat-step>
@if (loansAccountFormValidAndNotPristine) {
<mat-step state="preview" completed>
<ng-template matStepLabel>{{ 'labels.inputs.PREVIEW' | translate }}</ng-template>
<mifosx-loans-account-preview-step
[loansAccountTemplate]="loansAccountAndTemplate"
[loansAccountProductTemplate]="loansAccountProductTemplate"
[loansAccount]="loansAccount"
(submitEvent)="submit()"
>
</mifosx-loans-account-preview-step>
</mat-step>
}
</mat-stepper>
</div>
@@ -1,4 +1,4 @@
import { Component, ViewChild } from '@angular/core';
import { Component, ViewChild, inject } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { LoansService } from '../loans.service';
import { LoansAccountDetailsStepComponent } from '../loans-account-stepper/loans-account-details-step/loans-account-details-step.component';
@@ -36,6 +36,12 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class EditLoansAccountComponent {
private route = inject(ActivatedRoute);
private router = inject(Router);
private dateUtils = inject(Dates);
private loansService = inject(LoansService);
private settingsService = inject(SettingsService);
@ViewChild(LoansAccountDetailsStepComponent, { static: true })
loansAccountDetailsStep: LoansAccountDetailsStepComponent;
@ViewChild(LoansAccountTermsStepComponent, { static: true }) loansAccountTermsStep: LoansAccountTermsStepComponent;
@@ -60,13 +66,7 @@ export class EditLoansAccountComponent {
* @param {loansService} LoansService Loans Service
* @param {SettingsService} settingsService Settings Service
*/
constructor(
private route: ActivatedRoute,
private router: Router,
private dateUtils: Dates,
private loansService: LoansService,
private settingsService: SettingsService
) {
constructor() {
this.route.data.subscribe((data: { loansAccountAndTemplate: any }) => {
this.loansAccountAndTemplate = data.loansAccountAndTemplate;
});
@@ -71,36 +71,39 @@
</mifosx-loans-active-client-members>
</mat-step>
<mat-step state="repayment" *ngIf="loansAccountFormValid" completed>
<ng-template matStepLabel>{{ 'labels.inputs.REPAYMENT SCHEDULE' | translate }}</ng-template>
@if (loansAccountFormValid) {
<mat-step state="repayment" completed>
<ng-template matStepLabel>{{ 'labels.inputs.REPAYMENT SCHEDULE' | translate }}</ng-template>
<mifosx-loans-account-schedule-step
#loanAccountSchedule
[loansAccountTemplate]="loansAccountTemplate"
[loansAccountProductTemplate]="loansAccountProductTemplate"
[loansAccount]="loansAccount"
[currencyCode]="currencyCode"
>
</mifosx-loans-account-schedule-step>
</mat-step>
}
<mifosx-loans-account-schedule-step
#loanAccountSchedule
[loansAccountTemplate]="loansAccountTemplate"
[loansAccountProductTemplate]="loansAccountProductTemplate"
[loansAccount]="loansAccount"
[currencyCode]="currencyCode"
>
</mifosx-loans-account-schedule-step>
</mat-step>
@for (datatable of datatables; track datatable) {
<mat-step>
<ng-template matStepLabel>{{ datatable.registeredTableName }}</ng-template>
<mifosx-loans-account-datatable-step [datatableData]="datatable" #dtloan></mifosx-loans-account-datatable-step>
</mat-step>
}
<mat-step *ngFor="let datatable of datatables">
<ng-template matStepLabel>{{ datatable.registeredTableName }}</ng-template>
<mifosx-loans-account-datatable-step [datatableData]="datatable" #dtloan></mifosx-loans-account-datatable-step>
</mat-step>
<mat-step state="preview" *ngIf="loansAccountFormValid" completed>
<ng-template matStepLabel>{{ 'labels.inputs.PREVIEW' | translate }}</ng-template>
<mifosx-loans-account-preview-step
[loansAccountTemplate]="loansAccountTemplate"
[loansAccountProductTemplate]="loansAccountProductTemplate"
[loansAccount]="loansAccount"
[activeClientMembers]="activeClientMembers"
(submitEvent)="submit()"
>
</mifosx-loans-account-preview-step>
</mat-step>
@if (loansAccountFormValid) {
<mat-step state="preview" completed>
<ng-template matStepLabel>{{ 'labels.inputs.PREVIEW' | translate }}</ng-template>
<mifosx-loans-account-preview-step
[loansAccountTemplate]="loansAccountTemplate"
[loansAccountProductTemplate]="loansAccountProductTemplate"
[loansAccount]="loansAccount"
[activeClientMembers]="activeClientMembers"
(submitEvent)="submit()"
>
</mifosx-loans-account-preview-step>
</mat-step>
}
</mat-stepper>
</div>
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Component, QueryList, ViewChild, ViewChildren } from '@angular/core';
import { Component, QueryList, ViewChild, ViewChildren, inject } from '@angular/core';
import { I18nService } from 'app/core/i18n/i18n.service';
import { ActivatedRoute, Router } from '@angular/router';
@@ -42,6 +42,14 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class CreateGlimAccountComponent {
private route = inject(ActivatedRoute);
private router = inject(Router);
private loansService = inject(LoansService);
private settingsService = inject(SettingsService);
private clientService = inject(ClientsService);
private dateUtils = inject(Dates);
private i18nService = inject(I18nService);
/** Imports all the step component */
@ViewChild(LoansAccountDetailsStepComponent, { static: true })
loansAccountDetailsStep: LoansAccountDetailsStepComponent;
@@ -79,15 +87,7 @@ export class CreateGlimAccountComponent {
* @param {SettingsService} settingsService Settings Service
* @param {ClientsService} clientService Client Service
*/
constructor(
private route: ActivatedRoute,
private router: Router,
private loansService: LoansService,
private settingsService: SettingsService,
private clientService: ClientsService,
private dateUtils: Dates,
private i18nService: I18nService
) {
constructor() {
this.route.data.subscribe((data: { loansAccountTemplate: any; groupsData: any }) => {
this.loansAccountTemplate = data.loansAccountTemplate;
this.dataSource = data.groupsData.activeClientMembers;
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
@@ -13,10 +13,7 @@ import { LoansService } from '../loans.service';
*/
@Injectable()
export class GLIMViewResolver {
/**
* @param {LoansService} loansService Loans service.
*/
constructor(private loansService: LoansService) {}
private loansService = inject(LoansService);
/**
* Returns the Savings Account data.
@@ -1,4 +1,4 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { Component, OnInit, ViewChild, inject } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { MatPaginator } from '@angular/material/paginator';
import {
@@ -40,6 +40,9 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class GlimAccountComponent implements OnInit {
private route = inject(ActivatedRoute);
dialog = inject(MatDialog);
/** Columns to be displayed in GLIM overview table. */
displayedColumns: string[] = [
'loanId',
@@ -62,10 +65,7 @@ export class GlimAccountComponent implements OnInit {
* @param {ActivatedRoute} route Activated Route.
* @param {MatDialog} dialog Dialog reference.
*/
constructor(
private route: ActivatedRoute,
public dialog: MatDialog
) {
constructor() {
this.route.data.subscribe((data: { glimData: any }) => {
this.glimOverviewData = data.glimData;
});
@@ -2,9 +2,11 @@
<mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.Charge' | translate }}</mat-label>
<mat-select #charge>
<mat-option *ngFor="let charge of chargeData" [value]="charge">
{{ charge.name }}
</mat-option>
@for (charge of chargeData; track charge) {
<mat-option [value]="charge">
{{ charge.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
@@ -55,38 +57,37 @@
<ng-container matColumnDef="date">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Date' | translate }}</th>
<td mat-cell *matCellDef="let charge">
<span
*ngIf="charge.chargeTimeType.value === 'Specified due date' || charge.chargeTimeType.value === 'Weekly Fee'"
>
{{ (charge.dueDate | dateFormat) || 'Unassigned' }}
</span>
<span *ngIf="charge.chargeTimeType.value === 'Monthly Fee' || charge.chargeTimeType.value === 'Annual Fee'">
{{ (charge.feeOnMonthDay | dateFormat) || 'Unassigned' }}
</span>
<span
*ngIf="
!(
charge.chargeTimeType.value === 'Monthly Fee' ||
charge.chargeTimeType.value === 'Annual Fee' ||
charge.chargeTimeType.value === 'Specified due date' ||
charge.chargeTimeType.value === 'Weekly Fee'
)
"
>
{{ 'labels.inputs.N/A' | translate }}
</span>
<button
mat-icon-button
color="primary"
*ngIf="
charge.chargeTimeType.value === 'Weekly Fee' ||
@if (charge.chargeTimeType.value === 'Specified due date' || charge.chargeTimeType.value === 'Weekly Fee') {
<span>
{{ (charge.dueDate | dateFormat) || 'Unassigned' }}
</span>
}
@if (charge.chargeTimeType.value === 'Monthly Fee' || charge.chargeTimeType.value === 'Annual Fee') {
<span>
{{ (charge.feeOnMonthDay | dateFormat) || 'Unassigned' }}
</span>
}
@if (
!(
charge.chargeTimeType.value === 'Monthly Fee' ||
charge.chargeTimeType.value === 'Annual Fee' ||
charge.chargeTimeType.value === 'Specified due date'
"
(click)="editChargeDate(charge)"
>
<fa-icon icon="pen"></fa-icon>
</button>
charge.chargeTimeType.value === 'Specified due date' ||
charge.chargeTimeType.value === 'Weekly Fee'
)
) {
<span>
{{ 'labels.inputs.N/A' | translate }}
</span>
}
@if (
charge.chargeTimeType.value === 'Weekly Fee' ||
charge.chargeTimeType.value === 'Annual Fee' ||
charge.chargeTimeType.value === 'Specified due date'
) {
<button mat-icon-button color="primary" (click)="editChargeDate(charge)">
<fa-icon icon="pen"></fa-icon>
</button>
}
</td>
</ng-container>
@@ -142,7 +143,9 @@
{{ 'labels.buttons.Next' | translate }}
<fa-icon icon="arrow-right" class="m-l-10"></fa-icon>
</button>
<button mat-raised-button *ngIf="loanId" [routerLink]="['../', 'general']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
@if (loanId) {
<button mat-raised-button [routerLink]="['../', 'general']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
}
</div>
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Component, OnInit, Input, OnChanges } from '@angular/core';
import { Component, OnInit, Input, OnChanges, inject } from '@angular/core';
// import { FormControl } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import {
@@ -65,6 +65,11 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class LoansAccountChargesStepComponent implements OnInit, OnChanges {
dialog = inject(MatDialog);
private dateUtils = inject(Dates);
private route = inject(ActivatedRoute);
private settingsService = inject(SettingsService);
// @Input loansAccountProductTemplate: LoansAccountProductTemplate
@Input() loansAccountProductTemplate: any;
// @Imput loansAccountTemplate: LoansAccountTemplate
@@ -128,12 +133,7 @@ export class LoansAccountChargesStepComponent implements OnInit, OnChanges {
* @param {Dates} dateUtils Date Utils
* @param {SettingsService} settingsService Settings Service
*/
constructor(
public dialog: MatDialog,
private dateUtils: Dates,
private route: ActivatedRoute,
private settingsService: SettingsService
) {
constructor() {
this.loanId = this.route.snapshot.params['loanId'];
}
@@ -218,7 +218,6 @@ export class LoansAccountChargesStepComponent implements OnInit, OnChanges {
type: 'number',
required: false
})
];
const data = {
title: 'Edit Charge Amount',
@@ -249,7 +248,6 @@ export class LoansAccountChargesStepComponent implements OnInit, OnChanges {
type: 'datetime-local',
required: false
})
];
const data = {
title: 'Edit Charge Date',
@@ -291,7 +289,6 @@ export class LoansAccountChargesStepComponent implements OnInit, OnChanges {
type: 'text',
required: false
})
];
const data = {
title: 'Edit Charge Fee Interval',
@@ -1,58 +1,49 @@
<form [formGroup]="datatableForm">
<div class="layout-row-wrap gap-2px responsive-column">
<div *ngFor="let datatableInput of datatableInputs" class="flex-48">
<mat-form-field class="flex-100" *ngIf="!isBoolean(datatableInput.columnDisplayType)">
<mat-label>{{ getInputName(datatableInput) }}</mat-label>
<mat-select
*ngIf="isDropdown(datatableInput.columnDisplayType)"
formControlName="{{ datatableInput.controlName }}"
>
<mat-option *ngFor="let code of datatableInput.columnValues" [value]="code.id">
{{ code.value }}
</mat-option>
</mat-select>
<input
matInput
type="number"
*ngIf="isNumeric(datatableInput.columnDisplayType)"
formControlName="{{ datatableInput.controlName }}"
/>
<input
matInput
*ngIf="isString(datatableInput.columnDisplayType)"
formControlName="{{ datatableInput.controlName }}"
/>
<textarea
matInput
*ngIf="isText(datatableInput.columnDisplayType)"
formControlName="{{ datatableInput.controlName }}"
></textarea>
<span *ngIf="isDate(datatableInput.columnDisplayType)" (click)="datePicker.open()">
<input
matInput
[matDatepicker]="datePicker"
formControlName="{{ datatableInput.controlName }}"
class="date-picker"
/>
<mat-datepicker-toggle matSuffix [for]="datePicker"></mat-datepicker-toggle>
<mat-datepicker #datePicker></mat-datepicker>
</span>
</mat-form-field>
<mat-checkbox
*ngIf="isBoolean(datatableInput.columnDisplayType)"
formControlName="{{ datatableInput.controlName }}"
labelPosition="before"
class="margin-v"
>
{{ getInputName(datatableInput) }}
</mat-checkbox>
</div>
@for (datatableInput of datatableInputs; track datatableInput) {
<div class="flex-48">
@if (!isBoolean(datatableInput.columnDisplayType)) {
<mat-form-field class="flex-100">
<mat-label>{{ getInputName(datatableInput) }}</mat-label>
@if (isDropdown(datatableInput.columnDisplayType)) {
<mat-select formControlName="{{ datatableInput.controlName }}">
@for (code of datatableInput.columnValues; track code) {
<mat-option [value]="code.id">
{{ code.value }}
</mat-option>
}
</mat-select>
}
@if (isNumeric(datatableInput.columnDisplayType)) {
<input matInput type="number" formControlName="{{ datatableInput.controlName }}" />
}
@if (isString(datatableInput.columnDisplayType)) {
<input matInput formControlName="{{ datatableInput.controlName }}" />
}
@if (isText(datatableInput.columnDisplayType)) {
<textarea matInput formControlName="{{ datatableInput.controlName }}"></textarea>
}
@if (isDate(datatableInput.columnDisplayType)) {
<span (click)="datePicker.open()">
<input
matInput
[matDatepicker]="datePicker"
formControlName="{{ datatableInput.controlName }}"
class="date-picker"
/>
<mat-datepicker-toggle matSuffix [for]="datePicker"></mat-datepicker-toggle>
<mat-datepicker #datePicker></mat-datepicker>
</span>
}
</mat-form-field>
}
@if (isBoolean(datatableInput.columnDisplayType)) {
<mat-checkbox formControlName="{{ datatableInput.controlName }}" labelPosition="before" class="margin-v">
{{ getInputName(datatableInput) }}
</mat-checkbox>
}
</div>
}
</div>
<div class="layout-row align-center gap-2percent margin-t responsive-column">
@@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core';
import { Component, Input, OnInit, inject } from '@angular/core';
import {
UntypedFormBuilder,
UntypedFormControl,
@@ -26,6 +26,10 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class LoansAccountDatatableStepComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private settingsService = inject(SettingsService);
private dateUtils = inject(Dates);
/** Input Fields Data */
@Input() datatableData: any;
/** Create Input Form */
@@ -33,12 +37,6 @@ export class LoansAccountDatatableStepComponent implements OnInit {
datatableInputs: any = [];
constructor(
private formBuilder: UntypedFormBuilder,
private settingsService: SettingsService,
private dateUtils: Dates
) {}
ngOnInit(): void {
this.datatableInputs = this.datatableData.columnHeaderData.filter((column: any) => {
return (
@@ -14,9 +14,11 @@
[formControl]="filterFormCtrl"
></ngx-mat-select-search>
</mat-option>
<mat-option *ngFor="let product of productData | async" [value]="product.id">
{{ product.name }}
</mat-option>
@for (product of productData | async; track product) {
<mat-option [value]="product.id">
{{ product.name }}
</mat-option>
}
</mat-select>
<mat-error>
{{ 'labels.inputs.Product Name' | translate }} {{ 'labels.commons.is' | translate }}
@@ -25,97 +27,108 @@
</mat-form-field>
</div>
<div class="layout-row-wrap layout-lt-md-column gap-2percent" *ngIf="loanProductSelected">
<mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.External id' | translate }}</mat-label>
<input matInput formControlName="externalId" matTooltip="{{ 'tooltips.Provides an external id' | translate }}" />
</mat-form-field>
<mat-form-field class="flex-48" *ngIf="loanProductSelected">
<mat-label>{{ 'labels.inputs.Loan officer' | translate }}</mat-label>
<mat-select
formControlName="loanOfficerId"
matTooltip="{{ 'tooltips.Financial institution representative' | translate }}"
>
<mat-option *ngFor="let loanOfficer of loanOfficerOptions" [value]="loanOfficer.id">
{{ loanOfficer.displayName }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.Loan Purpose' | translate }}</mat-label>
<mat-select formControlName="loanPurposeId" matTooltip="{{ 'tooltips.Provides an indication' | translate }}">
<mat-option *ngFor="let loanPurpose of loanPurposeOptions" [value]="loanPurpose.id">
{{ loanPurpose.name }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.Fund' | translate }}</mat-label>
<mat-select formControlName="fundId">
<mat-option *ngFor="let fund of fundOptions" [value]="fund.id">
{{ fund.name }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="flex-48" (click)="submitPicker.open()">
<mat-label>{{ 'labels.inputs.Submitted on' | translate }}</mat-label>
<input
matInput
[min]="minDate"
[max]="maxDate"
[matDatepicker]="submitPicker"
matTooltip="{{ 'tooltips.Date the loan account application' | translate }}"
required
formControlName="submittedOnDate"
/>
<mat-datepicker-toggle matSuffix [for]="submitPicker"></mat-datepicker-toggle>
<mat-datepicker #submitPicker></mat-datepicker>
<mat-error *ngIf="loansAccountDetailsForm.controls.submittedOnDate?.hasError('required')">
{{ 'labels.inputs.Submitted on' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-form-field class="flex-48" (click)="disbursementPicker.open()">
<mat-label>{{ 'labels.inputs.Disbursement on' | translate }}</mat-label>
<input
matInput
[min]="loansAccountDetailsForm.value.submittedOnDate"
[max]="maxDate"
[matDatepicker]="disbursementPicker"
matTooltip="{{ 'tooltips.Date that the loan account disbursed' | translate }}"
required
formControlName="expectedDisbursementDate"
/>
<mat-datepicker-toggle matSuffix [for]="disbursementPicker"></mat-datepicker-toggle>
<mat-datepicker #disbursementPicker></mat-datepicker>
<mat-error *ngIf="loansAccountDetailsForm.controls.submittedOnDate?.hasError('required')">
{{ 'labels.inputs.Disbursement on' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-divider class="flex-98"></mat-divider>
<h3 class="mat-h3 flex-fill">{{ 'labels.heading.Savings Linkage' | translate }}</h3>
<mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.Link savings' | translate }}</mat-label>
<mat-select formControlName="linkAccountId">
<mat-option *ngFor="let savingaccount of accountLinkingOptions" [value]="savingaccount.id">
({{ savingaccount.accountNo }}) {{ savingaccount.productName }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-checkbox class="flex-48" formControlName="createStandingInstructionAtDisbursement">
<p>{{ 'labels.inputs.Create standing instructions at disbursement' | translate }}</p>
</mat-checkbox>
</div>
@if (loanProductSelected) {
<div class="layout-row-wrap layout-lt-md-column gap-2percent">
<mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.External id' | translate }}</mat-label>
<input
matInput
formControlName="externalId"
matTooltip="{{ 'tooltips.Provides an external id' | translate }}"
/>
</mat-form-field>
@if (loanProductSelected) {
<mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.Loan officer' | translate }}</mat-label>
<mat-select
formControlName="loanOfficerId"
matTooltip="{{ 'tooltips.Financial institution representative' | translate }}"
>
@for (loanOfficer of loanOfficerOptions; track loanOfficer) {
<mat-option [value]="loanOfficer.id">
{{ loanOfficer.displayName }}
</mat-option>
}
</mat-select>
</mat-form-field>
}
<mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.Loan Purpose' | translate }}</mat-label>
<mat-select formControlName="loanPurposeId" matTooltip="{{ 'tooltips.Provides an indication' | translate }}">
@for (loanPurpose of loanPurposeOptions; track loanPurpose) {
<mat-option [value]="loanPurpose.id">
{{ loanPurpose.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.Fund' | translate }}</mat-label>
<mat-select formControlName="fundId">
@for (fund of fundOptions; track fund) {
<mat-option [value]="fund.id">
{{ fund.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field class="flex-48" (click)="submitPicker.open()">
<mat-label>{{ 'labels.inputs.Submitted on' | translate }}</mat-label>
<input
matInput
[min]="minDate"
[max]="maxDate"
[matDatepicker]="submitPicker"
matTooltip="{{ 'tooltips.Date the loan account application' | translate }}"
required
formControlName="submittedOnDate"
/>
<mat-datepicker-toggle matSuffix [for]="submitPicker"></mat-datepicker-toggle>
<mat-datepicker #submitPicker></mat-datepicker>
@if (loansAccountDetailsForm.controls.submittedOnDate?.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Submitted on' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field class="flex-48" (click)="disbursementPicker.open()">
<mat-label>{{ 'labels.inputs.Disbursement on' | translate }}</mat-label>
<input
matInput
[min]="loansAccountDetailsForm.value.submittedOnDate"
[max]="maxDate"
[matDatepicker]="disbursementPicker"
matTooltip="{{ 'tooltips.Date that the loan account disbursed' | translate }}"
required
formControlName="expectedDisbursementDate"
/>
<mat-datepicker-toggle matSuffix [for]="disbursementPicker"></mat-datepicker-toggle>
<mat-datepicker #disbursementPicker></mat-datepicker>
@if (loansAccountDetailsForm.controls.submittedOnDate?.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Disbursement on' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-divider class="flex-98"></mat-divider>
<h3 class="mat-h3 flex-fill">{{ 'labels.heading.Savings Linkage' | translate }}</h3>
<mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.Link savings' | translate }}</mat-label>
<mat-select formControlName="linkAccountId">
@for (savingaccount of accountLinkingOptions; track savingaccount) {
<mat-option [value]="savingaccount.id">
({{ savingaccount.accountNo }}) {{ savingaccount.productName }}
</mat-option>
}
</mat-select>
</mat-form-field>
<mat-checkbox class="flex-48" formControlName="createStandingInstructionAtDisbursement">
<p>{{ 'labels.inputs.Create standing instructions at disbursement' | translate }}</p>
</mat-checkbox>
</div>
}
<div class="layout-row align-center gap-2percent margin-t responsive-column">
<button mat-raised-button matStepperPrevious disabled>
@@ -134,8 +147,10 @@
{{ 'labels.buttons.Next' | translate }}
<fa-icon icon="arrow-right" class="m-l-10"></fa-icon>
</button>
<button mat-raised-button *ngIf="loanId" [routerLink]="['../', 'general']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
@if (loanId) {
<button mat-raised-button [routerLink]="['../', 'general']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
}
</div>
</form>
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Component, OnInit, Input, Output, EventEmitter, OnDestroy } from '@angular/core';
import { Component, OnInit, Input, Output, EventEmitter, OnDestroy, inject } from '@angular/core';
import {
UntypedFormGroup,
UntypedFormBuilder,
@@ -18,7 +18,7 @@ import { takeUntil } from 'rxjs/operators';
import { ReplaySubject, Subject } from 'rxjs';
import { MatTooltip } from '@angular/material/tooltip';
import { NgxMatSelectSearchModule } from 'ngx-mat-select-search';
import { NgFor, NgIf, AsyncPipe } from '@angular/common';
import { AsyncPipe } from '@angular/common';
import { MatDivider } from '@angular/material/divider';
import { MatCheckbox } from '@angular/material/checkbox';
import { MatStepperPrevious, MatStepperNext } from '@angular/material/stepper';
@@ -45,6 +45,13 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class LoansAccountDetailsStepComponent implements OnInit, OnDestroy {
private formBuilder = inject(UntypedFormBuilder);
private loansService = inject(LoansService);
private route = inject(ActivatedRoute);
private translateService = inject(TranslateService);
private settingsService = inject(SettingsService);
private commons = inject(Commons);
//** Defining PlaceHolders for the search bar */
placeHolderLabel = '';
noEntriesFoundLabel = '';
@@ -89,14 +96,7 @@ export class LoansAccountDetailsStepComponent implements OnInit, OnDestroy {
* @param {LoansService} loansService Loans Service.
* @param {SettingsService} settingsService SettingsService
*/
constructor(
private formBuilder: UntypedFormBuilder,
private loansService: LoansService,
private route: ActivatedRoute,
private translateService: TranslateService,
private settingsService: SettingsService,
private commons: Commons
) {
constructor() {
this.loanId = this.route.snapshot.params['loanId'];
}
@@ -13,26 +13,32 @@
></span>
</div>
<div class="flex-fill" *ngIf="loansAccount.loanOfficerId">
<span class="flex-40">{{ 'labels.inputs.Loan officer' | translate }}:</span>
<span class="flex-60">{{
loansAccount.loanOfficerId | find: loansAccountProductTemplate.loanOfficerOptions : 'id' : 'displayName'
}}</span>
</div>
@if (loansAccount.loanOfficerId) {
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.Loan officer' | translate }}:</span>
<span class="flex-60">{{
loansAccount.loanOfficerId | find: loansAccountProductTemplate.loanOfficerOptions : 'id' : 'displayName'
}}</span>
</div>
}
<div class="flex-fill" *ngIf="loansAccount.loanPurposeId">
<span class="flex-40">{{ 'labels.inputs.Loan purpose' | translate }}:</span>
<span class="flex-60">{{
loansAccount.loanPurposeId | find: loansAccountProductTemplate.loanPurposeOptions : 'id' : 'name'
}}</span>
</div>
@if (loansAccount.loanPurposeId) {
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.Loan purpose' | translate }}:</span>
<span class="flex-60">{{
loansAccount.loanPurposeId | find: loansAccountProductTemplate.loanPurposeOptions : 'id' : 'name'
}}</span>
</div>
}
<div class="flex-fill" *ngIf="loansAccount.fundId">
<span class="flex-40">{{ 'labels.inputs.Fund' | translate }}:</span>
<span class="flex-60">{{
loansAccount.fundId | find: loansAccountProductTemplate.fundOptions : 'id' : 'name'
}}</span>
</div>
@if (loansAccount.fundId) {
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.Fund' | translate }}:</span>
<span class="flex-60">{{
loansAccount.fundId | find: loansAccountProductTemplate.fundOptions : 'id' : 'name'
}}</span>
</div>
}
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.Submitted on' | translate }}:</span>
@@ -44,14 +50,16 @@
<span class="flex-60">{{ loansAccount.expectedDisbursementDate | dateFormat }}</span>
</div>
<div class="flex-fill" *ngIf="loansAccount.externalId">
<span class="flex-40">{{ 'labels.inputs.External id' | translate }}:</span>
<span class="flex-60">
<mifosx-external-identifier externalId="{{ loansAccount.externalId }}"></mifosx-external-identifier>
</span>
</div>
@if (loansAccount.externalId) {
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.External id' | translate }}:</span>
<span class="flex-60">
<mifosx-external-identifier externalId="{{ loansAccount.externalId }}"></mifosx-external-identifier>
</span>
</div>
}
<ng-container *ngIf="activeClientMembers">
@if (activeClientMembers) {
<h3 class="mat-h3 margin-t flex-fill">{{ 'labels.heading.Client Members' | translate }}</h3>
<mat-divider class="flex-fill"></mat-divider>
<div class="flex-60">
@@ -61,19 +69,16 @@
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Client ID' | translate }}</th>
<td mat-cell *matCellDef="let element">{{ element.id }}</td>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Client Name' | translate }}</th>
<td mat-cell *matCellDef="let element">{{ element.displayName }}</td>
</ng-container>
<!-- Purpose Column -->
<ng-container matColumnDef="purpose">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Loan Purpose' | translate }}</th>
<td mat-cell *matCellDef="let element">{{ element.purpose }}</td>
</ng-container>
<!-- Principal Column -->
<ng-container matColumnDef="principal">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Original Loan' | translate }}</th>
@@ -81,12 +86,11 @@
{{ element.principal | currency: loansAccountProductTemplate.currency.code : 'symbol-narrow' : '1.2-2' }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="membersDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: membersDisplayedColumns"></tr>
</table>
</div>
</ng-container>
}
<h3 class="mat-h3 margin-t flex-fill">{{ 'labels.heading.Terms' | translate }}</h3>
@@ -134,39 +138,51 @@
>
</div>
<div class="flex-fill" *ngIf="productEnableDownPayment">
<span class="flex-40">{{ 'labels.inputs.Enable Down Payments' | translate }}:</span>
<span class="flex-60">{{ loansAccount.enableDownPayment | yesNo }}</span>
</div>
@if (productEnableDownPayment) {
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.Enable Down Payments' | translate }}:</span>
<span class="flex-60">{{ loansAccount.enableDownPayment | yesNo }}</span>
</div>
}
<div class="flex-fill" *ngIf="loansAccount.repaymentsStartingFromDate">
<span class="flex-40">{{ 'labels.inputs.First repayment on' | translate }}:</span>
<span class="flex-60">{{ loansAccount.repaymentsStartingFromDate | dateFormat }}</span>
</div>
@if (loansAccount.repaymentsStartingFromDate) {
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.First repayment on' | translate }}:</span>
<span class="flex-60">{{ loansAccount.repaymentsStartingFromDate | dateFormat }}</span>
</div>
}
<div class="flex-fill" *ngIf="loansAccount.interestChargedFromDate">
<span class="flex-40">{{ 'labels.inputs.Interest charged from' | translate }}:</span>
<span class="flex-60">{{ loansAccount.interestChargedFromDate | dateFormat }}</span>
</div>
@if (loansAccount.interestChargedFromDate) {
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.Interest charged from' | translate }}:</span>
<span class="flex-60">{{ loansAccount.interestChargedFromDate | dateFormat }}</span>
</div>
}
<div class="flex-fill" *ngIf="loansAccount.interestRatePerPeriod">
<span class="flex-40">{{ 'labels.inputs.Nominal interest rate' | translate }}:</span>
<span class="flex-60"
>{{ loansAccount.interestRatePerPeriod }}&nbsp;&nbsp;{{
loansAccountProductTemplate.interestRateFrequencyType.value
}}</span
>
</div>
@if (loansAccount.interestRatePerPeriod) {
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.Nominal interest rate' | translate }}:</span>
<span class="flex-60"
>{{ loansAccount.interestRatePerPeriod }}&nbsp;&nbsp;{{
loansAccountProductTemplate.interestRateFrequencyType.value
}}</span
>
</div>
}
<div class="flex-fill" *ngIf="loansAccount.interestType">
<span class="flex-40">{{ 'labels.inputs.Interest method' | translate }}: </span>
<span class="flex-60">{{ loansAccount.interestType }}</span>
</div>
@if (loansAccount.interestType) {
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.Interest method' | translate }}: </span>
<span class="flex-60">{{ loansAccount.interestType }}</span>
</div>
}
<div class="flex-fill" *ngIf="loansAccount.isEqualAmortization">
<span class="flex-40">{{ 'labels.inputs.Is Equal Amortization' | translate }}:</span>
<span class="flex-60">{{ loansAccount.isEqualAmortization }}</span>
</div>
@if (loansAccount.isEqualAmortization) {
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.Is Equal Amortization' | translate }}:</span>
<span class="flex-60">{{ loansAccount.isEqualAmortization }}</span>
</div>
}
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.Amortization' | translate }}</span>
@@ -183,20 +199,28 @@
}}</span>
</div>
<div class="flex-fill" *ngIf="loansAccount.allowPartialPeriodInterestCalculation">
<span class="flex-40">{{ 'labels.inputs.Calculate interest for exact days in partial period' | translate }}:</span>
<span class="flex-60">{{ loansAccount.allowPartialPeriodInterestCalculation }}</span>
</div>
@if (loansAccount.allowPartialPeriodInterestCalculation) {
<div class="flex-fill">
<span class="flex-40"
>{{ 'labels.inputs.Calculate interest for exact days in partial period' | translate }}:</span
>
<span class="flex-60">{{ loansAccount.allowPartialPeriodInterestCalculation }}</span>
</div>
}
<div class="flex-fill" *ngIf="loansAccount.inArrearsTolerance">
<span class="flex-40">{{ 'labels.inputs.Arrears tolerance' | translate }}: </span>
<span class="flex-60">{{ loansAccount.inArrearsTolerance }}</span>
</div>
@if (loansAccount.inArrearsTolerance) {
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.Arrears tolerance' | translate }}: </span>
<span class="flex-60">{{ loansAccount.inArrearsTolerance }}</span>
</div>
}
<div class="flex-fill" *ngIf="loansAccount.graceOnInterestCharged">
<span class="flex-40">{{ 'labels.inputs.Interest free period' | translate }}: </span>
<span class="flex-60">{{ loansAccount.graceOnInterestCharged }}</span>
</div>
@if (loansAccount.graceOnInterestCharged) {
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.Interest free period' | translate }}: </span>
<span class="flex-60">{{ loansAccount.graceOnInterestCharged }}</span>
</div>
}
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.Repayment strategy' | translate }}: </span>
@@ -219,138 +243,139 @@
<h3 class="mat-h3 margin-t flex-fill">{{ 'labels.heading.Moratorium' | translate }}</h3>
<mat-divider class="flex-fill"></mat-divider>
<div class="flex-fill" *ngIf="loansAccount.graceOnPrincipalPayment">
<span class="flex-40">{{ 'labels.inputs.On principal payment' | translate }}: </span>
<span class="flex-60">{{ loansAccount.graceOnPrincipalPayment }}</span>
</div>
@if (loansAccount.graceOnPrincipalPayment) {
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.On principal payment' | translate }}: </span>
<span class="flex-60">{{ loansAccount.graceOnPrincipalPayment }}</span>
</div>
}
<div class="flex-fill" *ngIf="loansAccount.graceOnInterestPayment">
<span class="flex-40">{{ 'labels.inputs.On interest payment' | translate }}: </span>
<span class="flex-60">{{ loansAccount.graceOnInterestPayment }}</span>
</div>
@if (loansAccount.graceOnInterestPayment) {
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.On interest payment' | translate }}: </span>
<span class="flex-60">{{ loansAccount.graceOnInterestPayment }}</span>
</div>
}
<div class="flex-fill" *ngIf="loansAccount.graceOnArrearsAgeing">
<span class="flex-40">{{ 'labels.inputs.On Arrears Aging' | translate }}: </span>
<span class="flex-60">{{ loansAccount.graceOnArrearsAgeing }}</span>
</div>
@if (loansAccount.graceOnArrearsAgeing) {
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.On Arrears Aging' | translate }}: </span>
<span class="flex-60">{{ loansAccount.graceOnArrearsAgeing }}</span>
</div>
}
<div class="flex-fill">
<span class="flex-40"> {{ 'labels.inputs.Enable installment level Delinquency' | translate }} </span>
<span class="flex-60"> {{ loansAccount.enableInstallmentLevelDelinquency | yesNo }} </span>
</div>
<div class="flex-fill" *ngIf="loansAccount.isTopup">
<span class="flex-40">{{ 'labels.inputs.Is Topup Loan' | translate }}? </span>
<span class="flex-60">{{ loansAccount.isTopup }}</span>
</div>
@if (loansAccount.isTopup) {
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.Is Topup Loan' | translate }}? </span>
<span class="flex-60">{{ loansAccount.isTopup }}</span>
</div>
}
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.Recalculate Interest' | translate }}: </span>
<span class="flex-60">{{ loansAccountProductTemplate?.isInterestRecalculationEnabled | yesNo }}</span>
</div>
<div class="flex-fill" *ngIf="loansAccountProductTemplate?.daysInMonthType">
<span class="flex-40">{{ 'labels.inputs.Days in month' | translate }}: </span>
<span class="flex-60">{{ loansAccountProductTemplate?.daysInMonthType.value }}</span>
</div>
@if (loansAccountProductTemplate?.daysInMonthType) {
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.Days in month' | translate }}: </span>
<span class="flex-60">{{ loansAccountProductTemplate?.daysInMonthType.value }}</span>
</div>
}
<div *ngIf="loansAccount.charges.length" class="layout-row-wrap responsive-column flex-fill margin-t">
<h3 class="mat-h3 flex-fill">{{ 'labels.heading.Charges' | translate }}</h3>
<mat-divider class="flex-fill"></mat-divider>
<table class="flex-fill mat-elevation-z1" mat-table [dataSource]="loansAccount.charges">
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.name' | translate }}</th>
<td mat-cell *matCellDef="let charge">
{{ charge.name + ', ' + (charge.currency?.displaySymbol || '') }}
</td>
</ng-container>
<ng-container matColumnDef="chargeCalculationType">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Type' | translate }}</th>
<td mat-cell *matCellDef="let charge">
{{ charge.chargeCalculationType.value }}
</td>
</ng-container>
<ng-container matColumnDef="amount">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Amount' | translate }}</th>
<td mat-cell *matCellDef="let charge">
{{ charge.amount }}
</td>
</ng-container>
<ng-container matColumnDef="chargeTimeType">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Collected On' | translate }}</th>
<td mat-cell *matCellDef="let charge">
{{ charge.chargeTimeType.value }}
</td>
</ng-container>
<ng-container matColumnDef="date">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Date' | translate }}</th>
<td mat-cell *matCellDef="let charge">
<span
*ngIf="charge.chargeTimeType.value === 'Specified due date' || charge.chargeTimeType.value === 'Weekly Fee'"
>
{{ (charge.dueDate | dateFormat) || 'Unassigned' }}
</span>
<span *ngIf="charge.chargeTimeType.value === 'Monthly Fee' || charge.chargeTimeType.value === 'Annual Fee'">
{{ (charge.feeOnMonthDay | dateFormat) || 'Unassigned' }}
</span>
<span
*ngIf="
@if (loansAccount.charges.length) {
<div class="layout-row-wrap responsive-column flex-fill margin-t">
<h3 class="mat-h3 flex-fill">{{ 'labels.heading.Charges' | translate }}</h3>
<mat-divider class="flex-fill"></mat-divider>
<table class="flex-fill mat-elevation-z1" mat-table [dataSource]="loansAccount.charges">
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.name' | translate }}</th>
<td mat-cell *matCellDef="let charge">
{{ charge.name + ', ' + (charge.currency?.displaySymbol || '') }}
</td>
</ng-container>
<ng-container matColumnDef="chargeCalculationType">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Type' | translate }}</th>
<td mat-cell *matCellDef="let charge">
{{ charge.chargeCalculationType.value }}
</td>
</ng-container>
<ng-container matColumnDef="amount">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Amount' | translate }}</th>
<td mat-cell *matCellDef="let charge">
{{ charge.amount }}
</td>
</ng-container>
<ng-container matColumnDef="chargeTimeType">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Collected On' | translate }}</th>
<td mat-cell *matCellDef="let charge">
{{ charge.chargeTimeType.value }}
</td>
</ng-container>
<ng-container matColumnDef="date">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Date' | translate }}</th>
<td mat-cell *matCellDef="let charge">
@if (charge.chargeTimeType.value === 'Specified due date' || charge.chargeTimeType.value === 'Weekly Fee') {
<span>
{{ (charge.dueDate | dateFormat) || 'Unassigned' }}
</span>
}
@if (charge.chargeTimeType.value === 'Monthly Fee' || charge.chargeTimeType.value === 'Annual Fee') {
<span>
{{ (charge.feeOnMonthDay | dateFormat) || 'Unassigned' }}
</span>
}
@if (
!(
charge.chargeTimeType.value === 'Monthly Fee' ||
charge.chargeTimeType.value === 'Annual Fee' ||
charge.chargeTimeType.value === 'Specified due date' ||
charge.chargeTimeType.value === 'Weekly Fee'
)
"
>
{{ 'labels.inputs.N/A' | translate }}
</span>
</td>
</ng-container>
) {
<span>
{{ 'labels.inputs.N/A' | translate }}
</span>
}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="chargesDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: chargesDisplayedColumns"></tr>
</table>
</div>
}
<tr mat-header-row *matHeaderRowDef="chargesDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: chargesDisplayedColumns"></tr>
</table>
</div>
<div
*ngIf="loansAccountProductTemplate.overdueCharges.length"
class="flex-fill layout-row-wrap layout-xs-column margin-t"
>
<h3 class="mat-h3 flex-98">{{ 'labels.heading.Overdue Charges' | translate }}</h3>
<mat-divider class="flex-98"></mat-divider>
<table mat-table class="mat-elevation-z1" [dataSource]="loansAccountProductTemplate.overdueCharges">
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.name' | translate }}</th>
<td mat-cell *matCellDef="let charge">{{ charge.name + ', ' + (charge.currency?.displaySymbol || '') }}</td>
</ng-container>
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Type' | translate }}</th>
<td mat-cell *matCellDef="let charge">{{ charge.chargeCalculationType.value }}</td>
</ng-container>
<ng-container matColumnDef="amount">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Amount' | translate }}</th>
<td mat-cell *matCellDef="let charge">{{ charge.amount | formatNumber }}</td>
</ng-container>
<ng-container matColumnDef="collectedon">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Collected On' | translate }}</th>
<td mat-cell *matCellDef="let charge">{{ charge.chargeTimeType.value }}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="overdueChargesDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: overdueChargesDisplayedColumns"></tr>
</table>
</div>
@if (loansAccountProductTemplate.overdueCharges.length) {
<div class="flex-fill layout-row-wrap layout-xs-column margin-t">
<h3 class="mat-h3 flex-98">{{ 'labels.heading.Overdue Charges' | translate }}</h3>
<mat-divider class="flex-98"></mat-divider>
<table mat-table class="mat-elevation-z1" [dataSource]="loansAccountProductTemplate.overdueCharges">
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.name' | translate }}</th>
<td mat-cell *matCellDef="let charge">{{ charge.name + ', ' + (charge.currency?.displaySymbol || '') }}</td>
</ng-container>
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Type' | translate }}</th>
<td mat-cell *matCellDef="let charge">{{ charge.chargeCalculationType.value }}</td>
</ng-container>
<ng-container matColumnDef="amount">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Amount' | translate }}</th>
<td mat-cell *matCellDef="let charge">{{ charge.amount | formatNumber }}</td>
</ng-container>
<ng-container matColumnDef="collectedon">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Collected On' | translate }}</th>
<td mat-cell *matCellDef="let charge">{{ charge.chargeTimeType.value }}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="overdueChargesDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: overdueChargesDisplayedColumns"></tr>
</table>
</div>
}
</div>
<div class="layout-row responsive-column align-center gap-2px margin-t">
@@ -14,7 +14,7 @@ import {
MatRow
} from '@angular/material/table';
import { LongTextComponent } from '../../../shared/long-text/long-text.component';
import { NgIf, CurrencyPipe } from '@angular/common';
import { CurrencyPipe } from '@angular/common';
import { ExternalIdentifierComponent } from '../../../shared/external-identifier/external-identifier.component';
import { MatDivider } from '@angular/material/divider';
import { MatStepperPrevious } from '@angular/material/stepper';
@@ -20,7 +20,9 @@
{{ 'labels.buttons.Next' | translate }}
<fa-icon icon="arrow-right" class="m-l-10"></fa-icon>
</button>
<button mat-raised-button *ngIf="loanId" [routerLink]="['../', 'general']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
@if (loanId) {
<button mat-raised-button [routerLink]="['../', 'general']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
}
</div>
@@ -1,4 +1,4 @@
import { Component, Input } from '@angular/core';
import { Component, Input, inject } from '@angular/core';
import { ActivatedRoute, RouterLink } from '@angular/router';
import { LoansService } from 'app/loans/loans.service';
import { RepaymentSchedule } from 'app/loans/models/loan-account.model';
@@ -21,6 +21,10 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class LoansAccountScheduleStepComponent {
private loansService = inject(LoansService);
private settingsService = inject(SettingsService);
private route = inject(ActivatedRoute);
/** Currency Code */
@Input() currencyCode: string;
/** Loans Account Template */
@@ -34,11 +38,7 @@ export class LoansAccountScheduleStepComponent {
loanId: string | null = null;
constructor(
private loansService: LoansService,
private settingsService: SettingsService,
private route: ActivatedRoute
) {
constructor() {
this.loanId = this.route.snapshot.params['loanId'];
}
@@ -1,14 +1,15 @@
<form [formGroup]="loansAccountTermsForm">
<div class="layout-row-wrap gap-2px responsive-column">
<mifosx-input-amount
class="flex-48"
*ngIf="currency"
[currency]="currency"
[isRequired]="true"
[inputFormControl]="loansAccountTermsForm.controls.principalAmount"
[inputLabel]="'Principal'"
>
</mifosx-input-amount>
@if (currency) {
<mifosx-input-amount
class="flex-48"
[currency]="currency"
[isRequired]="true"
[inputFormControl]="loansAccountTermsForm.controls.principalAmount"
[inputLabel]="'Principal'"
>
</mifosx-input-amount>
}
<h4 class="mat-h4 flex-98">
{{ 'labels.heading.Term Options' | translate }}
@@ -18,32 +19,42 @@
<mat-form-field class="flex-fill flex-23">
<mat-label>{{ 'labels.inputs.Loan Term' | translate }}</mat-label>
<input type="number" matInput required disabled formControlName="loanTermFrequency" />
<mat-error *ngIf="loansAccountTermsForm.controls.loanTermFrequency.hasError('required')">
{{ 'labels.inputs.Loan Term' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (loansAccountTermsForm.controls.loanTermFrequency.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Loan Term' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field class="flex-fill flex-23">
<mat-label>{{ 'labels.inputs.Frequency' | translate }}</mat-label>
<mat-select required formControlName="loanTermFrequencyType">
<mat-option *ngFor="let type of termFrequencyTypeData" [value]="type.id">
{{ type.value | translateKey: 'catalogs' }}
</mat-option>
@for (type of termFrequencyTypeData; track type) {
<mat-option [value]="type.id">
{{ type.value | translateKey: 'catalogs' }}
</mat-option>
}
</mat-select>
<mat-error *ngIf="loansAccountTermsForm.controls.loanTermFrequencyType.hasError('required')">
{{ 'labels.inputs.Frequency' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (loansAccountTermsForm.controls.loanTermFrequencyType.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Frequency' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field class="flex-fill flex-20" *ngIf="hasFixedLength()">
<mat-label>{{ 'labels.inputs.Fixed Length' | translate }}</mat-label>
<input type="number" matInput formControlName="fixedLength" />
</mat-form-field>
<span *ngIf="hasFixedLength()" class="flex-20 label-field">{{
loansAccountTermsForm.value.loanTermFrequencyType | find: termFrequencyTypeData : 'id' : 'value'
}}</span>
@if (hasFixedLength()) {
<mat-form-field class="flex-fill flex-20">
<mat-label>{{ 'labels.inputs.Fixed Length' | translate }}</mat-label>
<input type="number" matInput formControlName="fixedLength" />
</mat-form-field>
}
@if (hasFixedLength()) {
<span class="flex-20 label-field">{{
loansAccountTermsForm.value.loanTermFrequencyType | find: termFrequencyTypeData : 'id' : 'value'
}}</span>
}
<h4 class="mat-h4 flex-98">{{ 'labels.inputs.Repayments' | translate }}</h4>
@@ -55,16 +66,20 @@
formControlName="numberOfRepayments"
matTooltip="{{ 'tooltips.Enter the total count of repayments' | translate }}"
/>
<mat-error *ngIf="loansAccountTermsForm.controls.numberOfRepayments.hasError('required')">
{{ 'labels.inputs.Number of repayments' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (loansAccountTermsForm.controls.numberOfRepayments.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Number of repayments' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field class="flex-fill flex-23" *ngIf="loansAccountTermsData?.canDefineInstallmentAmount">
<mat-label>{{ 'labels.inputs.Installment Amount' | translate }}</mat-label>
<input type="number" matInput formControlName="fixedEmiAmount" />
</mat-form-field>
@if (loansAccountTermsData?.canDefineInstallmentAmount) {
<mat-form-field class="flex-fill flex-23">
<mat-label>{{ 'labels.inputs.Installment Amount' | translate }}</mat-label>
<input type="number" matInput formControlName="fixedEmiAmount" />
</mat-form-field>
}
<mat-form-field class="flex-fill flex-23" (click)="repaymentsPicker.open()">
<mat-label>{{ 'labels.inputs.First repayment on' | translate }}</mat-label>
@@ -111,88 +126,96 @@
formControlName="repaymentEvery"
matTooltip="{{ 'tooltips.Fields are input to calculating the repayment schedule' | translate }}"
/>
<mat-error *ngIf="loansAccountTermsForm.controls.repaymentEvery.hasError('required')">
{{ 'labels.inputs.Repaid every' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (loansAccountTermsForm.controls.repaymentEvery.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Repaid every' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field class="flex-fill flex-23">
<mat-label>{{ 'labels.inputs.Frequency' | translate }}</mat-label>
<mat-select formControlName="repaymentFrequencyType" disabled required>
<mat-option *ngFor="let repaymentFrequencyType of termFrequencyTypeData" [value]="repaymentFrequencyType.id">
{{ repaymentFrequencyType.value | translateKey: 'catalogs' }}
</mat-option>
@for (repaymentFrequencyType of termFrequencyTypeData; track repaymentFrequencyType) {
<mat-option [value]="repaymentFrequencyType.id">
{{ repaymentFrequencyType.value | translateKey: 'catalogs' }}
</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field class="flex-fill flex-14" *ngIf="loansAccountTermsForm.controls.repaymentFrequencyType.value === 2">
<mat-label>{{ 'labels.inputs.Select On' | translate }}</mat-label>
<mat-select formControlName="repaymentFrequencyNthDayType">
<mat-option
*ngFor="let repaymentFrequencyNthDayType of repaymentFrequencyNthDayTypeData"
[value]="repaymentFrequencyNthDayType.id"
>
{{ repaymentFrequencyNthDayType.value | translateKey: 'catalogs' }}
</mat-option>
</mat-select>
</mat-form-field>
@if (loansAccountTermsForm.controls.repaymentFrequencyType.value === 2) {
<mat-form-field class="flex-fill flex-14">
<mat-label>{{ 'labels.inputs.Select On' | translate }}</mat-label>
<mat-select formControlName="repaymentFrequencyNthDayType">
@for (repaymentFrequencyNthDayType of repaymentFrequencyNthDayTypeData; track repaymentFrequencyNthDayType) {
<mat-option [value]="repaymentFrequencyNthDayType.id">
{{ repaymentFrequencyNthDayType.value | translateKey: 'catalogs' }}
</mat-option>
}
</mat-select>
</mat-form-field>
}
<mat-form-field class="flex-fill flex-14" *ngIf="loansAccountTermsForm.controls.repaymentFrequencyType.value === 2">
<mat-label>{{ 'labels.inputs.Select Day' | translate }}</mat-label>
<mat-select formControlName="repaymentFrequencyDayOfWeekType">
<mat-option
*ngFor="let repaymentFrequencyDayOfWeekType of repaymentFrequencyDaysOfWeekTypeData"
[value]="repaymentFrequencyDayOfWeekType.id"
>
{{ repaymentFrequencyDayOfWeekType.value | translateKey: 'catalogs' }}
</mat-option>
</mat-select>
</mat-form-field>
@if (loansAccountTermsForm.controls.repaymentFrequencyType.value === 2) {
<mat-form-field class="flex-fill flex-14">
<mat-label>{{ 'labels.inputs.Select Day' | translate }}</mat-label>
<mat-select formControlName="repaymentFrequencyDayOfWeekType">
@for (
repaymentFrequencyDayOfWeekType of repaymentFrequencyDaysOfWeekTypeData;
track repaymentFrequencyDayOfWeekType
) {
<mat-option [value]="repaymentFrequencyDayOfWeekType.id">
{{ repaymentFrequencyDayOfWeekType.value | translateKey: 'catalogs' }}
</mat-option>
}
</mat-select>
</mat-form-field>
}
<mat-checkbox
labelPosition="before"
formControlName="enableDownPayment"
matTooltip="{{ 'tooltips.Leave this checkbox checked if the loan has Down Payment' | translate }}"
class="margin-b flex-73"
*ngIf="productEnableDownPayment"
>
{{ 'labels.inputs.Enable Down Payment' | translate }}
</mat-checkbox>
@if (productEnableDownPayment) {
<mat-checkbox
labelPosition="before"
formControlName="enableDownPayment"
matTooltip="{{ 'tooltips.Leave this checkbox checked if the loan has Down Payment' | translate }}"
class="margin-b flex-73"
>
{{ 'labels.inputs.Enable Down Payment' | translate }}
</mat-checkbox>
}
<h4 class="mat-h4 flex-98">{{ 'labels.inputs.Nominal interest rate' | translate }}</h4>
<ng-container *ngIf="!loansAccountTermsData?.isLoanProductLinkedToFloatingRate">
@if (!loansAccountTermsData?.isLoanProductLinkedToFloatingRate) {
<mat-form-field class="flex-fill flex-23">
<mat-label>{{ 'labels.inputs.Nominal interest rate' | translate }} %</mat-label>
<input type="number" matInput formControlName="interestRatePerPeriod" />
</mat-form-field>
<mat-form-field class="flex-fill flex-23">
<mat-label>{{ 'labels.inputs.Frequency' | translate }}</mat-label>
<mat-select formControlName="interestRateFrequencyType">
<mat-option
*ngFor="let interestRateFrequencyType of interestRateFrequencyTypeData"
[value]="interestRateFrequencyType.id"
>
{{ interestRateFrequencyType.value | translateKey: 'catalogs' }}
</mat-option>
@for (interestRateFrequencyType of interestRateFrequencyTypeData; track interestRateFrequencyType) {
<mat-option [value]="interestRateFrequencyType.id">
{{ interestRateFrequencyType.value | translateKey: 'catalogs' }}
</mat-option>
}
</mat-select>
<mat-error>
{{ 'labels.inputs.Nominal interest rate frequency' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-form-field class="flex-fill flex-23">
<mat-label>{{ 'labels.inputs.Interest method' | translate }}</mat-label>
<mat-select formControlName="interestType" matTooltip="{{ 'tooltips.The Interest method value' | translate }}">
<mat-option *ngFor="let interestType of interestTypeData" [value]="interestType.id">
{{ interestType.value | translateKey: 'catalogs' }}
</mat-option>
@for (interestType of interestTypeData; track interestType) {
<mat-option [value]="interestType.id">
{{ interestType.value | translateKey: 'catalogs' }}
</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field class="flex-fill flex-23">
<mat-label>{{ 'labels.inputs.Amortization' | translate }}</mat-label>
<mat-select
@@ -200,21 +223,25 @@
matTooltip="{{ 'tooltips.The Amortization value' | translate }}"
formControlName="amortizationType"
>
<mat-option *ngFor="let amortizationType of amortizationTypeData" [value]="amortizationType.id">
{{ amortizationType.value | translateKey: 'catalogs' }}
</mat-option>
@for (amortizationType of amortizationTypeData; track amortizationType) {
<mat-option [value]="amortizationType.id">
{{ amortizationType.value | translateKey: 'catalogs' }}
</mat-option>
}
</mat-select>
<mat-error *ngIf="loansAccountTermsForm.controls.amortizationType.hasError('required')">
{{ 'labels.inputs.Amortization Type' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (loansAccountTermsForm.controls.amortizationType.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Amortization Type' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field class="flex-fill flex-23" *ngIf="isEqualPrincipalPayments()">
<mat-label>{{ 'labels.inputs.Principal Percentage Per Installment' | translate }}</mat-label>
<input type="number" matInput formControlName="fixedPrincipalPercentagePerInstallment" />
</mat-form-field>
@if (isEqualPrincipalPayments()) {
<mat-form-field class="flex-fill flex-23">
<mat-label>{{ 'labels.inputs.Principal Percentage Per Installment' | translate }}</mat-label>
<input type="number" matInput formControlName="fixedPrincipalPercentagePerInstallment" />
</mat-form-field>
}
<mat-checkbox
class="flex-23"
formControlName="isEqualAmortization"
@@ -222,19 +249,20 @@
>
<p>{{ 'labels.inputs.Is Equal Amortization' | translate }}</p>
</mat-checkbox>
</ng-container>
}
<ng-container *ngIf="loansAccountTermsData?.isLoanProductLinkedToFloatingRate">
@if (loansAccountTermsData?.isLoanProductLinkedToFloatingRate) {
<div class="flex-48 layout-row layout-xs-column">
<mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.Interest Method' | translate }}</mat-label>
<mat-select formControlName="interestType">
<mat-option *ngFor="let interestType of interestTypeData" [value]="interestType.id">
{{ interestType.value | translateKey: 'catalogs' }}
</mat-option>
@for (interestType of interestTypeData; track interestType) {
<mat-option [value]="interestType.id">
{{ interestType.value | translateKey: 'catalogs' }}
</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.Amortization' | translate }}</mat-label>
<mat-select
@@ -242,34 +270,39 @@
matTooltip="{{ 'tooltips.The Amortization value' | translate }}"
formControlName="amortizationType"
>
<mat-option *ngFor="let amortizationType of amortizationTypeData" [value]="amortizationType.id">
{{ amortizationType.value | translateKey: 'catalogs' }}
</mat-option>
@for (amortizationType of amortizationTypeData; track amortizationType) {
<mat-option [value]="amortizationType.id">
{{ amortizationType.value | translateKey: 'catalogs' }}
</mat-option>
}
</mat-select>
<mat-error *ngIf="loansAccountTermsForm.controls.amortizationType.hasError('required')">
{{ 'labels.inputs.Amortization Type' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (loansAccountTermsForm.controls.amortizationType.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Amortization Type' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-checkbox class="flex-48" formControlName="isFloatingInterestRate">
<p>{{ 'labels.inputs.Is Floating Rate' | translate }}?</p>
</mat-checkbox>
</div>
</ng-container>
}
<h4 class="mat-h4 flex-98">{{ 'labels.inputs.Loan Schedule' | translate }}</h4>
<div class="flex-48" *ngIf="loanScheduleType">
<div class="layout-row">
<span class="flex-40"
><p>{{ 'labels.inputs.Loan Schedule Type' | translate }}</p></span
>
<span class="flex-60"
><p>{{ loanScheduleType.value | translateKey: 'catalogs' }}</p></span
>
@if (loanScheduleType) {
<div class="flex-48">
<div class="layout-row">
<span class="flex-40"
><p>{{ 'labels.inputs.Loan Schedule Type' | translate }}</p></span
>
<span class="flex-60"
><p>{{ loanScheduleType.value | translateKey: 'catalogs' }}</p></span
>
</div>
</div>
</div>
}
<mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.Repayment Strategy' | translate }}</mat-label>
@@ -278,17 +311,21 @@
matTooltip="{{ 'tooltips.The repayment strategy' | translate }}"
[disabled]="repaymentStrategyDisabled"
>
<mat-option
*ngFor="let transactionProcessingStrategy of transactionProcessingStrategyOptions"
[value]="transactionProcessingStrategy.code"
>
{{ transactionProcessingStrategy.name | translateKey: 'catalogs' }}
</mat-option>
@for (
transactionProcessingStrategy of transactionProcessingStrategyOptions;
track transactionProcessingStrategy
) {
<mat-option [value]="transactionProcessingStrategy.code">
{{ transactionProcessingStrategy.name | translateKey: 'catalogs' }}
</mat-option>
}
</mat-select>
<mat-error *ngIf="loansAccountTermsForm.controls.transactionProcessingStrategyCode.hasError('required')">
{{ 'labels.inputs.Repayment Strategy' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (loansAccountTermsForm.controls.transactionProcessingStrategyCode.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Repayment Strategy' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<h4 class="mat-h4 flex-98">{{ 'labels.heading.Interest Calculations' | translate }}</h4>
@@ -299,12 +336,11 @@
formControlName="interestCalculationPeriodType"
matTooltip="{{ 'tooltips.Daily - Will Calculate the interest' | translate }}"
>
<mat-option
*ngFor="let interestCalculationPeriodType of interestCalculationPeriodTypeData"
[value]="interestCalculationPeriodType.id"
>
{{ interestCalculationPeriodType.value | translateKey: 'catalogs' }}
</mat-option>
@for (interestCalculationPeriodType of interestCalculationPeriodTypeData; track interestCalculationPeriodType) {
<mat-option [value]="interestCalculationPeriodType.id">
{{ interestCalculationPeriodType.value | translateKey: 'catalogs' }}
</mat-option>
}
</mat-select>
</mat-form-field>
@@ -316,11 +352,13 @@
<p>{{ 'labels.inputs.Calculate interest for exact days in partial period' | translate }}</p>
</mat-checkbox>
<ng-container class="flex-98" *ngIf="isProgressive">
<mat-checkbox formControlName="interestRecognitionOnDisbursementDate" class="flex-98">
<p>{{ 'labels.inputs.Is interest recognition on disbursement date?' | translate }}</p>
</mat-checkbox>
</ng-container>
@if (isProgressive) {
<ng-container class="flex-98">
<mat-checkbox formControlName="interestRecognitionOnDisbursementDate" class="flex-98">
<p>{{ 'labels.inputs.Is interest recognition on disbursement date?' | translate }}</p>
</mat-checkbox>
</ng-container>
}
<mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.Arrears tolerance' | translate }} </mat-label>
@@ -361,35 +399,44 @@
<input type="number" matInput formControlName="graceOnArrearsAgeing" />
</mat-form-field>
<div class="flex-48 flex-fill" *ngIf="isDelinquencyEnabled()">
<p>
<span class="flex-53"
><b>{{ 'labels.inputs.Delinquency Bucket' | translate }}</b></span
>
<span class="flex-48">{{ loanProduct?.delinquencyBucket.name }}</span>
</p>
</div>
@if (isDelinquencyEnabled()) {
<div class="flex-48 flex-fill">
<p>
<span class="flex-53"
><b>{{ 'labels.inputs.Delinquency Bucket' | translate }}</b></span
>
<span class="flex-48">{{ loanProduct?.delinquencyBucket.name }}</span>
</p>
</div>
}
<div class="flex-48" *ngIf="isDelinquencyEnabled()">
<mat-checkbox formControlName="enableInstallmentLevelDelinquency">
<p>{{ 'labels.inputs.Enable installment level Delinquency' | translate }}</p>
</mat-checkbox>
</div>
@if (isDelinquencyEnabled()) {
<div class="flex-48">
<mat-checkbox formControlName="enableInstallmentLevelDelinquency">
<p>{{ 'labels.inputs.Enable installment level Delinquency' | translate }}</p>
</mat-checkbox>
</div>
}
<ng-container class="flex-48" *ngIf="loansAccountTermsData?.isTopup">
<mat-checkbox class="flex-20" formControlName="isTopup">
<p>{{ 'labels.inputs.Is Topup Loan' | translate }}?</p>
</mat-checkbox>
<mat-form-field class="flex-fill flex-24" *ngIf="loansAccountTermsForm.controls.isTopup.value">
<mat-label>{{ 'labels.inputs.Loan closed with Topup' | translate }}</mat-label>
<mat-select formControlName="loanIdToClose">
<mat-option *ngFor="let clientActiveLoan of clientActiveLoanData" [value]="clientActiveLoan.id">
{{ clientActiveLoan.accountNo }}
</mat-option>
</mat-select>
</mat-form-field>
</ng-container>
@if (loansAccountTermsData?.isTopup) {
<ng-container class="flex-48">
<mat-checkbox class="flex-20" formControlName="isTopup">
<p>{{ 'labels.inputs.Is Topup Loan' | translate }}?</p>
</mat-checkbox>
@if (loansAccountTermsForm.controls.isTopup.value) {
<mat-form-field class="flex-fill flex-24">
<mat-label>{{ 'labels.inputs.Loan closed with Topup' | translate }}</mat-label>
<mat-select formControlName="loanIdToClose">
@for (clientActiveLoan of clientActiveLoanData; track clientActiveLoan) {
<mat-option [value]="clientActiveLoan.id">
{{ clientActiveLoan.accountNo }}
</mat-option>
}
</mat-select>
</mat-form-field>
}
</ng-container>
}
<mat-divider class="flex-98"></mat-divider>
@@ -400,20 +447,26 @@
<span class="flex-60">{{ loansAccountTermsData?.isInterestRecalculationEnabled | yesNo }}</span>
</div>
<div class="flex-100 layout-row" *ngIf="loansAccountTermsData?.isInterestRecalculationEnabled">
<span class="flex-40">{{ 'labels.inputs.Days in year' | translate }}</span>
<span class="flex-60">{{ loansAccountTermsData.daysInYearType.value | translateKey: 'catalogs' }}</span>
</div>
<div class="flex-100 layout-row" *ngIf="loansAccountTermsData?.isInterestRecalculationEnabled">
<span class="flex-40">{{ 'labels.inputs.Days in month' | translate }}</span>
<span class="flex-60">{{ loansAccountTermsData.daysInMonthType.value | translateKey: 'catalogs' }}</span>
</div>
<div class="flex-100 layout-row" *ngIf="loansAccountTermsData?.isInterestRecalculationEnabled">
<span class="flex-40">{{ 'labels.inputs.Advance payments adjustment type' | translate }}</span>
<span class="flex-60">{{ loansAccountTermsData.interestRecalculationData.rescheduleStrategyType.value }}</span>
</div>
@if (loansAccountTermsData?.isInterestRecalculationEnabled) {
<div class="flex-100 layout-row">
<span class="flex-40">{{ 'labels.inputs.Days in year' | translate }}</span>
<span class="flex-60">{{ loansAccountTermsData.daysInYearType.value | translateKey: 'catalogs' }}</span>
</div>
}
@if (loansAccountTermsData?.isInterestRecalculationEnabled) {
<div class="flex-100 layout-row">
<span class="flex-40">{{ 'labels.inputs.Days in month' | translate }}</span>
<span class="flex-60">{{ loansAccountTermsData.daysInMonthType.value | translateKey: 'catalogs' }}</span>
</div>
}
@if (loansAccountTermsData?.isInterestRecalculationEnabled) {
<div class="flex-100 layout-row">
<span class="flex-40">{{ 'labels.inputs.Advance payments adjustment type' | translate }}</span>
<span class="flex-60">{{ loansAccountTermsData.interestRecalculationData.rescheduleStrategyType.value }}</span>
</div>
}
<ng-container *ngIf="loansAccountTermsData?.isInterestRecalculationEnabled">
@if (loansAccountTermsData?.isInterestRecalculationEnabled) {
<div class="flex-100 layout-row">
<span class="flex-40">{{ 'labels.inputs.Interest recalculation compounding on' | translate }}</span>
<span class="flex-60">{{
@@ -421,52 +474,50 @@
| translateKey: 'catalogs'
}}</span>
</div>
<div class="flex-100 layout-row">
<span class="flex-40">{{ 'labels.inputs.Frequency Interval for recalculation' | translate }}</span>
<span class="flex-60">
<span>{{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyType.value }}</span>
<span
*ngIf="
loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyType.id === 3 &&
loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyWeekday
"
>
on {{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyWeekday.value }}</span
>
<span
*ngIf="
loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyType.id === 4 &&
loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyOnDay
"
>on day {{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyOnDay }}</span
>
<span
*ngIf="
loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyType.id === 4 &&
!loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyOnDay &&
loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyNthDay
"
>on
{{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyNthDay.value }}
{{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyWeekday.value }}</span
>
@if (
loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyType.id === 3 &&
loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyWeekday
) {
<span>
on {{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyWeekday.value }}</span
>
}
@if (
loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyType.id === 4 &&
loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyOnDay
) {
<span>on day {{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyOnDay }}</span>
}
@if (
loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyType.id === 4 &&
!loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyOnDay &&
loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyNthDay
) {
<span
>on
{{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyNthDay.value }}
{{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyWeekday.value }}</span
>
}
</span>
</div>
</ng-container>
}
<div
class="flex-100 layout-row"
*ngIf="
loansAccountTermsData?.isInterestRecalculationEnabled &&
loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyType.id !== 1
"
>
<span class="flex-40">{{ 'labels.inputs.Frequency Interval for recalculation' | translate }}</span>
<span class="flex-60">{{
loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyInterval
}}</span>
</div>
@if (
loansAccountTermsData?.isInterestRecalculationEnabled &&
loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyType.id !== 1
) {
<div class="flex-100 layout-row">
<span class="flex-40">{{ 'labels.inputs.Frequency Interval for recalculation' | translate }}</span>
<span class="flex-60">{{
loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyInterval
}}</span>
</div>
}
<div class="flex-100 layout-row">
<span class="flex-40"
@@ -482,19 +533,34 @@
<span class="flex-40">{{ enableBuyDownFee | yesNo }}</span>
</div>
<ng-container *ngIf="multiDisburseLoan">
@if (multiDisburseLoan) {
<mat-divider class="flex-98"></mat-divider>
<div class="flex-100 layout-row" *ngIf="allowAddDisbursementDetails()">
<h4 class="mat-h4 flex-98">{{ 'labels.heading.Loan Tranche Details' | translate }}</h4>
</div>
@if (allowAddDisbursementDetails()) {
<div class="flex-100 layout-row">
<h4 class="mat-h4 flex-98">{{ 'labels.heading.Loan Tranche Details' | translate }}</h4>
</div>
}
@if (isFullTermTrancheEditable()) {
<mat-checkbox
class="flex-48 margin-v"
labelPosition="before"
formControlName="allowFullTermForTranche"
matTooltip="{{ 'tooltips.Allow full term length for each tranche disbursement' | translate }}"
>
{{ 'labels.inputs.Allow full term for each tranche' | translate }}
</mat-checkbox>
}
<div class="flex-100 layout-row">
<mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.Maximum allowed outstanding balance' | translate }}</mat-label>
<input matInput type="number" formControlName="maxOutstandingLoanBalance" />
<mat-error *ngIf="loansAccountTermsForm.controls.maxOutstandingLoanBalance.hasError('required')">
{{ 'labels.inputs.Maximum allowed outstanding balance' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (loansAccountTermsForm.controls.maxOutstandingLoanBalance.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Maximum allowed outstanding balance' | translate }}
{{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<span class="flex-48">
<button
@@ -509,12 +575,13 @@
</button>
</span>
</div>
<div class="flex-100 layout-row" *ngIf="!allowAddDisbursementDetails()">
<h4 class="mat-h4 flex-98">
{{ 'labels.heading.Loan Tranche Details are not allowed for this Loan Product' | translate }}
</h4>
</div>
@if (!allowAddDisbursementDetails()) {
<div class="flex-100 layout-row">
<h4 class="mat-h4 flex-98">
{{ 'labels.heading.Loan Tranche Details are not allowed for this Loan Product' | translate }}
</h4>
</div>
}
<table mat-table [dataSource]="disbursementDataSource" [hidden]="disbursementDataSource.length === 0">
<ng-container matColumnDef="expectedDisbursementDate">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Expected Disbursement Date' | translate }}</th>
@@ -522,14 +589,12 @@
{{ row.expectedDisbursementDate | dateFormat }}
</td>
</ng-container>
<ng-container matColumnDef="principal">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Principal' | translate }}</th>
<td mat-cell *matCellDef="let row">
{{ row.principal }}
</td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Actions' | translate }}</th>
<td mat-cell *matCellDef="let row; let rowIndex = index">
@@ -545,65 +610,63 @@
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="disbursementDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: disbursementDisplayedColumns"></tr>
</table>
</ng-container>
}
<ng-container
*ngIf="
loansAccountTermsData?.isInterestRecalculationEnabled &&
loansAccountTermsData.interestRecalculationData.interestRecalculationCompoundingType.id !== 0
"
>
@if (
loansAccountTermsData?.isInterestRecalculationEnabled &&
loansAccountTermsData.interestRecalculationData.interestRecalculationCompoundingType.id !== 0
) {
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.Frequency for compounding' | translate }}</span>
<span class="flex-60"
>{{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyType.value }}
<span
*ngIf="
loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyType.id === 3 &&
loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyWeekday
"
>
on {{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyWeekday.value }}
</span>
<span
*ngIf="
loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyType.id === 4 &&
loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyOnDay
"
>on day
{{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyOnDay }}
</span>
<span
*ngIf="
loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyType.id === 4 &&
!loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyOnDay &&
loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyNthDay
"
>on
{{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyNthDay.value }}
{{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyWeekday.value }}
</span>
@if (
loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyType.id === 3 &&
loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyWeekday
) {
<span>
on {{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyWeekday.value }}
</span>
}
@if (
loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyType.id === 4 &&
loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyOnDay
) {
<span
>on day
{{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyOnDay }}
</span>
}
@if (
loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyType.id === 4 &&
!loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyOnDay &&
loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyNthDay
) {
<span
>on
{{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyNthDay.value }}
{{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyWeekday.value }}
</span>
}
</span>
</div>
</ng-container>
}
<div
class="flex-fill"
*ngIf="
loansAccountTermsData?.isInterestRecalculationEnabled &&
loansAccountTermsData.interestRecalculationData.interestRecalculationCompoundingType.id !== 0 &&
loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyType.id !== 1
"
>
<span class="flex-40">{{ 'labels.inputs.Frequency Interval for compounding' | translate }}</span>
<span class="flex-60">{{
loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyInterval
}}</span>
</div>
@if (
loansAccountTermsData?.isInterestRecalculationEnabled &&
loansAccountTermsData.interestRecalculationData.interestRecalculationCompoundingType.id !== 0 &&
loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyType.id !== 1
) {
<div class="flex-fill">
<span class="flex-40">{{ 'labels.inputs.Frequency Interval for compounding' | translate }}</span>
<span class="flex-60">{{
loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyInterval
}}</span>
</div>
}
<mat-divider class="flex-98"></mat-divider>
@@ -664,8 +727,10 @@
{{ 'labels.buttons.Next' | translate }}
<fa-icon icon="arrow-right" class="m-l-10"></fa-icon>
</button>
<button mat-raised-button *ngIf="loanId" [routerLink]="['../', 'general']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
@if (loanId) {
<button mat-raised-button [routerLink]="['../', 'general']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
}
</div>
</form>
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Component, OnInit, Input, OnChanges } from '@angular/core';
import { Component, OnInit, Input, OnChanges, inject } from '@angular/core';
import { UntypedFormGroup, UntypedFormBuilder, Validators, UntypedFormControl } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute } from '@angular/router';
@@ -77,6 +77,11 @@ interface DisbursementData {
]
})
export class LoansAccountTermsStepComponent implements OnInit, OnChanges {
private formBuilder = inject(UntypedFormBuilder);
private settingsService = inject(SettingsService);
private route = inject(ActivatedRoute);
dialog = inject(MatDialog);
/** Loans Product Options */
@Input() loansProductOptions: any;
/** Loans Account Product Template */
@@ -162,12 +167,7 @@ export class LoansAccountTermsStepComponent implements OnInit, OnChanges {
* @param formBuilder FormBuilder
* @param {SettingsService} settingsService SettingsService
*/
constructor(
private formBuilder: UntypedFormBuilder,
private settingsService: SettingsService,
private route: ActivatedRoute,
public dialog: MatDialog
) {
constructor() {
this.loanId = this.route.snapshot.params['loanId'];
this.createloansAccountTermsForm();
}
@@ -560,7 +560,6 @@ export class LoansAccountTermsStepComponent implements OnInit, OnChanges {
required: true,
order: 2
})
];
const data = {
title: 'Add Disbursement Details',
@@ -1,56 +1,55 @@
<div *ngIf="activeClientMembers" class="layout-row-wrap gap-2percent layout-xs-column">
<table class="flex-98" mat-table [dataSource]="dataSource">
<!-- Check Column -->
<ng-container matColumnDef="check">
<th mat-header-cell *matHeaderCellDef>
<mat-checkbox (change)="toggleSelects()" [(ngModel)]="selectAllItems"></mat-checkbox>
</th>
<td mat-cell *matCellDef="let element">
<mat-checkbox (change)="toggleSelect()" [(ngModel)]="element.selected"></mat-checkbox>
</td>
</ng-container>
<!-- Position Column -->
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Client ID' | translate }}</th>
<td mat-cell *matCellDef="let element">{{ element.id }}</td>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Client Name' | translate }}</th>
<td mat-cell *matCellDef="let element">{{ element.displayName }}</td>
</ng-container>
<!-- Weight Column -->
<ng-container matColumnDef="purpose">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Loan Purpose' | translate }}</th>
<td mat-cell *matCellDef="let element">
<mat-form-field>
<mat-label>{{ 'labels.inputs.Select Purpose' | translate }}</mat-label>
<mat-select [(ngModel)]="element.loanPurposeId">
<mat-option *ngFor="let purpose of loanPurposeOptions" [value]="purpose.id">
{{ purpose.name }}
</mat-option>
</mat-select>
</mat-form-field>
</td>
</ng-container>
<!-- Symbol Column -->
<ng-container matColumnDef="amount">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Original Loan' | translate }}</th>
<td mat-cell *matCellDef="let element">
<mat-form-field>
<input type="number" matInput [(ngModel)]="element.principal" />
</mat-form-field>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumn"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumn"></tr>
</table>
</div>
@if (activeClientMembers) {
<div class="layout-row-wrap gap-2percent layout-xs-column">
<table class="flex-98" mat-table [dataSource]="dataSource">
<!-- Check Column -->
<ng-container matColumnDef="check">
<th mat-header-cell *matHeaderCellDef>
<mat-checkbox (change)="toggleSelects()" [(ngModel)]="selectAllItems"></mat-checkbox>
</th>
<td mat-cell *matCellDef="let element">
<mat-checkbox (change)="toggleSelect()" [(ngModel)]="element.selected"></mat-checkbox>
</td>
</ng-container>
<!-- Position Column -->
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Client ID' | translate }}</th>
<td mat-cell *matCellDef="let element">{{ element.id }}</td>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Client Name' | translate }}</th>
<td mat-cell *matCellDef="let element">{{ element.displayName }}</td>
</ng-container>
<!-- Weight Column -->
<ng-container matColumnDef="purpose">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Loan Purpose' | translate }}</th>
<td mat-cell *matCellDef="let element">
<mat-form-field>
<mat-label>{{ 'labels.inputs.Select Purpose' | translate }}</mat-label>
<mat-select [(ngModel)]="element.loanPurposeId">
@for (purpose of loanPurposeOptions; track purpose) {
<mat-option [value]="purpose.id">
{{ purpose.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
</td>
</ng-container>
<!-- Symbol Column -->
<ng-container matColumnDef="amount">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Original Loan' | translate }}</th>
<td mat-cell *matCellDef="let element">
<mat-form-field>
<input type="number" matInput [(ngModel)]="element.principal" />
</mat-form-field>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumn"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumn"></tr>
</table>
</div>
}
<div class="layout-row responsive-column align-center gap-2px margin-t">
<button mat-raised-button matStepperPrevious>
@@ -61,7 +60,9 @@
{{ 'labels.buttons.Next' | translate }}
<fa-icon icon="arrow-right" class="m-l-10"></fa-icon>
</button>
<button mat-raised-button *ngIf="loanId" [routerLink]="['../', 'general']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
@if (loanId) {
<button mat-raised-button [routerLink]="['../', 'general']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
}
</div>
@@ -1,4 +1,4 @@
import { Component, OnInit, Input } from '@angular/core';
import { Component, OnInit, Input, inject } from '@angular/core';
import {
MatTableDataSource,
MatTable,
@@ -43,11 +43,13 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class LoansActiveClientMembersComponent implements OnInit {
private route = inject(ActivatedRoute);
loanId: any = null;
@Input() activeClientMembers?: any;
@Input() loansAccountFormValid: boolean;
constructor(private route: ActivatedRoute) {
constructor() {
this.loanId = this.route.snapshot.params['loanId'];
}
dataSource: any;
@@ -13,41 +13,46 @@
>{{ loanDetails.numberOfRepayments }} every {{ loanDetails.repaymentEvery }}&nbsp;{{
loanDetails.repaymentFrequencyType.value | translateKey: 'catalogs'
}}
<span
*ngIf="
loanDetails.repaymentFrequencyType?.id === 2 &&
loanDetails.repaymentFrequencyNthDayType?.id !== 0 &&
loanDetails.repaymentFrequencyDayOfWeekType?.id !== 0
"
class="m-l-10"
>
<span *ngIf="loanDetails.repaymentFrequencyDayOfWeekType">
<span class="m-l-10">{{ 'labels.commons.on' | translate }}</span
>{{ loanDetails.repaymentFrequencyNthDayType?.value }}
<span class="m-l-10">{{
loanDetails.repaymentFrequencyDayOfWeekType?.value | translateKey: 'catalogs'
}}</span>
@if (
loanDetails.repaymentFrequencyType?.id === 2 &&
loanDetails.repaymentFrequencyNthDayType?.id !== 0 &&
loanDetails.repaymentFrequencyDayOfWeekType?.id !== 0
) {
<span class="m-l-10">
@if (loanDetails.repaymentFrequencyDayOfWeekType) {
<span>
<span class="m-l-10">{{ 'labels.commons.on' | translate }}</span
>{{ loanDetails.repaymentFrequencyNthDayType?.value }}
<span class="m-l-10">{{
loanDetails.repaymentFrequencyDayOfWeekType?.value | translateKey: 'catalogs'
}}</span>
</span>
}
</span>
</span>
}
</span>
</div>
<div class="flex-fill layout-row" *ngIf="loanDetails.fixedLength">
<span class="flex-50"> {{ 'labels.inputs.Fixed Length' | translate }} </span>
<span class="flex-50">
{{ loanDetails.fixedLength }} {{ loanDetails.repaymentFrequencyType.value | translateKey: 'catalogs' }}</span
>
</div>
@if (loanDetails.fixedLength) {
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Fixed Length' | translate }} </span>
<span class="flex-50">
{{ loanDetails.fixedLength }} {{ loanDetails.repaymentFrequencyType.value | translateKey: 'catalogs' }}</span
>
</div>
}
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Amortization' | translate }} </span>
<span class="flex-50"> {{ loanDetails.amortizationType.value | translateKey: 'catalogs' }} </span>
</div>
<div class="flex-fill layout-row" *ngIf="loanDetails.fixedPrincipalPercentagePerInstallment">
<span class="flex-50"> {{ 'labels.inputs.Principal Percentage Per Installment' | translate }} </span>
<span class="flex-50"> {{ loanDetails.fixedPrincipalPercentagePerInstallment | formatNumber }} %</span>
</div>
@if (loanDetails.fixedPrincipalPercentagePerInstallment) {
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Principal Percentage Per Installment' | translate }} </span>
<span class="flex-50"> {{ loanDetails.fixedPrincipalPercentagePerInstallment | formatNumber }} %</span>
</div>
}
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Equal Amortization' | translate }} </span>
@@ -84,49 +89,63 @@
<span class="flex-50"> {{ loanDetails.enableIncomeCapitalization | yesNo }} </span>
</div>
<div class="flex-fill layout-row" *ngIf="loanDetails.enableIncomeCapitalization">
<span class="flex-50"> {{ 'labels.inputs.Income capitalization calculation type' | translate }}</span>
<span class="flex-50">
{{ loanDetails.capitalizedIncomeCalculationType?.value | translateKey: 'catalogs' }}
</span>
</div>
@if (loanDetails.enableIncomeCapitalization) {
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Income capitalization calculation type' | translate }}</span>
<span class="flex-50">
{{ loanDetails.capitalizedIncomeCalculationType?.value | translateKey: 'catalogs' }}
</span>
</div>
}
<div class="flex-fill layout-row" *ngIf="loanDetails.enableIncomeCapitalization">
<span class="flex-50"> {{ 'labels.inputs.Income capitalization strategy' | translate }}</span>
<span class="flex-50"> {{ loanDetails.capitalizedIncomeStrategy?.value | translateKey: 'catalogs' }} </span>
</div>
@if (loanDetails.enableIncomeCapitalization) {
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Income capitalization strategy' | translate }}</span>
<span class="flex-50"> {{ loanDetails.capitalizedIncomeStrategy?.value | translateKey: 'catalogs' }} </span>
</div>
}
<div class="flex-fill layout-row" *ngIf="loanDetails.enableIncomeCapitalization">
<span class="flex-50"> {{ 'labels.inputs.Income capitalization type' | translate }}</span>
<span class="flex-50"> {{ loanDetails.capitalizedIncomeType?.value | translateKey: 'catalogs' }} </span>
</div>
@if (loanDetails.enableIncomeCapitalization) {
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Income capitalization type' | translate }}</span>
<span class="flex-50"> {{ loanDetails.capitalizedIncomeType?.value | translateKey: 'catalogs' }} </span>
</div>
}
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Enable Buy down fee' | translate }}</span>
<span class="flex-50"> {{ loanDetails.enableBuyDownFee | yesNo }} </span>
</div>
<div class="flex-fill layout-row" *ngIf="loanDetails.enableBuyDownFee">
<span class="flex-50"> {{ 'labels.inputs.Buy down fee calculation type' | translate }}</span>
<span class="flex-50">
{{ loanDetails.buyDownFeeCalculationType?.value | translateKey: 'catalogs' }}
</span>
</div>
@if (loanDetails.enableBuyDownFee) {
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Buy down fee calculation type' | translate }}</span>
<span class="flex-50">
{{ loanDetails.buyDownFeeCalculationType?.value | translateKey: 'catalogs' }}
</span>
</div>
}
<div class="flex-fill layout-row" *ngIf="loanDetails.enableBuyDownFee">
<span class="flex-50"> {{ 'labels.inputs.Buy down fee strategy' | translate }}</span>
<span class="flex-50"> {{ loanDetails.buyDownFeeStrategy?.value | translateKey: 'catalogs' }} </span>
</div>
@if (loanDetails.enableBuyDownFee) {
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Buy down fee strategy' | translate }}</span>
<span class="flex-50"> {{ loanDetails.buyDownFeeStrategy?.value | translateKey: 'catalogs' }} </span>
</div>
}
<div class="flex-fill layout-row" *ngIf="loanDetails.enableBuyDownFee">
<span class="flex-50"> {{ 'labels.inputs.Buy down fee income type' | translate }}</span>
<span class="flex-50"> {{ loanDetails.buyDownFeeIncomeType?.value | translateKey: 'catalogs' }} </span>
</div>
@if (loanDetails.enableBuyDownFee) {
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Buy down fee income type' | translate }}</span>
<span class="flex-50"> {{ loanDetails.buyDownFeeIncomeType?.value | translateKey: 'catalogs' }} </span>
</div>
}
<div class="flex-fill layout-row" *ngIf="loanDetails.enableBuyDownFee">
<span class="flex-50"> {{ 'labels.inputs.Merchant Buy down fee' | translate }}</span>
<span class="flex-50"> {{ loanDetails.merchantBuyDownFee | yesNo }} </span>
</div>
@if (loanDetails.enableBuyDownFee) {
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Merchant Buy down fee' | translate }}</span>
<span class="flex-50"> {{ loanDetails.merchantBuyDownFee | yesNo }} </span>
</div>
}
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Grace: On Principal Payment' | translate }}</span>
@@ -150,8 +169,12 @@
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Fund Source' | translate }} </span>
<span class="flex-50" *ngIf="loanDetails.fundName"> {{ loanDetails.fundName }} </span>
<span class="flex-50" *ngIf="!loanDetails.fundName"> {{ 'labels.inputs.Unassigned' | translate }} </span>
@if (loanDetails.fundName) {
<span class="flex-50"> {{ loanDetails.fundName }} </span>
}
@if (!loanDetails.fundName) {
<span class="flex-50"> {{ 'labels.inputs.Unassigned' | translate }} </span>
}
</div>
<div class="flex-fill layout-row">
@@ -196,27 +219,35 @@
<span class="flex-50"> {{ loanDetails.timeline.expectedMaturityDate | dateFormat }} </span>
</div>
<div class="flex-fill layout-row" *ngIf="loanDetails.canDefineInstallmentAmount">
<span class="flex-50"> {{ 'labels.inputs.Fixed EMI amount' | translate }}</span>
<span class="flex-50"> {{ loanDetails.fixedEmiAmount | formatNumber }} </span>
</div>
@if (loanDetails.canDefineInstallmentAmount) {
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Fixed EMI amount' | translate }}</span>
<span class="flex-50"> {{ loanDetails.fixedEmiAmount | formatNumber }} </span>
</div>
}
<div class="flex-fill layout-row" *ngIf="loanDetails.isTopup">
<span class="flex-50"> {{ 'labels.inputs.Is Topup Loan' | translate }}?</span>
<span class="flex-50"> {{ loanDetails.isTopup | yesNo }} </span>
</div>
@if (loanDetails.isTopup) {
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Is Topup Loan' | translate }}?</span>
<span class="flex-50"> {{ loanDetails.isTopup | yesNo }} </span>
</div>
}
<div class="flex-fill layout-row" *ngIf="loanDetails.isTopup">
<span class="flex-50"> {{ 'labels.inputs.Loan closed with Topup' | translate }} </span>
<span class="flex-50">
<a href="#">{{ loanDetails.closureLoanAccountNo }}</a>
</span>
</div>
@if (loanDetails.isTopup) {
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Loan closed with Topup' | translate }} </span>
<span class="flex-50">
<a href="#">{{ loanDetails.closureLoanAccountNo }}</a>
</span>
</div>
}
<div class="flex-fill layout-row" *ngIf="loanDetails.isTopup">
<span class="flex-50"> {{ 'labels.inputs.Topup closure amount' | translate }}</span>
<span class="flex-50"> {{ loanDetails.topupAmount | formatNumber }} </span>
</div>
@if (loanDetails.isTopup) {
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Topup closure amount' | translate }}</span>
<span class="flex-50"> {{ loanDetails.topupAmount | formatNumber }} </span>
</div>
}
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Recalculate Interest based on new terms' | translate }}</span>
@@ -233,64 +264,72 @@
<span class="flex-50"> {{ loanDetails.daysInMonthType.value | translateKey: 'catalogs' }} </span>
</div>
<div class="flex-fill layout-row" *ngIf="loanDetails.isInterestRecalculationEnabled">
<span class="flex-50"> {{ 'labels.inputs.Interest recalculation compounding on' | translate }}</span>
<span class="flex-50">
{{
loanDetails.interestRecalculationData.interestRecalculationCompoundingType.value | translateKey: 'catalogs'
}}
</span>
</div>
@if (loanDetails.isInterestRecalculationEnabled) {
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Interest recalculation compounding on' | translate }}</span>
<span class="flex-50">
{{
loanDetails.interestRecalculationData.interestRecalculationCompoundingType.value | translateKey: 'catalogs'
}}
</span>
</div>
}
<div class="flex-fill layout-row" *ngIf="loanDetails.isInterestRecalculationEnabled">
<span class="flex-50"> {{ 'labels.inputs.Advance payments adjustment type' | translate }}</span>
<span class="flex-50">
{{ loanDetails.interestRecalculationData.rescheduleStrategyType.value | translateKey: 'catalogs' }}
</span>
</div>
@if (loanDetails.isInterestRecalculationEnabled) {
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Advance payments adjustment type' | translate }}</span>
<span class="flex-50">
{{ loanDetails.interestRecalculationData.rescheduleStrategyType.value | translateKey: 'catalogs' }}
</span>
</div>
}
<div class="flex-fill layout-row" *ngIf="loanDetails.isInterestRecalculationEnabled">
<span class="flex-50"> {{ 'labels.inputs.Frequency for recalculate Outstanding Principal' | translate }}</span>
<span class="flex-50"> {{ loanDetails.interestRecalculationData.calendarData.humanReadable }} </span>
</div>
@if (loanDetails.isInterestRecalculationEnabled) {
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Frequency for recalculate Outstanding Principal' | translate }}</span>
<span class="flex-50"> {{ loanDetails.interestRecalculationData.calendarData.humanReadable }} </span>
</div>
}
<div
class="flex-fill layout-row"
*ngIf="
loanDetails.isInterestRecalculationEnabled &&
loanDetails.interestRecalculationData.interestRecalculationCompoundingType.id !== 0
"
>
<span class="flex-50"> {{ 'labels.inputs.Frequency for compounding' | translate }}</span>
<span class="flex-50"> {{ loanDetails.interestRecalculationData.compoundingCalendarData.humanReadable }} </span>
</div>
@if (
loanDetails.isInterestRecalculationEnabled &&
loanDetails.interestRecalculationData.interestRecalculationCompoundingType.id !== 0
) {
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Frequency for compounding' | translate }}</span>
<span class="flex-50"> {{ loanDetails.interestRecalculationData.compoundingCalendarData.humanReadable }} </span>
</div>
}
<div class="flex-fill layout-row" *ngIf="loanDetails.isVariableInstallmentsAllowed">
<span class="flex-50"> {{ 'labels.inputs.Variable Installments Allowed' | translate }}</span>
<span class="flex-50"> {{ loanDetails.isVariableInstallmentsAllowed | yesNo }} </span>
</div>
@if (loanDetails.isVariableInstallmentsAllowed) {
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Variable Installments Allowed' | translate }}</span>
<span class="flex-50"> {{ loanDetails.isVariableInstallmentsAllowed | yesNo }} </span>
</div>
}
<div class="flex-fill layout-row" *ngIf="loanDetails.isVariableInstallmentsAllowed">
<span class="flex-50"> {{ 'labels.inputs.Gap between Installments' | translate }}</span>
<span class="flex-50">
{{ loanDetails.minimumGap | formatNumber }}&nbsp;{{ 'labels.text.Days' | translate }}&nbsp;, Max:{{
loanDetails.maximumGap | formatNumber
}}&nbsp;{{ 'labels.text.Days' | translate }}
</span>
</div>
@if (loanDetails.isVariableInstallmentsAllowed) {
<div class="flex-fill layout-row">
<span class="flex-50"> {{ 'labels.inputs.Gap between Installments' | translate }}</span>
<span class="flex-50">
{{ loanDetails.minimumGap | formatNumber }}&nbsp;{{ 'labels.text.Days' | translate }}&nbsp;, Max:{{
loanDetails.maximumGap | formatNumber
}}&nbsp;{{ 'labels.text.Days' | translate }}
</span>
</div>
}
<div
class="flex-fill layout-row"
*ngIf="
loanDetails &&
loanDetails.delinquent &&
loanDetails.delinquent.availableDisbursementAmountWithOverApplied !== undefined
"
>
<span class="flex-50">{{ 'labels.inputs.Available Disbursement Amount (with Over Applied)' | translate }}</span>
<span class="flex-50">{{
loanDetails.delinquent.availableDisbursementAmountWithOverApplied | formatNumber
}}</span>
</div>
@if (
loanDetails &&
loanDetails.delinquent &&
loanDetails.delinquent.availableDisbursementAmountWithOverApplied !== undefined
) {
<div class="flex-fill layout-row">
<span class="flex-50">{{ 'labels.inputs.Available Disbursement Amount (with Over Applied)' | translate }}</span>
<span class="flex-50">{{
loanDetails.delinquent.availableDisbursementAmountWithOverApplied | formatNumber
}}</span>
</div>
}
</div>
</div>
@@ -1,4 +1,4 @@
import { Component } from '@angular/core';
import { Component, inject } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { DateFormatPipe } from '../../../pipes/date-format.pipe';
import { FormatNumberPipe } from '../../../pipes/format-number.pipe';
@@ -17,13 +17,15 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class AccountDetailsComponent {
private route = inject(ActivatedRoute);
loanDetails: any;
dataObject: {
property: string;
value: string;
}[];
constructor(private route: ActivatedRoute) {
constructor() {
this.route.parent.data.subscribe((data: { loanDetailsData: any }) => {
this.loanDetails = data.loanDetailsData;
});
@@ -8,8 +8,12 @@
<ng-container matColumnDef="feepenalty">
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'labels.inputs.Fee/Penalty' | translate }}</th>
<td mat-cell *matCellDef="let charge">
<span *ngIf="charge.penalty">{{ 'labels.inputs.Penalty' | translate }}</span>
<span *ngIf="!charge.penalty">{{ 'labels.inputs.Fee' | translate }}</span>
@if (charge.penalty) {
<span>{{ 'labels.inputs.Penalty' | translate }}</span>
}
@if (!charge.penalty) {
<span>{{ 'labels.inputs.Fee' | translate }}</span>
}
</td>
</ng-container>
@@ -25,12 +29,20 @@
<ng-container matColumnDef="dueDate">
<th mat-header-cell *matHeaderCellDef mat-sort-header [hide]="useDueDate">
<span *ngIf="useDueDate"> {{ 'labels.inputs.Due As Of' | translate }} </span>
<span *ngIf="!useDueDate"> {{ 'labels.inputs.Submitted On' | translate }} </span>
@if (useDueDate) {
<span> {{ 'labels.inputs.Due As Of' | translate }} </span>
}
@if (!useDueDate) {
<span> {{ 'labels.inputs.Submitted On' | translate }} </span>
}
</th>
<td mat-cell *matCellDef="let charge">
<span *ngIf="useDueDate">{{ charge.dueDate | dateFormat }}</span>
<span *ngIf="!useDueDate">{{ charge.submittedOnDate | dateFormat }}</span>
@if (useDueDate) {
<span>{{ charge.dueDate | dateFormat }}</span>
}
@if (!useDueDate) {
<span>{{ charge.submittedOnDate | dateFormat }}</span>
}
</td>
</ng-container>
@@ -76,56 +88,61 @@
{{ 'labels.inputs.Actions' | translate }}
</th>
<td mat-cell class="center" *matCellDef="let charge">
<span *ngIf="status === 'Submitted and pending approval'">
@if (status === 'Submitted and pending approval') {
<span>
<button
class="account-action-button"
mat-raised-button
color="primary"
matTooltip="{{ 'tooltips.Edit Charge' | translate }}"
(click)="routeEdit($event); editCharge(charge)"
>
<i class="fa fa-pencil"></i>
</button>
<button
class="account-action-button"
mat-raised-button
color="warn"
matTooltip="{{ 'tooltips.Delete Charge' | translate }}"
(click)="routeEdit($event); deleteCharge(charge.id)"
>
<i class="fa fa-trash"></i>
</button>
</span>
}
@if (!charge.paid && status === 'Active') {
<button
class="account-action-button"
mat-raised-button
color="accent"
matTooltip="{{ 'tooltips.Adjust Charge' | translate }}"
(click)="routeEdit($event); adjustCharge(charge.id)"
>
<i class="fa fa-pencil"></i>
</button>
}
@if (charge.chargePayable && !charge.paid && status === 'Active') {
<button
class="account-action-button"
mat-raised-button
color="primary"
matTooltip="{{ 'tooltips.Edit Charge' | translate }}"
(click)="routeEdit($event); editCharge(charge)"
matTooltip="{{ 'tooltips.Pay Charge' | translate }}"
(click)="routeEdit($event); payCharge(charge.id)"
>
<i class="fa fa-pencil"></i>
<i class="fa fa-dollar"></i>
</button>
}
@if (!charge.actionFlag) {
<button
class="account-action-button"
mat-raised-button
color="warn"
matTooltip="{{ 'tooltips.Delete Charge' | translate }}"
(click)="routeEdit($event); deleteCharge(charge.id)"
color="primary"
matTooltip="{{ 'tooltips.Waive Charge' | translate }}"
(click)="routeEdit($event); waiveCharge(charge.id)"
>
<i class="fa fa-trash"></i>
<i class="fa fa-flag"></i>
</button>
</span>
<button
class="account-action-button"
mat-raised-button
color="accent"
matTooltip="{{ 'tooltips.Adjust Charge' | translate }}"
*ngIf="!charge.paid && status === 'Active'"
(click)="routeEdit($event); adjustCharge(charge.id)"
>
<i class="fa fa-pencil"></i>
</button>
<button
class="account-action-button"
mat-raised-button
color="primary"
matTooltip="{{ 'tooltips.Pay Charge' | translate }}"
*ngIf="charge.chargePayable && !charge.paid && status === 'Active'"
(click)="routeEdit($event); payCharge(charge.id)"
>
<i class="fa fa-dollar"></i>
</button>
<button
class="account-action-button"
mat-raised-button
color="primary"
matTooltip="{{ 'tooltips.Waive Charge' | translate }}"
*ngIf="!charge.actionFlag"
(click)="routeEdit($event); waiveCharge(charge.id)"
>
<i class="fa fa-flag"></i>
</button>
}
</td>
</ng-container>
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Component, OnInit, ViewChild } from '@angular/core';
import { Component, OnInit, ViewChild, inject } from '@angular/core';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { MatDialog } from '@angular/material/dialog';
import { MatPaginator } from '@angular/material/paginator';
@@ -35,7 +35,7 @@ import { Dates } from 'app/core/utils/dates';
import { SystemService } from 'app/system/system.service';
import { GlobalConfiguration } from 'app/system/configurations/global-configurations-tab/configuration.model';
import { TranslateService } from '@ngx-translate/core';
import { NgIf, CurrencyPipe } from '@angular/common';
import { CurrencyPipe } from '@angular/common';
import { MatTooltip } from '@angular/material/tooltip';
import { DateFormatPipe } from '../../../pipes/date-format.pipe';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
@@ -65,6 +65,15 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class ChargesTabComponent implements OnInit {
private loansService = inject(LoansService);
private route = inject(ActivatedRoute);
private dateUtils = inject(Dates);
private router = inject(Router);
private translateService = inject(TranslateService);
dialog = inject(MatDialog);
private settingsService = inject(SettingsService);
private systemService = inject(SystemService);
/** Loan Details Data */
loanDetails: any;
/** Charges Data */
@@ -99,16 +108,7 @@ export class ChargesTabComponent implements OnInit {
* @param {ActivatedRoute} route Activated Route.
* @param {SettingsService} settingsService Settings Service
*/
constructor(
private loansService: LoansService,
private route: ActivatedRoute,
private dateUtils: Dates,
private router: Router,
private translateService: TranslateService,
public dialog: MatDialog,
private settingsService: SettingsService,
private systemService: SystemService
) {
constructor() {
this.route.parent.data.subscribe((data: { loanDetailsData: any }) => {
this.loanDetails = data.loanDetailsData;
});
@@ -164,7 +164,6 @@ export class ChargesTabComponent implements OnInit {
type: 'date',
required: true
})
];
const data = {
title: `Pay Charge ${chargeId}`,
@@ -229,7 +228,6 @@ export class ChargesTabComponent implements OnInit {
type: 'number',
required: true
})
];
const data = {
title: `Edit Charge ${charge.id}`,
@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, inject } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { EntityDatatableTabComponent } from '../../../shared/tabs/entity-datatable-tab/entity-datatable-tab.component';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
@@ -13,6 +13,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class DatatableTabComponent implements OnInit {
private route = inject(ActivatedRoute);
entityId: string;
/** Loan Datatable */
entityDatatable: any = null;
@@ -23,7 +25,7 @@ export class DatatableTabComponent implements OnInit {
* Fetches data table data from `resolve`
* @param {ActivatedRoute} route Activated Route.
*/
constructor(private route: ActivatedRoute) {
constructor() {
this.entityId = this.route.parent.parent.snapshot.paramMap.get('loanId');
this.entityDatatable = null;
this.route.data.subscribe((data: { loanDatatable: any }) => {
@@ -1,200 +1,210 @@
<div class="tab-container mat-typography">
<div class="flex-fill" *ngIf="existActiveTransfer">
<h3>{{ 'labels.heading.Active Asset Transfer' | translate }}</h3>
<div class="layout-row gap-32px asset-transfer-container">
<table>
<tbody>
<tr>
<td class="flex-25">
<b>{{ 'labels.inputs.Status' | translate }} :</b>
</td>
<td class="flex-25 left">
<div [ngClass]="itemStatus(activeTransferData.status)">
<fa-icon icon="stop"></fa-icon>
<span class="m-l-10 external-asset-owner-status">{{ activeTransferData.status }}</span>
</div>
</td>
<td class="flex-25">
<b>{{ 'labels.inputs.Owner External Id' | translate }} :</b>
</td>
<td class="flex-25 left">
<mifosx-external-identifier
externalId="{{ activeTransferData.owner.externalId }}"
completed="true"
></mifosx-external-identifier>
</td>
</tr>
<tr>
<td class="flex-25">
<b>{{ 'labels.inputs.Settlement Date' | translate }} :</b>
</td>
<td class="flex-25 left">
{{ activeTransferData.settlementDate | dateFormat }}
</td>
<td class="flex-25">
<b>{{ 'labels.inputs.Effective Date' | translate }} :</b>
</td>
<td class="flex-25 left">
{{ activeTransferData.effectiveFrom | dateFormat }}
</td>
</tr>
<tr>
<td class="flex-25">
<b>{{ 'labels.inputs.Details' | translate }} :</b>
</td>
<td class="flex-75 left">
<table>
<tbody>
<tr>
<td class="flex-50">
<b>{{ 'labels.inputs.Principal Outstanding' | translate }} :</b>
</td>
<td class="flex-50 r-amount">
{{ activeTransferData.details.totalPrincipalOutstanding | formatNumber }}
</td>
</tr>
<tr>
<td class="flex-50">
<b>{{ 'labels.inputs.Interest Outstanding' | translate }} :</b>
</td>
<td class="flex-50 r-amount">
{{ activeTransferData.details.totalInterestOutstanding | formatNumber }}
</td>
</tr>
<tr>
<td class="flex-50">
<b>{{ 'labels.inputs.Fees Outstanding' | translate }} :</b>
</td>
<td class="flex-50 r-amount">
{{ activeTransferData.details.totalFeeChargesOutstanding | formatNumber }}
</td>
</tr>
<tr>
<td class="flex-50">
<b>{{ 'labels.inputs.Penalties Outstanding' | translate }} :</b>
</td>
<td class="flex-50 r-amount">
{{ activeTransferData.details.totalPenaltyChargesOutstanding | formatNumber }}
</td>
</tr>
<tr>
<td class="flex-50">
<b>{{ 'labels.inputs.Outstanding' | translate }} :</b>
</td>
<td class="flex-50 r-amount">
{{ activeTransferData.details.totalOutstanding | formatNumber }}
</td>
</tr>
<tr>
<td class="flex-50">
<b>{{ 'labels.inputs.Overpaid' | translate }} :</b>
</td>
<td class="flex-50 r-amount">{{ activeTransferData.details.totalOverpaid | formatNumber }}</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
@if (existActiveTransfer) {
<div class="flex-fill">
<h3>{{ 'labels.heading.Active Asset Transfer' | translate }}</h3>
<div class="layout-row gap-32px asset-transfer-container">
<table>
<tbody>
<tr>
<td class="flex-25">
<b>{{ 'labels.inputs.Status' | translate }} :</b>
</td>
<td class="flex-25 left">
<div [ngClass]="itemStatus(activeTransferData.status)">
<fa-icon icon="stop"></fa-icon>
<span class="m-l-10 external-asset-owner-status">{{ activeTransferData.status }}</span>
</div>
</td>
<td class="flex-25">
<b>{{ 'labels.inputs.Owner External Id' | translate }} :</b>
</td>
<td class="flex-25 left">
<mifosx-external-identifier
externalId="{{ activeTransferData.owner.externalId }}"
completed="true"
></mifosx-external-identifier>
</td>
</tr>
<tr>
<td class="flex-25">
<b>{{ 'labels.inputs.Settlement Date' | translate }} :</b>
</td>
<td class="flex-25 left">
{{ activeTransferData.settlementDate | dateFormat }}
</td>
<td class="flex-25">
<b>{{ 'labels.inputs.Effective Date' | translate }} :</b>
</td>
<td class="flex-25 left">
{{ activeTransferData.effectiveFrom | dateFormat }}
</td>
</tr>
<tr>
<td class="flex-25">
<b>{{ 'labels.inputs.Details' | translate }} :</b>
</td>
<td class="flex-75 left">
<table>
<tbody>
<tr>
<td class="flex-50">
<b>{{ 'labels.inputs.Principal Outstanding' | translate }} :</b>
</td>
<td class="flex-50 r-amount">
{{ activeTransferData.details.totalPrincipalOutstanding | formatNumber }}
</td>
</tr>
<tr>
<td class="flex-50">
<b>{{ 'labels.inputs.Interest Outstanding' | translate }} :</b>
</td>
<td class="flex-50 r-amount">
{{ activeTransferData.details.totalInterestOutstanding | formatNumber }}
</td>
</tr>
<tr>
<td class="flex-50">
<b>{{ 'labels.inputs.Fees Outstanding' | translate }} :</b>
</td>
<td class="flex-50 r-amount">
{{ activeTransferData.details.totalFeeChargesOutstanding | formatNumber }}
</td>
</tr>
<tr>
<td class="flex-50">
<b>{{ 'labels.inputs.Penalties Outstanding' | translate }} :</b>
</td>
<td class="flex-50 r-amount">
{{ activeTransferData.details.totalPenaltyChargesOutstanding | formatNumber }}
</td>
</tr>
<tr>
<td class="flex-50">
<b>{{ 'labels.inputs.Outstanding' | translate }} :</b>
</td>
<td class="flex-50 r-amount">
{{ activeTransferData.details.totalOutstanding | formatNumber }}
</td>
</tr>
<tr>
<td class="flex-50">
<b>{{ 'labels.inputs.Overpaid' | translate }} :</b>
</td>
<td class="flex-50 r-amount">{{ activeTransferData.details.totalOverpaid | formatNumber }}</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
}
<div class="layout-row align-start-center">
<h3 class="flex-90">{{ 'labels.heading.External Asset Owner' | translate }}</h3>
<div class="flex-10" *ngIf="canBeSold()">
<button mat-raised-button class="f-right" color="primary" (click)="saleLoan()" *mifosxHasPermission="'SALE_LOAN'">
<fa-icon icon="dollar-sign" class="m-r-10"></fa-icon>{{ 'labels.buttons.Sell Loan' | translate }}
</button>
</div>
@if (canBeSold()) {
<div class="flex-10">
<button
mat-raised-button
class="f-right"
color="primary"
(click)="saleLoan()"
*mifosxHasPermission="'SALE_LOAN'"
>
<fa-icon icon="dollar-sign" class="m-r-10"></fa-icon>{{ 'labels.buttons.Sell Loan' | translate }}
</button>
</div>
}
<div class="flex-10" *ngIf="canBeCancelled()">
<button
mat-raised-button
class="f-right"
color="warn"
(click)="cancelSaleLoan()"
*mifosxHasPermission="'SALE_LOAN'"
>
<fa-icon icon="trash" class="m-r-10"></fa-icon>{{ 'labels.buttons.Cancel Sell Loan' | translate }}
</button>
</div>
@if (canBeCancelled()) {
<div class="flex-10">
<button
mat-raised-button
class="f-right"
color="warn"
(click)="cancelSaleLoan()"
*mifosxHasPermission="'SALE_LOAN'"
>
<fa-icon icon="trash" class="m-r-10"></fa-icon>{{ 'labels.buttons.Cancel Sell Loan' | translate }}
</button>
</div>
}
<div class="flex-10" *ngIf="canBeBuyed()">
<button
mat-raised-button
class="f-right"
color="primary"
(click)="buyBackLoan()"
*mifosxHasPermission="'SALE_LOAN'"
>
<fa-icon icon="dollar-sign" class="m-r-10"></fa-icon>{{ 'labels.buttons.Buy Back Loan' | translate }}
</button>
</div>
@if (canBeBuyed()) {
<div class="flex-10">
<button
mat-raised-button
class="f-right"
color="primary"
(click)="buyBackLoan()"
*mifosxHasPermission="'SALE_LOAN'"
>
<fa-icon icon="dollar-sign" class="m-r-10"></fa-icon>{{ 'labels.buttons.Buy Back Loan' | translate }}
</button>
</div>
}
</div>
<table mat-table mat-sort [dataSource]="loanTransfersData" *ngIf="loanTransfersData.length > 0">
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Status' | translate }}</th>
<td mat-cell *matCellDef="let item">
<div [ngClass]="itemStatus(item.status)">
<fa-icon icon="stop"></fa-icon>
<span class="m-l-10 status">
{{ itemCurrentStatus(item) | translate }}
</span>
</div>
</td>
</ng-container>
<ng-container matColumnDef="effectiveFrom">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Effective From' | translate }}</th>
<td mat-cell *matCellDef="let item">{{ item.effectiveFrom | dateFormat }}</td>
</ng-container>
<ng-container matColumnDef="ownerExternalId">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Owner External Id' | translate }}</th>
<td mat-cell *matCellDef="let item">
<mifosx-external-identifier externalId="{{ item.owner.externalId }}"></mifosx-external-identifier>
</td>
</ng-container>
<ng-container matColumnDef="transferExternalId">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Transfer External Id' | translate }}</th>
<td mat-cell *matCellDef="let item">
<mifosx-external-identifier externalId="{{ item.transferExternalId }}"></mifosx-external-identifier>
</td>
</ng-container>
<ng-container matColumnDef="settlementDate">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Settlement Date' | translate }}</th>
<td mat-cell *matCellDef="let item">{{ item.settlementDate | dateFormat }}</td>
</ng-container>
<ng-container matColumnDef="purchasePriceRatio">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Purchase Price Ratio' | translate }}</th>
<td mat-cell *matCellDef="let item">{{ item.purchasePriceRatio | number }}</td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell class="center" *matHeaderCellDef>{{ 'labels.inputs.Actions' | translate }}</th>
<td mat-cell *matCellDef="let item" class="center td-min-space">
<button
class="account-action-button"
*ngIf="!isPendingOrCanceled(item)"
mat-raised-button
color="primary"
matTooltip="{{ 'tooltips.View Journal Entries' | translate }}"
matTooltipPosition="left"
(click)="routeJournalEntry($event)"
[routerLink]="['/', 'journal-entry', 'view-transfer', item.transferId]"
>
<i class="fa fa-arrow-circle-right"></i>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="loanTransferColumns"></tr>
<tr mat-row *matRowDef="let row; columns: loanTransferColumns"></tr>
</table>
@if (loanTransfersData.length > 0) {
<table mat-table mat-sort [dataSource]="loanTransfersData">
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Status' | translate }}</th>
<td mat-cell *matCellDef="let item">
<div [ngClass]="itemStatus(item.status)">
<fa-icon icon="stop"></fa-icon>
<span class="m-l-10 status">
{{ itemCurrentStatus(item) | translate }}
</span>
</div>
</td>
</ng-container>
<ng-container matColumnDef="effectiveFrom">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Effective From' | translate }}</th>
<td mat-cell *matCellDef="let item">{{ item.effectiveFrom | dateFormat }}</td>
</ng-container>
<ng-container matColumnDef="ownerExternalId">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Owner External Id' | translate }}</th>
<td mat-cell *matCellDef="let item">
<mifosx-external-identifier externalId="{{ item.owner.externalId }}"></mifosx-external-identifier>
</td>
</ng-container>
<ng-container matColumnDef="transferExternalId">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Transfer External Id' | translate }}</th>
<td mat-cell *matCellDef="let item">
<mifosx-external-identifier externalId="{{ item.transferExternalId }}"></mifosx-external-identifier>
</td>
</ng-container>
<ng-container matColumnDef="settlementDate">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Settlement Date' | translate }}</th>
<td mat-cell *matCellDef="let item">{{ item.settlementDate | dateFormat }}</td>
</ng-container>
<ng-container matColumnDef="purchasePriceRatio">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Purchase Price Ratio' | translate }}</th>
<td mat-cell *matCellDef="let item">{{ item.purchasePriceRatio | number }}</td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell class="center" *matHeaderCellDef>{{ 'labels.inputs.Actions' | translate }}</th>
<td mat-cell *matCellDef="let item" class="center td-min-space">
@if (!isPendingOrCanceled(item)) {
<button
class="account-action-button"
mat-raised-button
color="primary"
matTooltip="{{ 'tooltips.View Journal Entries' | translate }}"
matTooltipPosition="left"
(click)="routeJournalEntry($event)"
[routerLink]="['/', 'journal-entry', 'view-transfer', item.transferId]"
>
<i class="fa fa-arrow-circle-right"></i>
</button>
}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="loanTransferColumns"></tr>
<tr mat-row *matRowDef="let row; columns: loanTransferColumns"></tr>
</table>
}
</div>
@@ -1,10 +1,10 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, inject } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { ExternalAssetOwner } from 'app/loans/services/external-asset-owner';
import { ExternalAssetOwnerService } from 'app/loans/services/external-asset-owner.service';
import { CancelDialogComponent } from 'app/shared/cancel-dialog/cancel-dialog.component';
import { NgIf, NgClass, DecimalPipe } from '@angular/common';
import { NgClass, DecimalPipe } from '@angular/common';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
import { ExternalIdentifierComponent } from '../../../shared/external-identifier/external-identifier.component';
import {
@@ -50,6 +50,12 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class ExternalAssetOwnerTabComponent implements OnInit {
private route = inject(ActivatedRoute);
private router = inject(Router);
private dialog = inject(MatDialog);
private externalAssetOwner = inject(ExternalAssetOwner);
private externalAssetOwnerService = inject(ExternalAssetOwnerService);
defaultDate = '9999-12-31';
loanTransfersData: any[] = [];
activeTransferData: any;
@@ -66,13 +72,7 @@ export class ExternalAssetOwnerTabComponent implements OnInit {
currentItem: any;
existActiveTransfer = false;
constructor(
private route: ActivatedRoute,
private router: Router,
private dialog: MatDialog,
private externalAssetOwner: ExternalAssetOwner,
private externalAssetOwnerService: ExternalAssetOwnerService
) {
constructor() {
this.route.data.subscribe((data: { loanTransfersData: any; activeTransferData: any }) => {
this.loanTransfersData = data.loanTransfersData.empty ? [] : data.loanTransfersData.content;
this.activeTransferData = data.activeTransferData || null;
@@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core';
import { Component, Input, OnInit, inject } from '@angular/core';
import { ExternalAssetOwner } from 'app/loans/services/external-asset-owner';
import { NgClass } from '@angular/common';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
@@ -21,11 +21,11 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class ExternalAssetTransferComponent {
private externalAssetOwner = inject(ExternalAssetOwner);
/** Input Fields Data */
@Input() transferData: any;
constructor(private externalAssetOwner: ExternalAssetOwner) {}
itemStatus(status: string): string {
return this.externalAssetOwner.itemStatus(status);
}
@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, inject } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import {
MatTable,
@@ -35,6 +35,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class FloatingInterestRatesComponent implements OnInit {
private route = inject(ActivatedRoute);
/** Loan Details */
loanDetails: any;
/** Interest Rate Data */
@@ -49,7 +51,7 @@ export class FloatingInterestRatesComponent implements OnInit {
* Retrieves the loans data from `resolve`.
* @param {ActivatedRoute} route Activated Route.
*/
constructor(private route: ActivatedRoute) {
constructor() {
this.route.parent.data.subscribe((data: { loanDetailsData: any }) => {
this.loanDetails = data.loanDetailsData;
});
@@ -1,5 +1,5 @@
<div class="tab-container mat-typography">
<ng-container *ngIf="loanDetails.summary">
@if (loanDetails.summary) {
<h3>{{ 'labels.heading.Performance History' | translate }}</h3>
<div class="layout-row gap-32px performance-history-container">
<table>
@@ -21,224 +21,253 @@
</tbody>
</table>
</div>
</ng-container>
}
<div *ngIf="loanDetails.summary">
<h3>{{ 'labels.heading.Loan Summary' | translate }}</h3>
@if (loanDetails.summary) {
<div>
<h3>{{ 'labels.heading.Loan Summary' | translate }}</h3>
<table mat-table [dataSource]="dataSource">
<ng-container matColumnDef="Empty">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let ele">{{ ele.property }}</td>
</ng-container>
<ng-container matColumnDef="Original">
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Original' | translate }}</th>
<td mat-cell class="r-amount" *matCellDef="let ele">
{{ ele.original | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
</td>
</ng-container>
<ng-container matColumnDef="Paid">
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Paid' | translate }}</th>
<td mat-cell class="r-amount amount-minus" *matCellDef="let ele">
{{ ele.paid | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
</td>
</ng-container>
<ng-container matColumnDef="Adjustments">
<th mat-header-cell class="r-amount" *matHeaderCellDef>
{{ 'labels.inputs.Credit Adjustments' | translate }}
</th>
<td mat-cell class="r-amount amount-plus" *matCellDef="let ele">
{{ ele.adjustment | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
</td>
</ng-container>
<ng-container matColumnDef="Waived">
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Waived' | translate }}</th>
<td mat-cell class="r-amount amount-minus" *matCellDef="let ele">
{{ ele.waived | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
</td>
</ng-container>
<ng-container matColumnDef="Written Off">
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Written Off' | translate }}</th>
<td mat-cell class="r-amount amount-minus" *matCellDef="let ele">
{{ ele.writtenOff | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
</td>
</ng-container>
<ng-container matColumnDef="Outstanding">
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Outstanding' | translate }}</th>
<td mat-cell class="r-amount" *matCellDef="let ele">
{{ ele.outstanding | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
</td>
</ng-container>
<ng-container matColumnDef="Over Due">
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Over Due' | translate }}</th>
<td mat-cell class="r-amount" *matCellDef="let ele">
{{ ele.overdue | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="loanSummaryColumns"></tr>
<tr mat-row *matRowDef="let row; columns: loanSummaryColumns"></tr>
</table>
</div>
}
<table mat-table [dataSource]="dataSource">
<ng-container matColumnDef="Empty">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let ele">{{ ele.property }}</td>
</ng-container>
@if (loanDetails.summary) {
<div>
<h3>{{ 'labels.heading.Loan Details' | translate }}</h3>
<table mat-table [dataSource]="detailsDataSource">
<ng-container matColumnDef="Key">
<td mat-cell *matCellDef="let ele">{{ 'labels.inputs.' + ele.key | translate }}</td>
</ng-container>
<ng-container matColumnDef="Value">
<td mat-cell *matCellDef="let ele">
@if (ele.key === 'Disbursement Date') {
@if (loanDetails.timeline.actualDisbursementDate) {
<span>
{{ loanDetails.timeline.actualDisbursementDate | dateFormat }}
</span>
}
@if (!loanDetails.timeline.actualDisbursementDate) {
<span>
{{ 'labels.inputs.Not Available' | translate }}
</span>
}
}
@if (ele.key === 'Loan Purpose') {
@if (loanDetails.loanPurposeName) {
<span> {{ loanDetails.loanPurposeName }} </span>
}
@if (!loanDetails.loanPurposeName) {
<span> {{ 'labels.inputs.Not Available' | translate }} </span>
}
}
@if (ele.key === 'Loan Officer') {
@if (!loanDetails.loanOfficerName) {
<span> {{ 'labels.inputs.Unassigned' | translate }} </span>
}
@if (loanDetails.loanOfficerName) {
<span>
{{ loanDetails.loanOfficerName }} &nbsp;
@if (loanDetails.loanOfficerName) {
<span> </span>
}
</span>
}
}
@if (ele.key === 'Currency') {
<span> {{ loanDetails.currency.name }} {{ loanDetails.currency.code }} </span>
}
@if (ele.key === 'External Id') {
@if (loanDetails.externalId) {
<span>
<mifosx-external-identifier
externalId="{{ loanDetails.externalId }}"
completed="true"
></mifosx-external-identifier>
</span>
}
@if (!loanDetails.externalId) {
<span> {{ 'labels.inputs.Not Available' | translate }} </span>
}
}
@if (ele.key === 'Write-off Reason') {
@if (ele.value) {
<span>{{ ele.value }}</span>
}
@if (!ele.value) {
<span>{{ 'labels.inputs.Not Available' | translate }}</span>
}
}
@if (ele.key === 'Proposed Amount' || ele.key === 'Approved Amount' || ele.key === 'Disburse Amount') {
{{ ele.value }}
}
</td>
</ng-container>
<tr mat-row *matRowDef="let row; columns: loanDetailsColumns"></tr>
</table>
</div>
}
<ng-container matColumnDef="Original">
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Original' | translate }}</th>
<td mat-cell class="r-amount" *matCellDef="let ele">
{{ ele.original | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
</td>
</ng-container>
@if (!loanDetails.summary) {
<div>
<h3>{{ 'labels.heading.Loan Details' | translate }}</h3>
<table mat-table [dataSource]="detailsDataSource">
<ng-container matColumnDef="Key">
<td mat-cell *matCellDef="let ele">{{ 'labels.inputs.' + ele.key | translate }}</td>
</ng-container>
<ng-container matColumnDef="Value">
<td mat-cell *matCellDef="let ele">
@if (ele.key === 'Disbursement Date') {
@if (loanDetails.timeline.actualDisbursementDate) {
<span>
{{ loanDetails.timeline.actualDisbursementDate | dateFormat }}
</span>
}
@if (!loanDetails.timeline.actualDisbursementDate) {
<span>
{{ 'labels.inputs.Not Available' | translate }}
</span>
}
}
@if (ele.key === 'Loan Officer') {
@if (!loanDetails.loanOfficerName) {
<span> {{ 'labels.inputs.Unassigned' | translate }} </span>
}
@if (loanDetails.loanOfficerName) {
<span>
{{ loanDetails.loanOfficerName }} &nbsp;
@if (loanDetails.loanOfficerName) {
<span> </span>
}
</span>
}
}
@if (ele.key === 'Currency') {
<span> {{ loanDetails.currency.name }} {{ loanDetails.currency.code }} </span>
}
@if (ele.key === 'External Id') {
@if (loanDetails.externalId) {
<span>
<mifosx-external-identifier
externalId="{{ loanDetails.externalId }}"
completed="true"
></mifosx-external-identifier>
</span>
}
@if (!loanDetails.externalId) {
<span> {{ 'labels.inputs.Not Available' | translate }} </span>
}
}
</td>
</ng-container>
<tr mat-row *matRowDef="let row; columns: loanDetailsColumns"></tr>
</table>
</div>
}
<ng-container matColumnDef="Paid">
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Paid' | translate }}</th>
<td mat-cell class="r-amount amount-minus" *matCellDef="let ele">
{{ ele.paid | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
</td>
</ng-container>
<ng-container matColumnDef="Adjustments">
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Credit Adjustments' | translate }}</th>
<td mat-cell class="r-amount amount-plus" *matCellDef="let ele">
{{ ele.adjustment | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
</td>
</ng-container>
<ng-container matColumnDef="Waived">
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Waived' | translate }}</th>
<td mat-cell class="r-amount amount-minus" *matCellDef="let ele">
{{ ele.waived | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
</td>
</ng-container>
<ng-container matColumnDef="Written Off">
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Written Off' | translate }}</th>
<td mat-cell class="r-amount amount-minus" *matCellDef="let ele">
{{ ele.writtenOff | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
</td>
</ng-container>
<ng-container matColumnDef="Outstanding">
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Outstanding' | translate }}</th>
<td mat-cell class="r-amount" *matCellDef="let ele">
{{ ele.outstanding | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
</td>
</ng-container>
<ng-container matColumnDef="Over Due">
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Over Due' | translate }}</th>
<td mat-cell class="r-amount" *matCellDef="let ele">
{{ ele.overdue | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="loanSummaryColumns"></tr>
<tr mat-row *matRowDef="let row; columns: loanSummaryColumns"></tr>
</table>
</div>
<div *ngIf="loanDetails.summary">
<h3>{{ 'labels.heading.Loan Details' | translate }}</h3>
<table mat-table [dataSource]="detailsDataSource">
<ng-container matColumnDef="Key">
<td mat-cell *matCellDef="let ele">{{ 'labels.inputs.' + ele.key | translate }}</td>
</ng-container>
<ng-container matColumnDef="Value">
<td mat-cell *matCellDef="let ele">
<ng-container *ngIf="ele.key === 'Disbursement Date'">
<span *ngIf="loanDetails.timeline.actualDisbursementDate">
{{ loanDetails.timeline.actualDisbursementDate | dateFormat }}
</span>
<span *ngIf="!loanDetails.timeline.actualDisbursementDate">
{{ 'labels.inputs.Not Available' | translate }}
</span>
</ng-container>
<ng-container *ngIf="ele.key === 'Loan Purpose'">
<span *ngIf="loanDetails.loanPurposeName"> {{ loanDetails.loanPurposeName }} </span>
<span *ngIf="!loanDetails.loanPurposeName"> {{ 'labels.inputs.Not Available' | translate }} </span>
</ng-container>
<ng-container *ngIf="ele.key === 'Loan Officer'">
<span *ngIf="!loanDetails.loanOfficerName"> {{ 'labels.inputs.Unassigned' | translate }} </span>
<span *ngIf="loanDetails.loanOfficerName">
{{ loanDetails.loanOfficerName }} &nbsp;
<span *ngIf="loanDetails.loanOfficerName"> </span>
</span>
</ng-container>
<ng-container *ngIf="ele.key === 'Currency'">
<span> {{ loanDetails.currency.name }} {{ loanDetails.currency.code }} </span>
</ng-container>
<ng-container *ngIf="ele.key === 'External Id'">
<span *ngIf="loanDetails.externalId">
<mifosx-external-identifier
externalId="{{ loanDetails.externalId }}"
completed="true"
></mifosx-external-identifier>
</span>
<span *ngIf="!loanDetails.externalId"> {{ 'labels.inputs.Not Available' | translate }} </span>
</ng-container>
<ng-container *ngIf="ele.key === 'Write-off Reason'">
<span *ngIf="ele.value">{{ ele.value }}</span>
<span *ngIf="!ele.value">{{ 'labels.inputs.Not Available' | translate }}</span>
</ng-container>
<ng-container
*ngIf="ele.key === 'Proposed Amount' || ele.key === 'Approved Amount' || ele.key === 'Disburse Amount'"
>
{{ ele.value }}
</ng-container>
</td>
</ng-container>
<tr mat-row *matRowDef="let row; columns: loanDetailsColumns"></tr>
</table>
</div>
<div *ngIf="!loanDetails.summary">
<h3>{{ 'labels.heading.Loan Details' | translate }}</h3>
<table mat-table [dataSource]="detailsDataSource">
<ng-container matColumnDef="Key">
<td mat-cell *matCellDef="let ele">{{ 'labels.inputs.' + ele.key | translate }}</td>
</ng-container>
<ng-container matColumnDef="Value">
<td mat-cell *matCellDef="let ele">
<ng-container *ngIf="ele.key === 'Disbursement Date'">
<span *ngIf="loanDetails.timeline.actualDisbursementDate">
{{ loanDetails.timeline.actualDisbursementDate | dateFormat }}
</span>
<span *ngIf="!loanDetails.timeline.actualDisbursementDate">
{{ 'labels.inputs.Not Available' | translate }}
</span>
</ng-container>
<ng-container *ngIf="ele.key === 'Loan Officer'">
<span *ngIf="!loanDetails.loanOfficerName"> {{ 'labels.inputs.Unassigned' | translate }} </span>
<span *ngIf="loanDetails.loanOfficerName">
{{ loanDetails.loanOfficerName }} &nbsp;
<span *ngIf="loanDetails.loanOfficerName"> </span>
</span>
</ng-container>
<ng-container *ngIf="ele.key === 'Currency'">
<span> {{ loanDetails.currency.name }} {{ loanDetails.currency.code }} </span>
</ng-container>
<ng-container *ngIf="ele.key === 'External Id'">
<span *ngIf="loanDetails.externalId">
<mifosx-external-identifier
externalId="{{ loanDetails.externalId }}"
completed="true"
></mifosx-external-identifier>
</span>
<span *ngIf="!loanDetails.externalId"> {{ 'labels.inputs.Not Available' | translate }} </span>
</ng-container>
</td>
</ng-container>
<tr mat-row *matRowDef="let row; columns: loanDetailsColumns"></tr>
</table>
</div>
<div *ngIf="!loanDetails.summary">
<h3>{{ 'labels.heading.Loan Purpose' | translate }}</h3>
<div class="container">
<div class="layout-row-wrap responsive-column">
<div class="flex-contents">
<span class="flex-50">{{ 'labels.inputs.Loan Purpose' | translate }}:</span>
<span class="flex-50" *ngIf="loanDetails.loanPurposeName">
{{ loanDetails.loanPurposeName }}
</span>
<span class="flex-50" *ngIf="!loanDetails.loanPurposeName">
{{ 'labels.inputs.Not Provided' | translate }}
</span>
</div>
<div class="flex-contents">
<span class="flex-50">{{ 'labels.inputs.Proposed Amount' | translate }}:</span>
<span class="flex-50">{{
loanDetails.proposedPrincipal | currency: currencyCode : 'symbol-narrow' : '1.2-2'
}}</span>
</div>
<div class="flex-contents" *ngIf="showApprovedAmountBasedOnStatus()">
<span class="flex-50">{{ 'labels.inputs.Approved Amount' | translate }}:</span>
<span class="flex-50">{{
loanDetails.approvedPrincipal | currency: currencyCode : 'symbol-narrow' : '1.2-2'
}}</span>
</div>
<div class="flex-contents" *ngIf="showDisbursedAmountBasedOnStatus()">
<span class="flex-50">{{ 'labels.inputs.Disburse Amount' | translate }}:</span>
<span class="flex-50">{{ loanDetails.principal | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}</span>
</div>
<div class="flex-contents" *ngIf="loanDetails.balloonRepaymentAmount > 0">
<span class="flex-50">{{ 'labels.inputs.Balloon Repayment Amount' | translate }}:</span>
<span class="flex-50">{{
loanDetails.balloonRepaymentAmount | currency: currencyCode : 'symbol-narrow' : '1.2-2'
}}</span>
</div>
<div class="flex-contents">
<span class="flex-50">{{ 'labels.inputs.Arrears By' | translate }}:</span>
<span class="flex-50">{{ 'labels.inputs.Not Provided' | translate }}</span>
@if (!loanDetails.summary) {
<div>
<h3>{{ 'labels.heading.Loan Purpose' | translate }}</h3>
<div class="container">
<div class="layout-row-wrap responsive-column">
<div class="flex-contents">
<span class="flex-50">{{ 'labels.inputs.Loan Purpose' | translate }}:</span>
@if (loanDetails.loanPurposeName) {
<span class="flex-50">
{{ loanDetails.loanPurposeName }}
</span>
}
@if (!loanDetails.loanPurposeName) {
<span class="flex-50">
{{ 'labels.inputs.Not Provided' | translate }}
</span>
}
</div>
<div class="flex-contents">
<span class="flex-50">{{ 'labels.inputs.Proposed Amount' | translate }}:</span>
<span class="flex-50">{{
loanDetails.proposedPrincipal | currency: currencyCode : 'symbol-narrow' : '1.2-2'
}}</span>
</div>
@if (showApprovedAmountBasedOnStatus()) {
<div class="flex-contents">
<span class="flex-50">{{ 'labels.inputs.Approved Amount' | translate }}:</span>
<span class="flex-50">{{
loanDetails.approvedPrincipal | currency: currencyCode : 'symbol-narrow' : '1.2-2'
}}</span>
</div>
}
@if (showDisbursedAmountBasedOnStatus()) {
<div class="flex-contents">
<span class="flex-50">{{ 'labels.inputs.Disburse Amount' | translate }}:</span>
<span class="flex-50">{{
loanDetails.principal | currency: currencyCode : 'symbol-narrow' : '1.2-2'
}}</span>
</div>
}
@if (loanDetails.balloonRepaymentAmount > 0) {
<div class="flex-contents">
<span class="flex-50">{{ 'labels.inputs.Balloon Repayment Amount' | translate }}:</span>
<span class="flex-50">{{
loanDetails.balloonRepaymentAmount | currency: currencyCode : 'symbol-narrow' : '1.2-2'
}}</span>
</div>
}
<div class="flex-contents">
<span class="flex-50">{{ 'labels.inputs.Arrears By' | translate }}:</span>
<span class="flex-50">{{ 'labels.inputs.Not Provided' | translate }}</span>
</div>
</div>
</div>
</div>
</div>
}
</div>
@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, inject } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import {
MatTableDataSource,
@@ -13,7 +13,7 @@ import {
MatRowDef,
MatRow
} from '@angular/material/table';
import { NgIf, CurrencyPipe } from '@angular/common';
import { CurrencyPipe } from '@angular/common';
import { ExternalIdentifierComponent } from '../../../shared/external-identifier/external-identifier.component';
import { DateFormatPipe } from '../../../pipes/date-format.pipe';
import { FormatNumberPipe } from '../../../pipes/format-number.pipe';
@@ -42,6 +42,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class GeneralTabComponent implements OnInit {
private route = inject(ActivatedRoute);
/** Currency Code */
currencyCode: string;
loanDetails: any;
@@ -78,7 +80,7 @@ export class GeneralTabComponent implements OnInit {
dataSource: MatTableDataSource<any>;
detailsDataSource: MatTableDataSource<any>;
constructor(private route: ActivatedRoute) {
constructor() {
this.route.parent.data.subscribe((data: { loanDetailsData: any }) => {
this.loanDetails = data.loanDetailsData;
this.currencyCode = this.loanDetails.currency.code;
@@ -6,23 +6,27 @@
<mat-form-field>
<mat-label>{{ 'labels.inputs.Collateral Type' | translate }}</mat-label>
<mat-select required formControlName="collateralTypeId">
<mat-option *ngFor="let collateral of dataObject.allowedCollateralTypes" [value]="collateral.id">
{{ collateral.name }}</mat-option
>
@for (collateral of dataObject.allowedCollateralTypes; track collateral) {
<mat-option [value]="collateral.id"> {{ collateral.name }}</mat-option>
}
</mat-select>
<mat-error *ngIf="collateralForm.controls.collateralTypeId.hasError('required')">
{{ 'labels.inputs.Collateral Type' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (collateralForm.controls.collateralTypeId.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Collateral Type' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Value' | translate }}</mat-label>
<input matInput required formControlName="value" />
<mat-error *ngIf="collateralForm.controls.value.hasError('required')">
{{ 'labels.inputs.Value' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (collateralForm.controls.value.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Value' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field>
@@ -1,5 +1,5 @@
/** Angular Imports. */
import { Component, OnInit, Input } from '@angular/core';
import { Component, OnInit, Input, inject } from '@angular/core';
import { UntypedFormGroup, UntypedFormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
@@ -21,6 +21,11 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class AddCollateralComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private router = inject(Router);
private route = inject(ActivatedRoute);
private loanService = inject(LoansService);
@Input() dataObject: any;
/** Collateral form. */
@@ -28,20 +33,6 @@ export class AddCollateralComponent implements OnInit {
/** Loan Id. */
loanId: string;
/**
* Retrieve data from `Resolver`.
* @param {FormBuilder} formBuilder Form Builder.
* @param {Router} router Router.
* @param {ActivatedRoute} route Activated Route.
* @param {LoansService} LoansService loans service.
*/
constructor(
private formBuilder: UntypedFormBuilder,
private router: Router,
private route: ActivatedRoute,
private loanService: LoansService
) {}
ngOnInit() {
this.createAddCollateralForm();
}
@@ -1,8 +1,10 @@
<div class="container mat-elevation-z8">
<mat-card>
<div class="m-b-20 layout-column" *ngIf="maturityDate">
<span class="m-r-10">{{ 'Maturity Date' | translateKey: 'inputs' }} : {{ maturityDate | dateFormat }}</span>
</div>
@if (maturityDate) {
<div class="m-b-20 layout-column">
<span class="m-r-10">{{ 'Maturity Date' | translateKey: 'inputs' }} : {{ maturityDate | dateFormat }}</span>
</div>
}
<form [formGroup]="interestPauseLoanForm" (ngSubmit)="submit()">
<mat-card-content>
<div class="layout-column">
@@ -18,9 +20,11 @@
/>
<mat-datepicker-toggle matSuffix [for]="startDatePicker"></mat-datepicker-toggle>
<mat-datepicker #startDatePicker></mat-datepicker>
<mat-error *ngIf="interestPauseLoanForm.controls.startDate.hasError('required')">
{{ 'labels.inputs.Start Date' | translate }}<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (interestPauseLoanForm.controls.startDate.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Start Date' | translate }}<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field (click)="endDatePicker.open()">
@@ -35,9 +39,11 @@
/>
<mat-datepicker-toggle matSuffix [for]="endDatePicker"></mat-datepicker-toggle>
<mat-datepicker #endDatePicker></mat-datepicker>
<mat-error *ngIf="interestPauseLoanForm.controls.endDate.hasError('required')">
{{ 'labels.inputs.End Date' | translate }}<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (interestPauseLoanForm.controls.endDate.hasError('required')) {
<mat-error>
{{ 'labels.inputs.End Date' | translate }}<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
</div>
@@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core';
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';
@@ -17,6 +17,13 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class AddInterestPauseComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private loanService = inject(LoansService);
private route = inject(ActivatedRoute);
private router = inject(Router);
private dateUtils = inject(Dates);
private settingsService = inject(SettingsService);
@Input() dataObject: any;
/** Loan Id */
loanId: string;
@@ -40,14 +47,7 @@ export class AddInterestPauseComponent implements OnInit {
* @param {Router} router Router for navigation.
* @param {SettingsService} settingsService Settings Service
*/
constructor(
private formBuilder: UntypedFormBuilder,
private loanService: LoansService,
private route: ActivatedRoute,
private router: Router,
private dateUtils: Dates,
private settingsService: SettingsService
) {
constructor() {
this.loanId = this.route.snapshot.params['loanId'];
}
@@ -6,23 +6,29 @@
<mat-form-field>
<mat-label>{{ 'labels.inputs.Charge' | translate }}</mat-label>
<mat-select required formControlName="chargeId">
<mat-option *ngFor="let loanCharge of loanChargeOptions" [value]="loanCharge.id">
{{ loanCharge.name + ' (' + loanCharge?.currency.name + ')' }}
</mat-option>
@for (loanCharge of loanChargeOptions; track loanCharge) {
<mat-option [value]="loanCharge.id">
{{ loanCharge.name + ' (' + loanCharge?.currency.name + ')' }}
</mat-option>
}
</mat-select>
<mat-error *ngIf="loanChargeForm.controls.chargeId.hasError('required')">
{{ 'labels.inputs.Charge' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (loanChargeForm.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>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Amount' | translate }}</mat-label>
<input type="number" required matInput formControlName="amount" />
<mat-error *ngIf="loanChargeForm.controls.amount.hasError('required')">
{{ 'labels.inputs.Amount' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (loanChargeForm.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>
@@ -35,23 +41,27 @@
<input matInput formControlName="chargeTime" />
</mat-form-field>
<mat-form-field *ngIf="loanChargeForm.controls['dueDate']" (click)="dueDatePicker.open()">
<mat-label>{{ 'labels.inputs.Due 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>
<mat-error *ngIf="loanChargeForm.controls.dueDate.hasError('required')">
{{ 'labels.inputs.Due Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
</mat-form-field>
@if (loanChargeForm.controls['dueDate']) {
<mat-form-field (click)="dueDatePicker.open()">
<mat-label>{{ 'labels.inputs.Due 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 (loanChargeForm.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>
}
</div>
<mat-card-actions class="layout-row layout-xs-column layout-align-center gap-5px">
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, inject } from '@angular/core';
import {
UntypedFormGroup,
UntypedFormBuilder,
@@ -27,6 +27,13 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class AddLoanChargeComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private route = inject(ActivatedRoute);
private router = inject(Router);
private dateUtils = inject(Dates);
private loansService = inject(LoansService);
private settingsService = inject(SettingsService);
/** Minimum Due Date allowed. */
minDate = new Date(2000, 0, 1);
/** Maximum Due Date allowed. */
@@ -60,14 +67,7 @@ export class AddLoanChargeComponent implements OnInit {
* @param {Router} router Router for navigation.
* @param {SettingsService} settingsService Settings Service
*/
constructor(
private formBuilder: UntypedFormBuilder,
private route: ActivatedRoute,
private router: Router,
private dateUtils: Dates,
private loansService: LoansService,
private settingsService: SettingsService
) {
constructor() {
this.route.data.subscribe((data: { actionButtonData: any }) => {
this.loanChargeOptions = data.actionButtonData.chargeOptions;
});
@@ -8,10 +8,12 @@
<span matTextSuffix class="m-l-10">{{ loanDetailsData.currency.code }}</span>
<span class="flex-auto"></span>
<input type="number" matInput required class="right-input" formControlName="amount" />
<mat-error *ngIf="adjustLoanChargeForm.controls.amount.hasError('required')">
{{ 'labels.inputs.Amount' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (adjustLoanChargeForm.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>
@@ -22,9 +24,11 @@
<mat-form-field>
<mat-label>{{ 'labels.inputs.Payment Type' | translate }}</mat-label>
<mat-select formControlName="paymentTypeId">
<mat-option *ngFor="let paymentType of paymentTypes" [value]="paymentType.id">
{{ paymentType.name }}
</mat-option>
@for (paymentType of paymentTypes; track paymentType) {
<mat-option [value]="paymentType.id">
{{ paymentType.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
@@ -38,32 +42,28 @@
</span>
</div>
<ng-container *ngIf="showPaymentDetails">
@if (showPaymentDetails) {
<mat-form-field>
<mat-label> {{ 'labels.inputs.Account' | translate }} #</mat-label>
<input matInput formControlName="accountNumber" />
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Cheque' | translate }} #</mat-label>
<input matInput formControlName="checkNumber" />
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Routing Code' | translate }}</mat-label>
<input matInput formControlName="routingCode" />
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Reciept' | translate }} #</mat-label>
<input matInput formControlName="receiptNumber" />
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Bank' | translate }} #</mat-label>
<input matInput formControlName="bankNumber" />
</mat-form-field>
</ng-container>
}
<mat-form-field>
<mat-label>{{ 'labels.inputs.Note' | translate }}</mat-label>
@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, inject } from '@angular/core';
import {
UntypedFormBuilder,
UntypedFormControl,
@@ -25,6 +25,13 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class AdjustLoanChargeComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private loanService = inject(LoansService);
private route = inject(ActivatedRoute);
private router = inject(Router);
private settingsService = inject(SettingsService);
private organizationService = inject(OrganizationService);
/** Loan Id */
loanId: string;
chargeId: string;
@@ -50,14 +57,7 @@ export class AdjustLoanChargeComponent implements OnInit {
* @param {Router} router Router for navigation.
* @param {SettingsService} settingsService Settings Service
*/
constructor(
private formBuilder: UntypedFormBuilder,
private loanService: LoansService,
private route: ActivatedRoute,
private router: Router,
private settingsService: SettingsService,
private organizationService: OrganizationService
) {
constructor() {
this.loanId = this.route.snapshot.params['loanId'];
this.chargeId = this.route.snapshot.params['id'];
this.route.data.subscribe((data: { loansAccountCharge: any; loanDetailsData: any }) => {
@@ -14,10 +14,12 @@
/>
<mat-datepicker-toggle matSuffix [for]="approvedDatePicker"></mat-datepicker-toggle>
<mat-datepicker #approvedDatePicker></mat-datepicker>
<mat-error *ngIf="approveLoanForm.controls.approvedOnDate.hasError('required')">
{{ 'labels.inputs.Approved Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (approveLoanForm.controls.approvedOnDate.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Approved Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field (click)="disbursementDatePicker.open()">
@@ -49,10 +51,12 @@
<mat-form-field>
<mat-label>{{ 'labels.inputs.Transaction Amount' | translate }}</mat-label>
<input matInput type="number" required formControlName="approvedLoanAmount" />
<mat-error *ngIf="approveLoanForm.controls.approvedLoanAmount.hasError('required')">
{{ 'labels.inputs.Transaction Amount' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (approveLoanForm.controls.approvedLoanAmount.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Transaction Amount' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field>
@@ -1,5 +1,5 @@
/** Angular Imports. */
import { Component, OnInit } from '@angular/core';
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';
@@ -28,6 +28,13 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class ApproveLoanComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private route = inject(ActivatedRoute);
private dateUtils = inject(Dates);
private loanService = inject(LoansService);
private router = inject(Router);
private settingsService = inject(SettingsService);
/** Approve Loan form. */
approveLoanForm: UntypedFormGroup;
/** Loan data. */
@@ -49,14 +56,7 @@ export class ApproveLoanComponent implements OnInit {
* @param router Router.
* @param {SettingsService} settingsService Settings Service
*/
constructor(
private formBuilder: UntypedFormBuilder,
private route: ActivatedRoute,
private dateUtils: Dates,
private loanService: LoansService,
private router: Router,
private settingsService: SettingsService
) {
constructor() {
this.route.data.subscribe((data: { actionButtonData: any }) => {
this.loanData = data.actionButtonData;
this.currency = data.actionButtonData.currency;
@@ -15,29 +15,39 @@
/>
<mat-datepicker-toggle matSuffix [for]="settlementDatePicker"></mat-datepicker-toggle>
<mat-datepicker #settlementDatePicker></mat-datepicker>
<mat-error *ngIf="saleLoanForm.controls.settlementDate.hasError('required')">
{{ 'labels.inputs.Settlement Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (saleLoanForm.controls.settlementDate.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Settlement Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field *ngIf="!isBuyBack()">
<mat-label>{{ 'labels.inputs.Purchase Price Ratio' | translate }}</mat-label>
<input type="number" matInput required formControlName="purchasePriceRatio" />
<mat-error *ngIf="saleLoanForm.controls.purchasePriceRatio.hasError('required')">
{{ 'labels.inputs.Purchase Price Ratio' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
</mat-form-field>
@if (!isBuyBack()) {
<mat-form-field>
<mat-label>{{ 'labels.inputs.Purchase Price Ratio' | translate }}</mat-label>
<input type="number" matInput required formControlName="purchasePriceRatio" />
@if (saleLoanForm.controls.purchasePriceRatio.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Purchase Price Ratio' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
}
<mat-form-field *ngIf="!isBuyBack()">
<mat-label>{{ 'labels.inputs.Owner External Id' | translate }}</mat-label>
<input matInput formControlName="ownerExternalId" />
<mat-error *ngIf="saleLoanForm.controls.ownerExternalId.hasError('required')">
{{ 'labels.inputs.Owner External Id' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
</mat-form-field>
@if (!isBuyBack()) {
<mat-form-field>
<mat-label>{{ 'labels.inputs.Owner External Id' | translate }}</mat-label>
<input matInput formControlName="ownerExternalId" />
@if (saleLoanForm.controls.ownerExternalId.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Owner External Id' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
}
<mat-form-field>
<mat-label>{{ 'labels.inputs.Transfer External Id' | translate }}</mat-label>
@@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core';
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';
@@ -15,6 +15,13 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class AssetTransferLoanComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private externalAssetOwnerService = inject(ExternalAssetOwnerService);
private route = inject(ActivatedRoute);
private router = inject(Router);
private dateUtils = inject(Dates);
private settingsService = inject(SettingsService);
BUYBACK_COMMAND = 'buyback';
SALE_COMMAND = 'sale';
@@ -28,14 +35,7 @@ export class AssetTransferLoanComponent implements OnInit {
/** Sell Loan Form */
saleLoanForm: UntypedFormGroup;
constructor(
private formBuilder: UntypedFormBuilder,
private externalAssetOwnerService: ExternalAssetOwnerService,
private route: ActivatedRoute,
private router: Router,
private dateUtils: Dates,
private settingsService: SettingsService
) {
constructor() {
this.loanId = this.route.snapshot.params['loanId'];
const actionName = this.route.snapshot.params['action'];
this.command = actionName === 'Sell Loan' ? this.SALE_COMMAND : this.BUYBACK_COMMAND;
@@ -6,14 +6,18 @@
<mat-form-field>
<mat-label> {{ 'labels.inputs.To Loan Officer' | translate }}</mat-label>
<mat-select required formControlName="toLoanOfficerId">
<mat-option *ngFor="let loanOfficer of loanOfficers" [value]="loanOfficer.id">
{{ loanOfficer.displayName }}
</mat-option>
@for (loanOfficer of loanOfficers; track loanOfficer) {
<mat-option [value]="loanOfficer.id">
{{ loanOfficer.displayName }}
</mat-option>
}
</mat-select>
<mat-error *ngIf="assignOfficerForm.controls.toLoanOfficerId.hasError('required')">
{{ 'labels.inputs.Loan Officer' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (assignOfficerForm.controls.toLoanOfficerId.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Loan Officer' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field (click)="assignOnDatePicker.open()">
@@ -28,10 +32,12 @@
/>
<mat-datepicker-toggle matSuffix [for]="assignOnDatePicker"></mat-datepicker-toggle>
<mat-datepicker #assignOnDatePicker></mat-datepicker>
<mat-error *ngIf="assignOfficerForm.controls.assignmentDate.hasError('required')">
{{ 'labels.inputs.Assignment Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (assignOfficerForm.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>
@@ -1,4 +1,4 @@
import { Component, OnInit, Input } from '@angular/core';
import { Component, OnInit, Input, inject } from '@angular/core';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { LoansService } from 'app/loans/loans.service';
import { UntypedFormGroup, UntypedFormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
@@ -17,6 +17,13 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class AssignLoanOfficerComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private loanService = inject(LoansService);
private route = inject(ActivatedRoute);
private router = inject(Router);
private dateUtils = inject(Dates);
private settingsService = inject(SettingsService);
@Input() dataObject: any;
/** Loan Id */
loanId: string;
@@ -35,14 +42,7 @@ export class AssignLoanOfficerComponent implements OnInit {
* @param {Router} router Router for navigation.
* @param {SettingsService} settingsService Settings Service
*/
constructor(
private formBuilder: UntypedFormBuilder,
private loanService: LoansService,
private route: ActivatedRoute,
private router: Router,
private dateUtils: Dates,
private settingsService: SettingsService
) {
constructor() {
this.loanId = this.route.snapshot.params['loanId'];
}
@@ -15,23 +15,29 @@
/>
<mat-datepicker-toggle matSuffix [for]="transactionDatePicker"></mat-datepicker-toggle>
<mat-datepicker #transactionDatePicker></mat-datepicker>
<mat-error *ngIf="chargeoffLoanForm.controls.transactionDate.hasError('required')">
{{ 'labels.inputs.Transaction Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (chargeoffLoanForm.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-form-field>
<mat-label>{{ 'labels.inputs.Reason for Charge-Off' | translate }}</mat-label>
<mat-select formControlName="chargeOffReasonId">
<mat-option *ngFor="let chargeOffReason of chargeOffReasonOptions" [value]="chargeOffReason.id">
{{ chargeOffReason.name }}
</mat-option>
@for (chargeOffReason of chargeOffReasonOptions; track chargeOffReason) {
<mat-option [value]="chargeOffReason.id">
{{ chargeOffReason.name }}
</mat-option>
}
</mat-select>
<mat-error *ngIf="chargeoffLoanForm.controls.chargeOffReasonId.hasError('required')">
{{ 'labels.inputs.Reason for Charge-Off' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (chargeoffLoanForm.controls.chargeOffReasonId.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Reason for Charge-Off' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field>
@@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core';
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';
@@ -17,6 +17,13 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class ChargeOffComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private loanService = inject(LoansService);
private route = inject(ActivatedRoute);
private router = inject(Router);
private dateUtils = inject(Dates);
private settingsService = inject(SettingsService);
@Input() dataObject: any;
/** Loan Id */
@@ -41,14 +48,7 @@ export class ChargeOffComponent implements OnInit {
* @param {Router} router Router for navigation.
* @param {SettingsService} settingsService Settings Service
*/
constructor(
private formBuilder: UntypedFormBuilder,
private loanService: LoansService,
private route: ActivatedRoute,
private router: Router,
private dateUtils: Dates,
private settingsService: SettingsService
) {
constructor() {
this.loanId = this.route.snapshot.params['loanId'];
}
@@ -15,10 +15,12 @@
/>
<mat-datepicker-toggle matSuffix [for]="closedDatePicker"></mat-datepicker-toggle>
<mat-datepicker #closedDatePicker></mat-datepicker>
<mat-error *ngIf="closeLoanForm.controls.transactionDate.hasError('required')">
{{ 'labels.inputs.Closed Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (closeLoanForm.controls.transactionDate.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Closed Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field>
@@ -1,4 +1,4 @@
import { Component, OnInit, Input } from '@angular/core';
import { Component, OnInit, Input, inject } from '@angular/core';
import { UntypedFormGroup, UntypedFormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
import { LoansService } from 'app/loans/loans.service';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
@@ -19,6 +19,13 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class CloseAsRescheduledComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private loanService = inject(LoansService);
private route = inject(ActivatedRoute);
private router = inject(Router);
private dateUtils = inject(Dates);
private settingsService = inject(SettingsService);
@Input() dataObject: any;
/** Close form. */
@@ -37,14 +44,7 @@ export class CloseAsRescheduledComponent implements OnInit {
* @param {Router} router Router for navigation.
* @param {SettingsService} settingsService Settings Service
*/
constructor(
private formBuilder: UntypedFormBuilder,
private loanService: LoansService,
private route: ActivatedRoute,
private router: Router,
private dateUtils: Dates,
private settingsService: SettingsService
) {
constructor() {
this.loanId = this.route.snapshot.params['loanId'];
}
@@ -7,118 +7,119 @@
{{ 'labels.inputs.Existing Client' | translate }}
</mat-checkbox>
<ng-container *ngIf="!showClientDetailsForm">
@if (!showClientDetailsForm) {
<mat-form-field class="flex-30">
<mat-label>{{ 'labels.inputs.name' | translate }}</mat-label>
<input matInput formControlName="name" [matAutocomplete]="clientsAutocomplete" />
<mat-error *ngIf="newGuarantorForm.controls.name.hasError('required')">
{{ 'labels.inputs.name' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (newGuarantorForm.controls.name.hasError('required')) {
<mat-error>
{{ 'labels.inputs.name' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-autocomplete
autoActiveFirstOption
#clientsAutocomplete="matAutocomplete"
[displayWith]="displayClient"
(optionSelected)="clientSelected($event.option.value)"
>
<mat-option *ngFor="let client of clientsData" [value]="client">
{{ client.displayName }}
</mat-option>
@for (client of clientsData; track client) {
<mat-option [value]="client">
{{ client.displayName }}
</mat-option>
}
</mat-autocomplete>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Relationship' | translate }}</mat-label>
<mat-select formControlName="clientRelationshipTypeId">
<mat-option *ngFor="let relationType of relationTypes" [value]="relationType.id">
{{ relationType.name }}
</mat-option>
@for (relationType of relationTypes; track relationType) {
<mat-option [value]="relationType.id">
{{ relationType.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
<ng-container *ngIf="accountOptions?.length > 0">
@if (accountOptions?.length > 0) {
<mat-form-field>
<mat-label>{{ 'labels.inputs.Account' | translate }}</mat-label>
<mat-select formControlName="savingsId">
<mat-option *ngFor="let accountOption of accountOptions" [value]="accountOption.id">
{{ accountOption.productName }} - {{ accountOption.accountNo }}
</mat-option>
@for (accountOption of accountOptions; track accountOption) {
<mat-option [value]="accountOption.id">
{{ accountOption.productName }} - {{ accountOption.accountNo }}
</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Amount' | translate }}</mat-label>
<input type="number" matInput required formControlName="amount" />
</mat-form-field>
</ng-container>
</ng-container>
}
}
<ng-container *ngIf="showClientDetailsForm">
@if (showClientDetailsForm) {
<mat-form-field>
<mat-label>{{ 'labels.inputs.Relationship' | translate }}</mat-label>
<mat-select formControlName="clientRelationshipTypeId">
<mat-option *ngFor="let relationType of relationTypes" [value]="relationType.id">
{{ relationType.name }}
</mat-option>
@for (relationType of relationTypes; track relationType) {
<mat-option [value]="relationType.id">
{{ relationType.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.First Name' | translate }}</mat-label>
<input matInput required formControlName="firstname" />
<mat-error *ngIf="newGuarantorForm.controls.firstname.hasError('required')">
{{ 'labels.inputs.First Name' | translate }} {{ 'labels.commons.is' | translate }}
{{ 'labels.commons.is' | translate }} <strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (newGuarantorForm.controls.firstname.hasError('required')) {
<mat-error>
{{ 'labels.inputs.First Name' | translate }} {{ 'labels.commons.is' | translate }}
{{ 'labels.commons.is' | translate }} <strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Last Name' | translate }}</mat-label>
<input matInput required formControlName="lastname" />
<mat-error *ngIf="newGuarantorForm.controls.lastname.hasError('required')">
{{ 'labels.inputs.Last Name' | translate }} {{ 'labels.commons.is' | translate }}
{{ 'labels.commons.is' | translate }} <strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (newGuarantorForm.controls.lastname.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Last Name' | translate }} {{ 'labels.commons.is' | translate }}
{{ 'labels.commons.is' | translate }} <strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field (click)="dobDatePicker.open()">
<mat-label>{{ 'labels.inputs.Date Of Birth' | translate }}</mat-label>
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="dobDatePicker" formControlName="dob" />
<mat-datepicker-toggle matSuffix [for]="dobDatePicker"></mat-datepicker-toggle>
<mat-datepicker #dobDatePicker></mat-datepicker>
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Address Line' | translate }} 1</mat-label>
<input matInput formControlName="addressLine1" />
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Address Line' | translate }} 2</mat-label>
<input matInput formControlName="addressLine2" />
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.City' | translate }}</mat-label>
<input matInput formControlName="city" />
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Zip' | translate }}</mat-label>
<input matInput formControlName="zip" />
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Mobile' | translate }}</mat-label>
<input type="number" matInput formControlName="mobileNumber" />
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Residence Phone' | translate }} #</mat-label>
<input type="number" matInput formControlName="housePhoneNumber" />
</mat-form-field>
</ng-container>
}
</div>
<mat-card-actions class="layout-row align-center gap-5px responsive-column">
@@ -137,7 +138,7 @@
</mat-card-content>
</form>
<ng-container *ngIf="newGuarantorForm?.controls?.name?.value">
@if (newGuarantorForm?.controls?.name?.value) {
<div class="mat-table">
<div class="mat-header-row">
<div class="mat-header-cell">{{ 'labels.inputs.Client Details' | translate }}</div>
@@ -155,6 +156,6 @@
<div class="mat-cell">{{ newGuarantorForm.controls.name.value.officeName }}</div>
</div>
</div>
</ng-container>
}
</mat-card>
</div>
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Component, OnInit, Input, AfterViewInit } from '@angular/core';
import { Component, OnInit, Input, AfterViewInit, inject } from '@angular/core';
import {
UntypedFormGroup,
UntypedFormBuilder,
@@ -33,6 +33,14 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class CreateGuarantorComponent implements OnInit, AfterViewInit {
private formBuilder = inject(UntypedFormBuilder);
private loanService = inject(LoansService);
private route = inject(ActivatedRoute);
private router = inject(Router);
private dateUtils = inject(Dates);
private clientsService = inject(ClientsService);
private settingsService = inject(SettingsService);
@Input() dataObject: any;
/** New Guarantor Form */
newGuarantorForm: UntypedFormGroup;
@@ -58,15 +66,7 @@ export class CreateGuarantorComponent implements OnInit, AfterViewInit {
* @param {Router} router Router for navigation.
* @param {SettingsService} settingsService Settings Service
*/
constructor(
private formBuilder: UntypedFormBuilder,
private loanService: LoansService,
private route: ActivatedRoute,
private router: Router,
private dateUtils: Dates,
private clientsService: ClientsService,
private settingsService: SettingsService
) {
constructor() {
this.loanId = this.route.snapshot.params['loanId'];
}
@@ -15,10 +15,12 @@
/>
<mat-datepicker-toggle matSuffix [for]="disbursementDatePicker"></mat-datepicker-toggle>
<mat-datepicker #disbursementDatePicker></mat-datepicker>
<mat-error *ngIf="disbursementForm.controls.actualDisbursementDate.hasError('required')">
{{ 'labels.inputs.Disbursement Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (disbursementForm.controls.actualDisbursementDate.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Disbursement Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mifosx-input-amount
@@ -35,10 +37,12 @@
<input matInput [value]="dataObject.availableDisbursementAmountWithOverApplied | formatNumber" readonly />
</mat-form-field>
<mat-form-field *ngIf="dataObject.fixedEmiAmount">
<mat-label>{{ 'labels.inputs.Fixed EMI amount' | translate }}</mat-label>
<input matInput type="number" formControlName="fixedEmiAmount" />
</mat-form-field>
@if (dataObject.fixedEmiAmount) {
<mat-form-field>
<mat-label>{{ 'labels.inputs.Fixed EMI amount' | translate }}</mat-label>
<input matInput type="number" formControlName="fixedEmiAmount" />
</mat-form-field>
}
<mat-form-field>
<mat-label>{{ 'labels.inputs.Note' | translate }}</mat-label>
@@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core';
import { Component, Input, OnInit, inject } from '@angular/core';
import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { Dates } from 'app/core/utils/dates';
@@ -22,6 +22,13 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class DisburseToSavingsAccountComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private route = inject(ActivatedRoute);
private router = inject(Router);
private dateUtils = inject(Dates);
private loanService = inject(LoansService);
private settingsService = inject(SettingsService);
@Input() dataObject: any;
/** Minimum Date allowed. */
@@ -32,23 +39,6 @@ export class DisburseToSavingsAccountComponent implements OnInit {
disbursementForm: UntypedFormGroup;
currency: Currency;
/**
* Get data from `Resolver`.
* @param {FormBuilder} formBuilder FormBuilder.
* @param {ActivatedRoute} route ActivatedRoute.
* @param {Router} router Router.
* @param {LoansService} loanService Loan Service.
* @param {SettingsService} settingsService Settings Service
*/
constructor(
private formBuilder: UntypedFormBuilder,
private route: ActivatedRoute,
private router: Router,
private dateUtils: Dates,
private loanService: LoansService,
private settingsService: SettingsService
) {}
ngOnInit() {
this.maxDate = this.settingsService.businessDate;
this.setDisbursementToSavingsForm();
@@ -15,10 +15,12 @@
/>
<mat-datepicker-toggle matSuffix [for]="actualDisbursementDatePicker"></mat-datepicker-toggle>
<mat-datepicker #actualDisbursementDatePicker></mat-datepicker>
<mat-error *ngIf="disbursementLoanForm.controls.actualDisbursementDate.hasError('required')">
{{ 'labels.inputs.Disbursed On Date' | translate
}}<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (disbursementLoanForm.controls.actualDisbursementDate.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Disbursed On Date' | translate
}}<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mifosx-input-amount
@@ -43,9 +45,11 @@
<mat-form-field>
<mat-label>{{ 'labels.inputs.Payment Type' | translate }}</mat-label>
<mat-select formControlName="paymentTypeId">
<mat-option *ngFor="let paymentType of paymentTypes" [value]="paymentType.id">
{{ paymentType.name }}
</mat-option>
@for (paymentType of paymentTypes; track paymentType) {
<mat-option [value]="paymentType.id">
{{ paymentType.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
@@ -59,32 +63,28 @@
</span>
</div>
<ng-container *ngIf="showPaymentDetails">
@if (showPaymentDetails) {
<mat-form-field>
<mat-label>{{ 'labels.inputs.Account' | translate }} #</mat-label>
<input matInput formControlName="accountNumber" />
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Cheque' | translate }} #</mat-label>
<input matInput formControlName="checkNumber" />
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Routing Code' | translate }}</mat-label>
<input matInput formControlName="routingCode" />
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Reciept' | translate }} #</mat-label>
<input matInput formControlName="receiptNumber" />
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Bank' | translate }} #</mat-label>
<input matInput formControlName="bankNumber" />
</mat-form-field>
</ng-container>
}
<mat-form-field>
<mat-label>{{ 'labels.inputs.Note' | translate }}</mat-label>
@@ -1,5 +1,5 @@
/** Angular Imports */
import { Component, OnInit, Input } from '@angular/core';
import { Component, OnInit, Input, inject } from '@angular/core';
import { UntypedFormGroup, UntypedFormBuilder, Validators, UntypedFormControl } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
@@ -30,6 +30,13 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class DisburseComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private loanService = inject(LoansService);
private route = inject(ActivatedRoute);
private router = inject(Router);
private dateUtils = inject(Dates);
private settingsService = inject(SettingsService);
@Input() dataObject: any;
/** Loan Id */
loanId: string;
@@ -52,14 +59,7 @@ export class DisburseComponent implements OnInit {
* @param {Router} router Router for navigation.
* @param {SettingsService} settingsService Settings Service
*/
constructor(
private formBuilder: UntypedFormBuilder,
private loanService: LoansService,
private route: ActivatedRoute,
private router: Router,
private dateUtils: Dates,
private settingsService: SettingsService
) {
constructor() {
this.loanId = this.route.snapshot.params['loanId'];
}
@@ -2,13 +2,14 @@
<mat-card>
<mat-card-content>
<div class="m-b-10 layout-column">
<mifosx-repayment-schedule-tab
*ngIf="repaymentScheduleDetails"
class="flex-100"
[repaymentScheduleDetails]="repaymentScheduleDetails"
[forEditing]="true"
>
</mifosx-repayment-schedule-tab>
@if (repaymentScheduleDetails) {
<mifosx-repayment-schedule-tab
class="flex-100"
[repaymentScheduleDetails]="repaymentScheduleDetails"
[forEditing]="true"
>
</mifosx-repayment-schedule-tab>
}
</div>
<mat-card-actions class="layout-row align-center gap-5px responsive-column">
@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, inject } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
@@ -24,6 +24,14 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class EditRepaymentScheduleComponent implements OnInit {
private loansService = inject(LoansService);
private router = inject(Router);
private route = inject(ActivatedRoute);
private dialog = inject(MatDialog);
private dateUtils = inject(Dates);
private translateService = inject(TranslateService);
private settingsService = inject(SettingsService);
/** Loan ID. */
loanId: string;
/** Indicates If the Schedule has been changed */
@@ -43,15 +51,7 @@ export class EditRepaymentScheduleComponent implements OnInit {
* @param {Dates} dateUtils Dates Utils.
* @param {SettingsService} settingsService Settings Service
*/
constructor(
private loansService: LoansService,
private router: Router,
private route: ActivatedRoute,
private dialog: MatDialog,
private dateUtils: Dates,
private translateService: TranslateService,
private settingsService: SettingsService
) {
constructor() {
this.loanId = this.route.snapshot.params['loanId'];
this.getRepaymentSchedule();
}
@@ -107,7 +107,6 @@ export class EditRepaymentScheduleComponent implements OnInit {
type: 'number',
required: true
})
];
const data = {
title: 'Pattern Update',
@@ -15,10 +15,12 @@
/>
<mat-datepicker-toggle matSuffix [for]="transactionsDatePicker"></mat-datepicker-toggle>
<mat-datepicker #transactionsDatePicker></mat-datepicker>
<mat-error *ngIf="foreclosureForm.controls.transactionDate.hasError('required')">
{{ 'labels.inputs.Transaction Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (foreclosureForm.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-form-field>
@@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core';
import { Component, Input, OnInit, inject } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
import { LoansService } from 'app/loans/loans.service';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
@@ -19,6 +19,13 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class ForeclosureComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private loanService = inject(LoansService);
private route = inject(ActivatedRoute);
private router = inject(Router);
private dateUtils = inject(Dates);
private settingsService = inject(SettingsService);
@Input() dataObject: any;
loanId: any;
@@ -36,14 +43,7 @@ export class ForeclosureComponent implements OnInit {
* @param {Router} router Router for navigation.
* @param {SettingsService} settingsService Settings Service
*/
constructor(
private formBuilder: UntypedFormBuilder,
private loanService: LoansService,
private route: ActivatedRoute,
private router: Router,
private dateUtils: Dates,
private settingsService: SettingsService
) {
constructor() {
this.loanId = this.route.snapshot.params['loanId'];
}
@@ -1,69 +1,108 @@
<mifosx-loans-account-close [dataObject]="actionButtonData" *ngIf="actions['Close']"></mifosx-loans-account-close>
<mifosx-undo-approval *ngIf="actions['Undo Approval']"></mifosx-undo-approval>
<mifosx-assign-loan-officer
*ngIf="actions['Assign Loan Officer']"
[dataObject]="actionButtonData"
></mifosx-assign-loan-officer>
<mifosx-foreclosure [dataObject]="actionButtonData" *ngIf="actions['Foreclosure']"></mifosx-foreclosure>
<mifosx-prepay-loan
[dataObject]="actionButtonData"
*ngIf="actions['Prepay Loan'] || actions['Contract Termination']"
></mifosx-prepay-loan>
<mifosx-make-repayment [dataObject]="actionButtonData" *ngIf="actions['Make Repayment']"></mifosx-make-repayment>
<mifosx-make-repayment [dataObject]="actionButtonData" *ngIf="actions['Capitalized Income']"></mifosx-make-repayment>
<mifosx-make-repayment [dataObject]="actionButtonData" *ngIf="actions['Goodwill Credit']"></mifosx-make-repayment>
<mifosx-make-repayment [dataObject]="actionButtonData" *ngIf="actions['Buy Down Fee']"></mifosx-make-repayment>
<mifosx-make-repayment
[dataObject]="actionButtonData"
*ngIf="actions['Interest Payment Waiver']"
></mifosx-make-repayment>
<mifosx-make-repayment [dataObject]="actionButtonData" *ngIf="actions['Payout Refund']"></mifosx-make-repayment>
<mifosx-make-repayment
[dataObject]="actionButtonData"
*ngIf="actions['Merchant Issued Refund']"
></mifosx-make-repayment>
<mifosx-loan-credit-balance-refund
[dataObject]="actionButtonData"
*ngIf="actions['Credit Balance Refund']"
></mifosx-loan-credit-balance-refund>
<mifosx-waive-interest [dataObject]="actionButtonData" *ngIf="actions['Waive Interest']"></mifosx-waive-interest>
<mifosx-write-off-page [dataObject]="actionButtonData" *ngIf="actions['Write Off']"></mifosx-write-off-page>
<mifosx-close-as-rescheduled
[dataObject]="actionButtonData"
*ngIf="actions['Close (as Rescheduled)']"
></mifosx-close-as-rescheduled>
<mifosx-loan-reschedule [dataObject]="actionButtonData" *ngIf="actions['Reschedule']"></mifosx-loan-reschedule>
<mifosx-recovery-repayment
[dataObject]="actionButtonData"
*ngIf="actions['Recovery Payment']"
></mifosx-recovery-repayment>
<mifosx-view-guarantors [dataObject]="actionButtonData" *ngIf="actions['View Guarantors']"></mifosx-view-guarantors>
<mifosx-create-guarantor [dataObject]="actionButtonData" *ngIf="actions['Create Guarantor']"></mifosx-create-guarantor>
<mifosx-disburse-to-savings-account
[dataObject]="actionButtonData"
*ngIf="actions['Disburse to Savings']"
></mifosx-disburse-to-savings-account>
<mifosx-reject-loan *ngIf="actions['Reject']"></mifosx-reject-loan>
<mifosx-disburse [dataObject]="actionButtonData" *ngIf="actions['Disburse']"></mifosx-disburse>
<mifosx-withdrawn-by-client *ngIf="actions['Withdrawn by Client']"></mifosx-withdrawn-by-client>
<mifosx-add-collateral [dataObject]="actionButtonData" *ngIf="actions['Add Collateral']"></mifosx-add-collateral>
<mifosx-undo-disbursal
*ngIf="actions['Undo Disbursal'] || actions['Undo Last Disbursal']"
[actionName]="actionName"
></mifosx-undo-disbursal>
<mifosx-loan-screen-reports
[dataObject]="actionButtonData"
*ngIf="actions['Loan Screen Reports']"
></mifosx-loan-screen-reports>
<mifosx-approve-loan *ngIf="actions['Approve']"></mifosx-approve-loan>
<mifosx-add-loan-charge *ngIf="actions['Add Loan Charge']"></mifosx-add-loan-charge>
<mifosx-edit-repayment-schedule *ngIf="actions['Edit Repayment Schedule']"></mifosx-edit-repayment-schedule>
<mifosx-charge-off [dataObject]="actionButtonData" *ngIf="actions['Charge-Off']"></mifosx-charge-off>
<mifosx-asset-transfer-loan *ngIf="actions['Sell Loan'] || actions['Buy Back Loan']"></mifosx-asset-transfer-loan>
<mifosx-loan-reaging [dataObject]="actionButtonData" *ngIf="actions['Re-Age']"></mifosx-loan-reaging>
<mifosx-loan-reamortize [dataObject]="actionButtonData" *ngIf="actions['Re-Amortize']"></mifosx-loan-reamortize>
<mifosx-add-interest-pause
[dataObject]="navigationData"
*ngIf="actions['Add Interest Pause']"
></mifosx-add-interest-pause>
<mifosx-undo-write-off [dataObject]="actionButtonData" *ngIf="actions['Undo Write-off']"></mifosx-undo-write-off>
@if (actions['Close']) {
<mifosx-loans-account-close [dataObject]="actionButtonData"></mifosx-loans-account-close>
}
@if (actions['Undo Approval']) {
<mifosx-undo-approval></mifosx-undo-approval>
}
@if (actions['Assign Loan Officer']) {
<mifosx-assign-loan-officer [dataObject]="actionButtonData"></mifosx-assign-loan-officer>
}
@if (actions['Foreclosure']) {
<mifosx-foreclosure [dataObject]="actionButtonData"></mifosx-foreclosure>
}
@if (actions['Prepay Loan'] || actions['Contract Termination']) {
<mifosx-prepay-loan [dataObject]="actionButtonData"></mifosx-prepay-loan>
}
@if (actions['Make Repayment']) {
<mifosx-make-repayment [dataObject]="actionButtonData"></mifosx-make-repayment>
}
@if (actions['Capitalized Income']) {
<mifosx-make-repayment [dataObject]="actionButtonData"></mifosx-make-repayment>
}
@if (actions['Goodwill Credit']) {
<mifosx-make-repayment [dataObject]="actionButtonData"></mifosx-make-repayment>
}
@if (actions['Buy Down Fee']) {
<mifosx-make-repayment [dataObject]="actionButtonData"></mifosx-make-repayment>
}
@if (actions['Interest Payment Waiver']) {
<mifosx-make-repayment [dataObject]="actionButtonData"></mifosx-make-repayment>
}
@if (actions['Payout Refund']) {
<mifosx-make-repayment [dataObject]="actionButtonData"></mifosx-make-repayment>
}
@if (actions['Merchant Issued Refund']) {
<mifosx-make-repayment [dataObject]="actionButtonData"></mifosx-make-repayment>
}
@if (actions['Credit Balance Refund']) {
<mifosx-loan-credit-balance-refund [dataObject]="actionButtonData"></mifosx-loan-credit-balance-refund>
}
@if (actions['Waive Interest']) {
<mifosx-waive-interest [dataObject]="actionButtonData"></mifosx-waive-interest>
}
@if (actions['Write Off']) {
<mifosx-write-off-page [dataObject]="actionButtonData"></mifosx-write-off-page>
}
@if (actions['Close (as Rescheduled)']) {
<mifosx-close-as-rescheduled [dataObject]="actionButtonData"></mifosx-close-as-rescheduled>
}
@if (actions['Reschedule']) {
<mifosx-loan-reschedule [dataObject]="actionButtonData"></mifosx-loan-reschedule>
}
@if (actions['Recovery Payment']) {
<mifosx-recovery-repayment [dataObject]="actionButtonData"></mifosx-recovery-repayment>
}
@if (actions['View Guarantors']) {
<mifosx-view-guarantors [dataObject]="actionButtonData"></mifosx-view-guarantors>
}
@if (actions['Create Guarantor']) {
<mifosx-create-guarantor [dataObject]="actionButtonData"></mifosx-create-guarantor>
}
@if (actions['Disburse to Savings']) {
<mifosx-disburse-to-savings-account [dataObject]="actionButtonData"></mifosx-disburse-to-savings-account>
}
@if (actions['Reject']) {
<mifosx-reject-loan></mifosx-reject-loan>
}
@if (actions['Disburse']) {
<mifosx-disburse [dataObject]="actionButtonData"></mifosx-disburse>
}
@if (actions['Withdrawn by Client']) {
<mifosx-withdrawn-by-client></mifosx-withdrawn-by-client>
}
@if (actions['Add Collateral']) {
<mifosx-add-collateral [dataObject]="actionButtonData"></mifosx-add-collateral>
}
@if (actions['Undo Disbursal'] || actions['Undo Last Disbursal']) {
<mifosx-undo-disbursal [actionName]="actionName"></mifosx-undo-disbursal>
}
@if (actions['Loan Screen Reports']) {
<mifosx-loan-screen-reports [dataObject]="actionButtonData"></mifosx-loan-screen-reports>
}
@if (actions['Approve']) {
<mifosx-approve-loan></mifosx-approve-loan>
}
@if (actions['Add Loan Charge']) {
<mifosx-add-loan-charge></mifosx-add-loan-charge>
}
@if (actions['Edit Repayment Schedule']) {
<mifosx-edit-repayment-schedule></mifosx-edit-repayment-schedule>
}
@if (actions['Charge-Off']) {
<mifosx-charge-off [dataObject]="actionButtonData"></mifosx-charge-off>
}
@if (actions['Sell Loan'] || actions['Buy Back Loan']) {
<mifosx-asset-transfer-loan></mifosx-asset-transfer-loan>
}
@if (actions['Re-Age']) {
<mifosx-loan-reaging [dataObject]="actionButtonData"></mifosx-loan-reaging>
}
@if (actions['Re-Amortize']) {
<mifosx-loan-reamortize [dataObject]="actionButtonData"></mifosx-loan-reamortize>
}
@if (actions['Add Interest Pause']) {
<mifosx-add-interest-pause [dataObject]="navigationData"></mifosx-add-interest-pause>
}
@if (actions['Undo Write-off']) {
<mifosx-undo-write-off [dataObject]="actionButtonData"></mifosx-undo-write-off>
}
@@ -1,5 +1,5 @@
/** Angular Imports. */
import { Component } from '@angular/core';
import { Component, inject } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { LoansAccountCloseComponent } from './loans-account-close/loans-account-close.component';
import { UndoApprovalComponent } from './undo-approval/undo-approval.component';
@@ -75,6 +75,9 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class LoanAccountActionsComponent {
private route = inject(ActivatedRoute);
private router = inject(Router);
/** Loan Details Data */
navigationData: any;
@@ -167,11 +170,8 @@ export class LoanAccountActionsComponent {
/**
* @param route Activated Route.
*/
constructor(
private route: ActivatedRoute,
private router: Router
) {
const currentNavigation = this.router.getCurrentNavigation();
constructor() {
const currentNavigation = this.router.currentNavigation();
// Safely access data with optional chaining
this.navigationData = currentNavigation?.extras?.state?.data;
@@ -15,10 +15,12 @@
/>
<mat-datepicker-toggle matSuffix [for]="transactionDatePicker"></mat-datepicker-toggle>
<mat-datepicker #transactionDatePicker></mat-datepicker>
<mat-error *ngIf="creditBalanceLoanForm.controls.transactionDate.hasError('required')">
{{ 'labels.inputs.Transaction Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
@if (creditBalanceLoanForm.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
@@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core';
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';
@@ -20,6 +20,13 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
]
})
export class LoanCreditBalanceRefundComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private loanService = inject(LoansService);
private route = inject(ActivatedRoute);
private router = inject(Router);
private dateUtils = inject(Dates);
private settingsService = inject(SettingsService);
@Input() dataObject: any;
/** Loan Id */
loanId: string;
@@ -38,14 +45,7 @@ export class LoanCreditBalanceRefundComponent implements OnInit {
* @param {Router} router Router for navigation.
* @param {SettingsService} settingsService Settings Service
*/
constructor(
private formBuilder: UntypedFormBuilder,
private loanService: LoansService,
private route: ActivatedRoute,
private router: Router,
private dateUtils: Dates,
private settingsService: SettingsService
) {
constructor() {
this.loanId = this.route.snapshot.params['loanId'];
}
@@ -1,125 +1,123 @@
<div class="container mat-elevation-z8">
<mat-card>
<form [formGroup]="reagingLoanForm" (ngSubmit)="submit()" *ngIf="loanTransactionData !== null">
<mat-card-content>
<div class="layout-column">
<mat-form-field>
<mat-label>{{ 'labels.inputs.Number of Installments' | translate }}</mat-label>
<input type="number" matInput required formControlName="numberOfInstallments" />
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Frequency Number' | translate }}</mat-label>
<input type="number" matInput required formControlName="frequencyNumber" />
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Frequency Type' | translate }}</mat-label>
<mat-select formControlName="frequencyType">
<mat-option *ngFor="let frequencyType of periodFrequencyOptions" [value]="frequencyType">
{{ frequencyType }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field (click)="startDatePicker.open()">
<mat-label>{{ 'labels.inputs.Start Date' | translate }}</mat-label>
<input
matInput
[min]="minDate"
[max]="maxDate"
[matDatepicker]="startDatePicker"
required
formControlName="startDate"
/>
<mat-datepicker-toggle matSuffix [for]="startDatePicker"></mat-datepicker-toggle>
<mat-datepicker #startDatePicker></mat-datepicker>
<mat-error *ngIf="reagingLoanForm.controls.startDate.hasError('required')">
{{ 'labels.inputs.Start Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Interest Handling' | translate }}</mat-label>
<mat-select formControlName="reAgeInterestHandling">
<mat-option
*ngFor="let reAgeInterestHandlingOption of reAgeInterestHandlingOptions"
[value]="reAgeInterestHandlingOption.id"
@if (loanTransactionData !== null) {
<form [formGroup]="reagingLoanForm" (ngSubmit)="submit()">
<mat-card-content>
<div class="layout-column">
<mat-form-field>
<mat-label>{{ 'labels.inputs.Number of Installments' | translate }}</mat-label>
<input type="number" matInput required formControlName="numberOfInstallments" />
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Frequency Number' | translate }}</mat-label>
<input type="number" matInput required formControlName="frequencyNumber" />
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Frequency Type' | translate }}</mat-label>
<mat-select formControlName="frequencyType">
@for (frequencyType of periodFrequencyOptions; track frequencyType) {
<mat-option [value]="frequencyType">
{{ frequencyType }}
</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field (click)="startDatePicker.open()">
<mat-label>{{ 'labels.inputs.Start Date' | translate }}</mat-label>
<input
matInput
[min]="minDate"
[max]="maxDate"
[matDatepicker]="startDatePicker"
required
formControlName="startDate"
/>
<mat-datepicker-toggle matSuffix [for]="startDatePicker"></mat-datepicker-toggle>
<mat-datepicker #startDatePicker></mat-datepicker>
@if (reagingLoanForm.controls.startDate.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Start Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Interest Handling' | translate }}</mat-label>
<mat-select formControlName="reAgeInterestHandling">
@for (reAgeInterestHandlingOption of reAgeInterestHandlingOptions; track reAgeInterestHandlingOption) {
<mat-option [value]="reAgeInterestHandlingOption.id">
{{ reAgeInterestHandlingOption.value | translateKey: 'catalogs' }}
</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Reason' | translate }}</mat-label>
<mat-select formControlName="reasonCodeValueId">
@for (reAgeReasonOption of reAgeReasonOptions; track reAgeReasonOption) {
<mat-option [value]="reAgeReasonOption.id">
{{ reAgeReasonOption.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.External Id' | translate }}</mat-label>
<input matInput formControlName="externalId" />
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Note' | translate }}</mat-label>
<input matInput formControlName="note" />
</mat-form-field>
<div class="flex-fill">
<span
class="expandcollapsebutton m-l-10 m-t-5 m-b-5 flex-75"
(click)="addTransactionAmount = !addTransactionAmount"
>
{{ reAgeInterestHandlingOption.value | translateKey: 'catalogs' }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Reason' | translate }}</mat-label>
<mat-select formControlName="reasonCodeValueId">
<mat-option *ngFor="let reAgeReasonOption of reAgeReasonOptions" [value]="reAgeReasonOption.id">
{{ reAgeReasonOption.name }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.External Id' | translate }}</mat-label>
<input matInput formControlName="externalId" />
</mat-form-field>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Note' | translate }}</mat-label>
<input matInput formControlName="note" />
</mat-form-field>
<div class="flex-fill">
<span
class="expandcollapsebutton m-l-10 m-t-5 m-b-5 flex-75"
(click)="addTransactionAmount = !addTransactionAmount"
>
<mat-slide-toggle>
<div>
<span class="m-l-10">{{ 'labels.inputs.Transaction Amount' | translate }}</span>
</div>
</mat-slide-toggle>
</span>
<mat-slide-toggle>
<div>
<span class="m-l-10">{{ 'labels.inputs.Transaction Amount' | translate }}</span>
</div>
</mat-slide-toggle>
</span>
</div>
@if (addTransactionAmount) {
<mifosx-input-amount
[currency]="loanTransactionData.currency"
[isRequired]="false"
[inputFormControl]="reagingLoanForm.controls.transactionAmount"
[inputLabel]="'Transaction Amount'"
[minVal]="0.01"
[maxVal]="loanTransactionData.amount"
>
</mifosx-input-amount>
}
</div>
<mifosx-input-amount
*ngIf="addTransactionAmount"
[currency]="loanTransactionData.currency"
[isRequired]="false"
[inputFormControl]="reagingLoanForm.controls.transactionAmount"
[inputLabel]="'Transaction Amount'"
[minVal]="0.01"
[maxVal]="loanTransactionData.amount"
>
</mifosx-input-amount>
</div>
<mat-card-actions class="layout-row align-center gap-5px responsive-column">
<button type="button" mat-raised-button [routerLink]="['../../general']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
<button
mat-raised-button
color="primary"
[disabled]="!reagingLoanForm.valid"
*mifosxHasPermission="'REAGING_LOAN'"
>
{{ 'labels.buttons.Submit' | translate }}
</button>
<button
type="button"
mat-raised-button
color="accent"
[disabled]="!reagingLoanForm.valid"
*mifosxHasPermission="'REAGING_LOAN'"
(click)="preview()"
>
{{ 'labels.buttons.Preview' | translate }}
</button>
</mat-card-actions>
</mat-card-content>
</form>
<mat-card-actions class="layout-row align-center gap-5px responsive-column">
<button type="button" mat-raised-button [routerLink]="['../../general']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
<button
mat-raised-button
color="primary"
[disabled]="!reagingLoanForm.valid"
*mifosxHasPermission="'REAGING_LOAN'"
>
{{ 'labels.buttons.Submit' | translate }}
</button>
<button
type="button"
mat-raised-button
color="accent"
[disabled]="!reagingLoanForm.valid"
*mifosxHasPermission="'REAGING_LOAN'"
(click)="preview()"
>
{{ 'labels.buttons.Preview' | translate }}
</button>
</mat-card-actions>
</mat-card-content>
</form>
}
</mat-card>
</div>
@@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core';
import { Component, Input, OnInit, inject } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { MatDialog } from '@angular/material/dialog';
@@ -24,6 +24,14 @@ import { MatSlideToggle } from '@angular/material/slide-toggle';
]
})
export class LoanReagingComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private route = inject(ActivatedRoute);
private router = inject(Router);
private settingsService = inject(SettingsService);
private loanService = inject(LoansService);
private dateUtils = inject(Dates);
private dialog = inject(MatDialog);
@Input() dataObject: any;
/** Loan Id */
loanId: string;
@@ -42,15 +50,7 @@ export class LoanReagingComponent implements OnInit {
loanTransactionData: LoanTransactionTemplate | null = null;
addTransactionAmount = false;
constructor(
private formBuilder: UntypedFormBuilder,
private route: ActivatedRoute,
private router: Router,
private settingsService: SettingsService,
private loanService: LoansService,
private dateUtils: Dates,
private dialog: MatDialog
) {
constructor() {
this.loanId = this.route.snapshot.params['loanId'];
}
@@ -1,4 +1,4 @@
import { Component, Inject } from '@angular/core';
import { Component, inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef, MatDialogContent, MatDialogActions } from '@angular/material/dialog';
import { MatButton } from '@angular/material/button';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
@@ -23,13 +23,15 @@ export interface ReAgePreviewDialogData {
]
})
export class ReAgePreviewDialogComponent {
dialogRef = inject<MatDialogRef<ReAgePreviewDialogComponent>>(MatDialogRef);
data = inject<ReAgePreviewDialogData>(MAT_DIALOG_DATA);
repaymentSchedule: RepaymentSchedule;
currencyCode: string;
constructor(
public dialogRef: MatDialogRef<ReAgePreviewDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: ReAgePreviewDialogData
) {
constructor() {
const data = this.data;
this.repaymentSchedule = data.repaymentSchedule;
this.currencyCode = data.currencyCode;
}

Some files were not shown because too many files have changed in this diff Show More