feat: collateral module

This commit is contained in:
Ramveer
2022-07-22 13:37:21 +05:30
parent ed1395bb20
commit 22428de9b1
58 changed files with 1892 additions and 61 deletions
@@ -47,7 +47,7 @@
<mifosx-loans-account-charges-step [loansAccountProductTemplate]="loansAccountProductTemplate"
[loansAccountTemplate]="loansAccountTemplate" [collateralOptions]="collateralOptions"
[loansAccountFormValid]="loansAccountFormValid">
[loansAccountFormValid]="loansAccountFormValid" [loanPrincipal]="loanPrincipal">
</mifosx-loans-account-charges-step>
</mat-step>
@@ -5,6 +5,7 @@ import { ActivatedRoute, Router } from '@angular/router';
/** Custom Services */
import { LoansService } from '../loans.service';
import { SettingsService } from 'app/settings/settings.service';
import { ClientsService } from 'app/clients/clients.service';
/** Step Components */
import { LoansAccountDetailsStepComponent } from '../loans-account-stepper/loans-account-details-step/loans-account-details-step.component';
@@ -35,6 +36,8 @@ export class CreateLoansAccountComponent implements OnInit {
collateralOptions: any;
/** Multi Disburse Loan */
multiDisburseLoan: any;
/** Principal Amount */
principal: any;
/**
* Sets loans account create form.
@@ -43,12 +46,14 @@ export class CreateLoansAccountComponent implements OnInit {
* @param {Dates} dateUtils Date Utils
* @param {loansService} LoansService Loans Service
* @param {SettingsService} settingsService Settings Service
* @param {ClientsService} clientService Client Service
*/
constructor(private route: ActivatedRoute,
private router: Router,
private dateUtils: Dates,
private loansService: LoansService,
private settingsService: SettingsService
private settingsService: SettingsService,
private clientService: ClientsService
) {
this.route.data.subscribe((data: { loansAccountTemplate: any }) => {
this.loansAccountTemplate = data.loansAccountTemplate;
@@ -64,8 +69,9 @@ export class CreateLoansAccountComponent implements OnInit {
*/
setTemplate($event: any) {
this.loansAccountProductTemplate = $event;
this.loansService.getLoansCollateralTemplateResource(this.loansAccountProductTemplate.loanProductId).subscribe((response: any) => {
this.collateralOptions = response.loanCollateralOptions;
const clientId = this.loansAccountTemplate.clientId;
this.clientService.getCollateralTemplate(clientId).subscribe((response: any) => {
this.collateralOptions = response;
});
const entityId = (this.loansAccountTemplate.clientId) ? this.loansAccountTemplate.clientId : this.loansAccountTemplate.group.id;
const isGroup = (this.loansAccountTemplate.clientId) ? false : true;
@@ -89,10 +95,16 @@ export class CreateLoansAccountComponent implements OnInit {
get loansAccountFormValid() {
return (
this.loansAccountDetailsForm.valid &&
this.loansAccountTermsForm.valid
this.loansAccountTermsForm.valid &&
this.loansAccountChargesStep.loansAccountCharges.isValid
);
}
/** Gets principal Amount */
get loanPrincipal() {
return this.loansAccountTermsStep.loansAccountTermsForm.value.principal;
}
/** Retrieves Data of all forms except Currency to submit the data */
get loansAccount() {
return {
@@ -116,9 +128,8 @@ export class CreateLoansAccountComponent implements OnInit {
dueDate: charge.dueDate && this.dateUtils.formatDate(charge.dueDate, dateFormat),
})),
collateral: this.loansAccount.collateral.map((collateralEle: any) => ({
type: collateralEle.type,
value: collateralEle.value,
description: collateralEle.description
clientCollateralId: collateralEle.type.collateralId,
quantity: collateralEle.value,
})),
disbursementData: this.loansAccount.disbursementData.map((item: any) => ({
expectedDisbursementDate: this.dateUtils.formatDate(item.expectedDisbursementDate, dateFormat),
@@ -157,6 +168,7 @@ export class CreateLoansAccountComponent implements OnInit {
if (!(this.multiDisburseLoan)) {
delete loansAccountData.disbursementData;
}
delete loansAccountData.isValid;
this.loansService.createLoansAccount(loansAccountData).subscribe((response: any) => {
this.router.navigate(['../', response.resourceId], { relativeTo: this.route });
@@ -3,31 +3,36 @@
<div mat-dialog-content [formGroup]="addCollateralForm" fxLayout="column">
<mat-form-field>
<mat-label>Collateral Type</mat-label>
<mat-select formControlName="type" required>
<mat-option *ngFor="let collateralType of collateralTypeData" [value]="collateralType.id">
<mat-label>Collateral</mat-label>
<mat-select formControlName="collateral" required>
<mat-option *ngFor="let collateralType of collateralTypeData" [value]="collateralType" >
{{ collateralType.name }}
</mat-option>
</mat-select>
<mat-error>
Collateral Type is <strong>required</strong>
Collateral is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field>
<mat-label>Value</mat-label>
<input type="number" matInput formControlName="value" required>
<mat-error>
Value is <strong>required</strong>
<mat-label>Quantity</mat-label>
<input type="number" [max]="maxQuantity" [min]="0" matInput formControlName="quantity" required>
<mat-error *ngIf="addCollateralForm.controls.quantity.hasError('required')">
Quantity is <strong>required</strong>
</mat-error>
<mat-error *ngIf="addCollateralForm.controls.quantity.hasError('max')">
Quantity can not be more than <strong>{{ maxQuantity }}</strong>
</mat-error>
</mat-form-field>
<mat-form-field>
<mat-label>Description</mat-label>
<input type="text" matInput formControlName="description" required>
<mat-error>
Description is <strong>required</strong>
</mat-error>
<mat-label>Total Value</mat-label>
<input type="text" matInput formControlName="totalValue" [disabled]="true">
</mat-form-field>
<mat-form-field>
<mat-label>Total Collateral Value</mat-label>
<input type="text" matInput formControlName="totalCollateralValue" [disabled]="true">
</mat-form-field>
</div>
@@ -16,7 +16,12 @@ export class LoansAccountAddCollateralDialogComponent implements OnInit {
};
addCollateralForm: FormGroup;
/** All Collateral Options */
collateralTypeData: any;
/** Selected Collateral */
collateralData: any;
/** Maximum ALlowed Quantity of selected collateral */
maxQuantity: any = 0;
constructor(public dialogRef: MatDialogRef<LoansAccountAddCollateralDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any,
@@ -26,14 +31,33 @@ export class LoansAccountAddCollateralDialogComponent implements OnInit {
ngOnInit() {
this.dialogRef.updateSize('400px');
this.collateralTypeData = this.data.collateralTypeOptions;
this.collateralTypeData = this.data.collateralOptions;
this.buildDependencies();
}
createAddCollateralForm() {
this.addCollateralForm = this.formBuilder.group({
'type': ['', Validators.required],
'value': ['', Validators.required],
'description': ['', Validators.required]
'collateral': ['', Validators.required],
'quantity': ['', Validators.required],
'totalValue': [{value: '', disabled: true}],
'totalCollateralValue': [{value: '', disabled: true}],
});
}
/**
* Subscribe to Form controls value changes
*/
buildDependencies() {
this.addCollateralForm.controls.collateral.valueChanges.subscribe((collateral: any) => {
this.collateralData = collateral;
this.maxQuantity = collateral.quantity;
});
this.addCollateralForm.controls.quantity.valueChanges.subscribe((quantity: any) => {
this.addCollateralForm.patchValue({
'totalValue': this.collateralData.basePrice * quantity,
'totalCollateralValue': this.collateralData.basePrice * this.collateralData.pctToBase * quantity / 100
});
});
}
@@ -135,18 +135,23 @@
<table mat-table class="mat-elevation-z1" [dataSource]="collateralDataSource">
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef> Type </th>
<th mat-header-cell *matHeaderCellDef> Name </th>
<td mat-cell *matCellDef="let ele"> {{ ele.type.name }} </td>
</ng-container>
<ng-container matColumnDef="value">
<th mat-header-cell *matHeaderCellDef> Value </th>
<th mat-header-cell *matHeaderCellDef> Quantity </th>
<td mat-cell *matCellDef="let ele"> {{ ele.value }} </td>
</ng-container>
<ng-container matColumnDef="description">
<th mat-header-cell *matHeaderCellDef> Description </th>
<td mat-cell *matCellDef="let ele"> {{ ele.description }} </td>
<ng-container matColumnDef="totalValue">
<th mat-header-cell *matHeaderCellDef> Total Value </th>
<td mat-cell *matCellDef="let ele"> {{ ele.type.basePrice*ele.value }} </td>
</ng-container>
<ng-container matColumnDef="totalCollateralValue">
<th mat-header-cell *matHeaderCellDef> Total Collateral Value </th>
<td mat-cell *matCellDef="let ele"> {{ ele.type.pctToBase*ele.type.basePrice*ele.value/100 }} </td>
</ng-container>
<ng-container matColumnDef="action">
@@ -169,7 +174,7 @@
<fa-icon icon="arrow-left"></fa-icon>&nbsp;&nbsp;
Previous
</button>
<button mat-raised-button matStepperNext [disabled]="!loansAccountFormValid">
<button mat-raised-button matStepperNext [disabled]="!isCollateralSufficient">
Next&nbsp;&nbsp;
<fa-icon icon="arrow-right"></fa-icon>
</button>
@@ -31,8 +31,10 @@ export class LoansAccountChargesStepComponent implements OnInit, OnChanges {
@Input() loansAccountTemplate: any;
// @Input() loansAccountFormValid: LoansAccountFormValid
@Input() loansAccountFormValid: boolean;
// @Input collateralOptionsL Collateral Options
// @Input collateralOptions: Collateral Options
@Input() collateralOptions: any;
// @Input loanPrincipal: Loan Principle
@Input() loanPrincipal: any;
/** Charges Data */
chargeData: any;
@@ -47,9 +49,13 @@ export class LoansAccountChargesStepComponent implements OnInit, OnChanges {
/** Columns to be displayed in overdue charges table. */
overdueChargesDisplayedColumns: string[] = ['name', 'type', 'amount', 'collectedon'];
/** Columns to be displayed in collateral table. */
loanCollateralDisplayedColumns: string[] = ['type', 'value', 'description', 'action'];
loanCollateralDisplayedColumns: string[] = ['type', 'value', 'totalValue', 'totalCollateralValue', 'action'];
/** Component is pristine if there has been no changes by user interaction */
pristine = true;
/** Check if value of collateral added is more than principal amount */
isCollateralSufficient = false;
/** Total value of all collateral added to a loan */
totalCollateralValue: any = 0;
/**
* Loans Account Charges Form Step
@@ -207,33 +213,53 @@ export class LoansAccountChargesStepComponent implements OnInit, OnChanges {
});
}
// TODO: Needs to be completed
/**
* Add a Collateral to the loan
*/
addCollateral() {
const addCollateralDialogRef = this.dialog.open(LoansAccountAddCollateralDialogComponent, {
data: { collateralOptions: this.collateralOptions }
});
console.log(this.collateralOptions);
addCollateralDialogRef.afterClosed().subscribe((response: any) => {
if (response.addCollateralForm) {
console.log(this.loanPrincipal);
if (response.data) {
const collateralData = {
type: response.addCollateralForm.value.type,
value: response.addCollateralForm.value.value,
description: response.addCollateralForm.value.description
type: response.data.value.collateral,
value: response.data.value.quantity,
};
this.collateralDataSource = this.collateralDataSource.concat(collateralData);
this.totalCollateralValue += collateralData.type.pctToBase * collateralData.type.basePrice * collateralData.value / 100;
this.collateralDataSource = this.collateralDataSource.concat(collateralData);
this.collateralOptions = this.collateralOptions.filter( (user: any) => user.collateralId !== response.data.value.collateral.collateralId);
if (this.loanPrincipal < this.totalCollateralValue) {
this.isCollateralSufficient = true;
} else {
this.isCollateralSufficient = false;
}
}
});
}
/**
* Delete a added collateral from loan
* @param id ID od the collateral to be deleted
*/
deleteCollateral(id: any) {
const deleteCollateralDialogRef = this.dialog.open(DeleteDialogComponent, {
data: { deleteContext: `collateral` }
});
deleteCollateralDialogRef.afterClosed().subscribe((response: any) => {
if (response.delete) {
this.collateralDataSource.splice(this.collateralDataSource.indexOf(id), 1);
const removed: any = this.collateralDataSource.splice(id, 1);
this.collateralOptions = this.collateralOptions.concat(removed[0].type);
this.totalCollateralValue -= removed[0].type.pctToBase * removed[0].type.basePrice * removed[0].value / 100;
this.collateralDataSource = this.collateralDataSource.concat([]);
this.pristine = false;
if (this.loanPrincipal < this.totalCollateralValue) {
this.isCollateralSufficient = true;
} else {
this.isCollateralSufficient = false;
}
}
});
}
@@ -244,7 +270,8 @@ export class LoansAccountChargesStepComponent implements OnInit, OnChanges {
get loansAccountCharges() {
return {
charges: this.chargesDataSource,
collateral: this.collateralDataSource
collateral: this.collateralDataSource,
isValid: this.isCollateralSufficient
};
}
@@ -2,19 +2,24 @@
<table mat-table [dataSource]="loanDetails.collateral">
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef> Type </th>
<td mat-cell *matCellDef="let ele"> {{ ele.type.name }} </td>
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef> ID </th>
<td mat-cell *matCellDef="let ele"> {{ ele.clientCollateralId }} </td>
</ng-container>
<ng-container matColumnDef="value">
<th mat-header-cell *matHeaderCellDef> Value </th>
<td mat-cell *matCellDef="let ele"> {{ ele.value }} </td>
<ng-container matColumnDef="quantity">
<th mat-header-cell *matHeaderCellDef> Quantity </th>
<td mat-cell *matCellDef="let ele"> {{ ele.quantity }} </td>
</ng-container>
<ng-container matColumnDef="description">
<th mat-header-cell *matHeaderCellDef> Description </th>
<td mat-cell *matCellDef="let ele"> {{ ele.description }} </td>
<ng-container matColumnDef="total">
<th mat-header-cell *matHeaderCellDef> Total Value </th>
<td mat-cell *matCellDef="let ele"> {{ ele.total }} </td>
</ng-container>
<ng-container matColumnDef="totalCollateral">
<th mat-header-cell *matHeaderCellDef> Total Collateral Value </th>
<td mat-cell *matCellDef="let ele"> {{ ele.totalCollateral }} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
@@ -11,7 +11,7 @@ export class LoanCollateralTabComponent implements OnInit {
/** Loan Details */
loanDetails: any;
/** Columns to be displayed in collateral table. */
displayedColumns: string[] = ['type', 'value', 'description'];
displayedColumns: string[] = ['id', 'quantity', 'total', 'totalCollateral'];
/**
* Retrieves the loans data from `resolve`.