Merge pull request #1531 from josehernandezfintecheandomx/enhancement/manage_loan_tranches
Loan tranches Management
This commit is contained in:
@@ -7,29 +7,29 @@
|
||||
|
||||
<h3>Loan Tranche Details</h3>
|
||||
|
||||
<div fxLayout="row" fxLayoutAlign="flex-end">
|
||||
<button mat-raised-button color="primary" *ngIf="showAddDeleteTrancheButtons('adddisbursedetails')">
|
||||
<fa-icon icon="plus"></fa-icon> Add
|
||||
</button>
|
||||
<span class="delete-button">
|
||||
<button mat-raised-button color="warn" (click)="delete()" *ngIf="showAddDeleteTrancheButtons('deletedisbursedetails')">
|
||||
<fa-icon icon="trash"></fa-icon> Delete
|
||||
</button>
|
||||
</span>
|
||||
<div fxLayout="row" class="margin-t" fxLayout.xs="column" fxLayoutAlign="flex-end" fxLayoutGap="2%">
|
||||
<button mat-raised-button color="primary" *ngIf="showAddTrancheButtons()"
|
||||
(click)="addDisbursementDataEntry()">
|
||||
<fa-icon icon="plus"></fa-icon> Add
|
||||
</button>
|
||||
<button mat-raised-button color="primary" *ngIf="!pristine"
|
||||
(click)="editDisbursementData()">
|
||||
Apply Changes
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<table mat-table [dataSource]="loanDetails.disbursementDetails" *ngIf="loanDetails.disbursementDetails.length>0">
|
||||
<table mat-table [dataSource]="disbursementDataSource" *ngIf="disbursementDataSource.length > 0">
|
||||
|
||||
<ng-container matColumnDef="expected disbursement on">
|
||||
<th mat-header-cell *matHeaderCellDef> Expected Disbursement On </th>
|
||||
<td mat-cell *matCellDef="let ele"> {{ ele.expectedDisbursementDate | dateFormat}} </td>
|
||||
<td mat-cell *matCellDef="let ele"> {{ ele.expectedDisbursementDate | dateFormat}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="disbursed on">
|
||||
<th mat-header-cell *matHeaderCellDef> Disbursed On </th>
|
||||
<td mat-cell *matCellDef="let ele">
|
||||
<span *ngIf="ele.actualDisbursementDate">
|
||||
{{ ele.actualDisbursementDate | dateFormat }}
|
||||
{{ ele.actualDisbursementDate | dateFormat }}
|
||||
</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
@@ -41,12 +41,19 @@
|
||||
|
||||
<ng-container matColumnDef="action">
|
||||
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
||||
<td mat-cell *matCellDef="let ele">
|
||||
<td mat-cell *matCellDef="let ele; let rowIndex = index">
|
||||
<span *ngIf="ele.actualDisbursementDate">
|
||||
<i class="fa fa-check "></i>
|
||||
</span>
|
||||
<button mat-raised-button color="primary" *ngIf="showEdit(ele)">
|
||||
<i class="fa fa-pencil"></i>
|
||||
<button type="button" mat-icon-button color="primary"
|
||||
(click)="editDisbursementDataEntry(rowIndex)" matTooltip="Edit"
|
||||
matTooltipPosition="left" *ngIf="!ele.actualDisbursementDate && showActionsTrancheButtons()">
|
||||
<fa-icon icon="edit"></fa-icon>
|
||||
</button>
|
||||
<button type="button" mat-icon-button color="warn"
|
||||
(click)="removeDisbursementDataEntry(rowIndex)" matTooltip="Delete"
|
||||
matTooltipPosition="left" *ngIf="!ele.actualDisbursementDate && showActionsTrancheButtons()">
|
||||
<fa-icon icon="trash"></fa-icon>
|
||||
</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
@@ -63,7 +70,7 @@
|
||||
|
||||
<ng-container matColumnDef="emi amount variation from">
|
||||
<th mat-header-cell *matHeaderCellDef> Applicable From Date </th>
|
||||
<td mat-cell *matCellDef="let ele"> {{ ele.termVariationApplicableFrom | dateFormat}} </td>
|
||||
<td mat-cell *matCellDef="let ele"> {{ ele.termVariationApplicableFrom | dateFormat}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="fixed emi amount">
|
||||
@@ -75,6 +82,4 @@
|
||||
<tr mat-row *matRowDef="let row; columns: emivariationColumns;"></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Dates } from 'app/core/utils/dates';
|
||||
import { LoansService } from 'app/loans/loans.service';
|
||||
import { SettingsService } from 'app/settings/settings.service';
|
||||
import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
|
||||
import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component';
|
||||
import { DatepickerBase } from 'app/shared/form-dialog/formfield/model/datepicker-base';
|
||||
import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base';
|
||||
import { InputBase } from 'app/shared/form-dialog/formfield/model/input-base';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-loan-tranche-details',
|
||||
@@ -10,63 +19,196 @@ export class LoanTrancheDetailsComponent implements OnInit {
|
||||
loanDetails: any;
|
||||
return: any;
|
||||
status: any;
|
||||
totalDisbursedAmount: any;
|
||||
count: number;
|
||||
expectedDisbursementColumns: string[] = ['expected disbursement on', 'disbursed on', 'principal', 'action'];
|
||||
emivariationColumns: string[] = ['emi amount variation from', 'fixed emi amount'];
|
||||
|
||||
loanId: number;
|
||||
currentPrincipalAmount: number;
|
||||
minDate = new Date(2000, 0, 1);
|
||||
maxDate = new Date(2100, 0, 1);
|
||||
disbursementDataSource: {}[] = [];
|
||||
totalMultiDisbursed: number = null;
|
||||
disallowExpectedDisbursements = false;
|
||||
pristine = true;
|
||||
|
||||
/**
|
||||
* Retrieves the loans data from `resolve`.
|
||||
* @param {ActivatedRoute} route Activated Route.
|
||||
*/
|
||||
constructor(private route: ActivatedRoute) {
|
||||
constructor(private route: ActivatedRoute,
|
||||
public dialog: MatDialog,
|
||||
private loanServices: LoansService,
|
||||
private settingsService: SettingsService,
|
||||
private dateUtils: Dates) {
|
||||
this.route.parent.data.subscribe((data: { loanDetailsData: any }) => {
|
||||
this.loanId = data.loanDetailsData.id;
|
||||
this.loanDetails = data.loanDetailsData;
|
||||
this.disallowExpectedDisbursements = this.loanDetails.disallowExpectedDisbursements || false;
|
||||
this.disbursementDataSource = data.loanDetailsData.disbursementDetails;
|
||||
this.currentPrincipalAmount = this.loanDetails.approvedPrincipal;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.maxDate = this.settingsService.maxFutureDate;
|
||||
this.status = this.loanDetails.status.value;
|
||||
}
|
||||
|
||||
showAddDeleteTrancheButtons(action: string) {
|
||||
showAddTrancheButtons() {
|
||||
this.return = true;
|
||||
if (
|
||||
this.status === 'Closed (obligations met)' ||
|
||||
this.status === 'Overpaid' ||
|
||||
this.status === 'Closed (rescheduled)' ||
|
||||
this.status === 'Closed (written off)' ||
|
||||
this.status === 'Submitted and pending approval'
|
||||
this.status === 'Submitted and pending approval' ||
|
||||
this.disallowExpectedDisbursements
|
||||
) {
|
||||
this.return = false;
|
||||
}
|
||||
this.totalDisbursedAmount = 0;
|
||||
this.count = 0;
|
||||
this.loanDetails.disbursementDetails.forEach((element: any) => {
|
||||
if (element.actualDisbursementDate) {
|
||||
this.totalDisbursedAmount += element.principal;
|
||||
} else {
|
||||
this.count += 1;
|
||||
}
|
||||
});
|
||||
|
||||
if (this.totalDisbursedAmount === this.loanDetails.approvedPrincipal || this.return === false) {
|
||||
return false;
|
||||
}
|
||||
if (this.count === 0 && action === 'deletedisbursedetails') {
|
||||
this.calculateTotalDisbursedAmount();
|
||||
|
||||
if (this.totalMultiDisbursed === this.currentPrincipalAmount || this.return === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
showEdit(disbursementDetail: any) {
|
||||
showActionsTrancheButtons() {
|
||||
if (
|
||||
(!disbursementDetail.actualDisbursementDate || disbursementDetail.actualDisbursementDate === null) &&
|
||||
this.status === 'Approved'
|
||||
this.status === 'Closed (obligations met)' ||
|
||||
this.status === 'Overpaid' ||
|
||||
this.status === 'Closed (rescheduled)' ||
|
||||
this.status === 'Closed (written off)' ||
|
||||
this.status === 'Submitted and pending approval' ||
|
||||
this.disallowExpectedDisbursements
|
||||
) {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the Principal Disbursed.
|
||||
*/
|
||||
calculateTotalDisbursedAmount() {
|
||||
this.totalMultiDisbursed = 0;
|
||||
this.count = 0;
|
||||
this.disbursementDataSource.forEach((item: any) => {
|
||||
this.totalMultiDisbursed += (item.principal * 1);
|
||||
this.count += 1;
|
||||
});
|
||||
}
|
||||
|
||||
buildForm(expectedDisbursementDate: Date, principal: number): FormfieldBase[] {
|
||||
const formBase: FormfieldBase[] = [
|
||||
new DatepickerBase({
|
||||
controlName: 'expectedDisbursementDate',
|
||||
label: 'Expected Disbursement Date',
|
||||
value: expectedDisbursementDate || '',
|
||||
type: 'datetime-local',
|
||||
minDate: this.minDate,
|
||||
maxDate: this.maxDate,
|
||||
required: true,
|
||||
order: 1
|
||||
}),
|
||||
new InputBase({
|
||||
controlName: 'principal',
|
||||
label: 'Principal',
|
||||
value: principal,
|
||||
type: 'number',
|
||||
required: true,
|
||||
order: 2
|
||||
})
|
||||
];
|
||||
return formBase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the Disbursement Data entry form to given Disbursement Data entry.
|
||||
*/
|
||||
addDisbursementDataEntry() {
|
||||
this.calculateTotalDisbursedAmount();
|
||||
|
||||
const data = {
|
||||
title: 'Add Disbursement Details',
|
||||
layout: { addButtonText: 'Add' },
|
||||
formfields: this.buildForm(new Date(), (this.currentPrincipalAmount - this.totalMultiDisbursed))
|
||||
};
|
||||
const disbursementDialogRef = this.dialog.open(FormDialogComponent, { data });
|
||||
disbursementDialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.data) {
|
||||
const principal = response.data.value.principal * 1;
|
||||
if ((this.totalMultiDisbursed + principal) <= this.currentPrincipalAmount) {
|
||||
this.disbursementDataSource = this.disbursementDataSource.concat(response.data.value);
|
||||
this.pristine = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit the Disbursement Data entry form to given Disbursement Data entry.
|
||||
*/
|
||||
editDisbursementDataEntry(index: number) {
|
||||
const principal: number = this.disbursementDataSource[index]['principal'] * 1;
|
||||
const expectedDisbursementDate: Date = this.dateUtils.parseDate(this.disbursementDataSource[index]['expectedDisbursementDate']);
|
||||
|
||||
const data = {
|
||||
title: 'Edit Disbursement Details',
|
||||
layout: { addButtonText: 'Save' },
|
||||
formfields: this.buildForm(expectedDisbursementDate, principal)
|
||||
};
|
||||
const disbursementDialogRef = this.dialog.open(FormDialogComponent, { data });
|
||||
disbursementDialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.data) {
|
||||
const newPrincipal = response.data.value.principal * 1;
|
||||
if ((this.totalMultiDisbursed - principal + newPrincipal) <= this.currentPrincipalAmount) {
|
||||
this.disbursementDataSource[index]['principal'] = newPrincipal;
|
||||
this.disbursementDataSource[index]['expectedDisbursementDate'] = response.data.value.expectedDisbursementDate;
|
||||
this.pristine = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
removeDisbursementDataEntry(index: any) {
|
||||
const dialogRef = this.dialog.open(DeleteDialogComponent, {
|
||||
data: { deleteContext: `this` }
|
||||
});
|
||||
dialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.delete) {
|
||||
const principal = this.disbursementDataSource[index]['principal'] * 1;
|
||||
this.disbursementDataSource.splice(index, 1);
|
||||
this.disbursementDataSource = this.disbursementDataSource.concat([]);
|
||||
this.totalMultiDisbursed -= principal;
|
||||
this.pristine = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
editDisbursementData() {
|
||||
const disbursementData: any = [];
|
||||
this.disbursementDataSource.forEach((item: any) => {
|
||||
disbursementData.push({
|
||||
expectedDisbursementDate: this.dateUtils.formatDate(item.expectedDisbursementDate, this.settingsService.dateFormat),
|
||||
principal: item.principal
|
||||
});
|
||||
});
|
||||
|
||||
const payload = {
|
||||
disbursementData: disbursementData,
|
||||
dateFormat: this.settingsService.dateFormat,
|
||||
locale: this.settingsService.language.code
|
||||
};
|
||||
this.loanServices.editDisbursements(this.loanId, payload).toPromise()
|
||||
.then(result => {
|
||||
this.pristine = true;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -239,7 +239,6 @@ export class LoansService {
|
||||
.set('locale', foreclosuredata.locale)
|
||||
.set('transactionDate', foreclosuredata.transactionDate);
|
||||
return this.http.get(`/loans/${loanId}/transactions/template`, { params: httpParams });
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -251,6 +250,14 @@ export class LoansService {
|
||||
return this.http.post(`/loans/${loanId}/transactions`, data, { params: httpParams });
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|number} loanId Loan Id
|
||||
* @param {any} data Data
|
||||
*/
|
||||
editDisbursements(loanId: any, data: any) {
|
||||
return this.http.put(`/loans/${loanId}/disbursements/editDisbursements`, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Reschedule Loans Template
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user