feat: add loan action (guarantors) (#1059)
- add view guarantor - add create guarantor - add view guarantor details - add delete guarantor - add recover from guarantor - add delete loan action Fixes: #832, #246
This commit is contained in:
+1
-2
@@ -1,6 +1,5 @@
|
||||
import { Component, OnInit, Inject } from '@angular/core';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
|
||||
import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-recurring-deposit-confirmation-action',
|
||||
@@ -13,7 +12,7 @@ export class RecurringDepositConfirmationDialogComponent implements OnInit {
|
||||
* @param {MatDialogRef} dialogRef Component reference to dialog.
|
||||
* @param {any} data Provides a confirmation for all the recurring deposit actions.
|
||||
*/
|
||||
constructor(public dialogRef: MatDialogRef<DeleteDialogComponent>,
|
||||
constructor(public dialogRef: MatDialogRef<RecurringDepositConfirmationDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any) { }
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
@@ -44,6 +44,10 @@ export class LoanActionButtonResolver implements Resolve<Object> {
|
||||
return this.loansService.getLoanActionTemplate(loanId, 'prepayLoan');
|
||||
} else if (loanActionButton === 'recovery-payment') {
|
||||
return this.loansService.getLoanActionTemplate(loanId, 'recoverypayment');
|
||||
} else if (loanActionButton === 'view-guarantors') {
|
||||
return this.loansService.getLoanAccountResource(loanId, 'guarantors');
|
||||
} else if (loanActionButton === 'create-guarantor') {
|
||||
return this.loansService.getGuarantorTemplate(loanId);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
-2
@@ -26,8 +26,6 @@ export class LoansAccountAddCollateralDialogComponent implements OnInit {
|
||||
|
||||
ngOnInit() {
|
||||
this.dialogRef.updateSize('400px');
|
||||
console.log('collateral: ', this.data.collateralTypeOptions);
|
||||
|
||||
this.collateralTypeData = this.data.collateralTypeOptions;
|
||||
}
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
<h1 mat-dialog-title>Guarantor Detail</h1>
|
||||
|
||||
<div mat-dialog-content fxLayout="column">
|
||||
|
||||
<div fxLayout="row wrap" fxLayout.lt-md="column">
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="50%">First Name:</span>
|
||||
<span fxFlex="50%">{{ data.guarantorData.firstname }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="50%">Last Name:</span>
|
||||
<span fxFlex="50%">{{ data.guarantorData.lastname }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="50%">Relationship:</span>
|
||||
<span fxFlex="50%">{{ data.guarantorData.clientRelationshipType.name }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="50%">Guarantor Type:</span>
|
||||
<span fxFlex="50%">{{ data.guarantorData.guarantorType.value }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="50%">Status:</span>
|
||||
<span fxFlex="50%">
|
||||
<span *ngIf="data.guarantorData.status">
|
||||
Active
|
||||
</span>
|
||||
<span *ngIf="!data.guarantorData.status">
|
||||
Deleted
|
||||
</span></span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<mat-dialog-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="2%">
|
||||
<button mat-raised-button mat-dialog-close> Cancel </button>
|
||||
</mat-dialog-actions>
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { LoansAccountViewGuarantorDetailsDialogComponent } from './loans-account-view-guarantor-details-dialog.component';
|
||||
|
||||
describe('LoansAccountViewGuarantorDetailsDialogComponent', () => {
|
||||
let component: LoansAccountViewGuarantorDetailsDialogComponent;
|
||||
let fixture: ComponentFixture<LoansAccountViewGuarantorDetailsDialogComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ LoansAccountViewGuarantorDetailsDialogComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(LoansAccountViewGuarantorDetailsDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
import { Component, OnInit, Inject } from '@angular/core';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-loans-account-view-guarantor-details-dialog',
|
||||
templateUrl: './loans-account-view-guarantor-details-dialog.component.html',
|
||||
styleUrls: ['./loans-account-view-guarantor-details-dialog.component.scss']
|
||||
})
|
||||
export class LoansAccountViewGuarantorDetailsDialogComponent implements OnInit {
|
||||
|
||||
constructor(public dialogRef: MatDialogRef<LoansAccountViewGuarantorDetailsDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.dialogRef.updateSize('400px');
|
||||
}
|
||||
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<h1 mat-dialog-title>{{data.heading}}</h1>
|
||||
<div mat-dialog-content>
|
||||
<p>{{ data.dialogContext }}</p>
|
||||
</div>
|
||||
<mat-dialog-actions align="end">
|
||||
<button mat-raised-button mat-dialog-close>Cancel</button>
|
||||
<button mat-raised-button color="warn" [mat-dialog-close]="{ confirm: true }">Confirm</button>
|
||||
</mat-dialog-actions>
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { LoansConfirmationDialogBoxComponent } from './loans-confirmation-dialog-box.component';
|
||||
|
||||
describe('LoansConfirmationDialogBoxComponent', () => {
|
||||
let component: LoansConfirmationDialogBoxComponent;
|
||||
let fixture: ComponentFixture<LoansConfirmationDialogBoxComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ LoansConfirmationDialogBoxComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(LoansConfirmationDialogBoxComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
import { Component, OnInit, Inject } from '@angular/core';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
|
||||
import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-loans-confirmation-dialog-box',
|
||||
templateUrl: './loans-confirmation-dialog-box.component.html',
|
||||
styleUrls: ['./loans-confirmation-dialog-box.component.scss']
|
||||
})
|
||||
export class LoansConfirmationDialogBoxComponent implements OnInit {
|
||||
|
||||
/**
|
||||
* @param {MatDialogRef} dialogRef Component reference to dialog.
|
||||
* @param {any} data Provides a confirmation for all the loans account actions.
|
||||
*/
|
||||
constructor(public dialogRef: MatDialogRef<LoansConfirmationDialogBoxComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any) { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
||||
+1
-2
@@ -6,7 +6,7 @@ import { MatDialog } from '@angular/material';
|
||||
/** Dialog Components */
|
||||
import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
|
||||
import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component';
|
||||
import { LoansAccountAddCollateralDialogComponent } from 'app/loans/loans-account-add-collateral-dialog/loans-account-add-collateral-dialog.component';
|
||||
import { LoansAccountAddCollateralDialogComponent } from 'app/loans/custom-dialog/loans-account-add-collateral-dialog/loans-account-add-collateral-dialog.component';
|
||||
|
||||
/** Custom Services */
|
||||
import { DatePipe } from '@angular/common';
|
||||
@@ -211,7 +211,6 @@ export class LoansAccountChargesStepComponent implements OnInit, OnChanges {
|
||||
});
|
||||
addCollateralDialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.addCollateralForm) {
|
||||
console.log('formdata: ', response.addCollateralForm);
|
||||
const collateralData = {
|
||||
type: response.addCollateralForm.value.type,
|
||||
value: response.addCollateralForm.value.value,
|
||||
|
||||
@@ -74,7 +74,7 @@ export const ButtonConfig = {
|
||||
taskPermissionName: 'CREATE_LOANCHARGE',
|
||||
},
|
||||
{
|
||||
name: 'List Guarantor',
|
||||
name: 'View Guarantors',
|
||||
taskPermissionName: 'READ_GUARANTOR',
|
||||
},
|
||||
{
|
||||
@@ -137,7 +137,7 @@ export const ButtonConfig = {
|
||||
taskPermissionName: 'READ_LOAN',
|
||||
},
|
||||
{
|
||||
name: 'List Guarantor',
|
||||
name: 'View Guarantors',
|
||||
taskPermissionName: 'READ_GUARANTOR',
|
||||
},
|
||||
{
|
||||
@@ -145,7 +145,7 @@ export const ButtonConfig = {
|
||||
taskPermissionName: 'CREATE_GUARANTOR',
|
||||
},
|
||||
{
|
||||
name: 'Recover Guarantee',
|
||||
name: 'Recover From Guarantor',
|
||||
taskPermissionName: 'RECOVERGUARANTEES_LOAN',
|
||||
},
|
||||
],
|
||||
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
<div class="container">
|
||||
<form [formGroup]="newGuarantorForm" (ngSubmit)="submit()">
|
||||
|
||||
<mat-card-content>
|
||||
|
||||
<div fxLayout="column">
|
||||
|
||||
<mat-checkbox labelPosition="before" formControlName="existingClient">
|
||||
Existing Client
|
||||
</mat-checkbox>
|
||||
|
||||
<ng-container *ngIf="!showClientDetailsForm">
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput required formControlName="name" required>
|
||||
<mat-error *ngIf="newGuarantorForm.controls.name.hasError('required')">
|
||||
Name <strong>is required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
</ng-container>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Relationship</mat-label>
|
||||
<mat-select formControlName="clientRelationshipTypeId">
|
||||
<mat-option *ngFor="let relationType of relationTypes" [value]="relationType.id">
|
||||
{{ relationType.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<ng-container *ngIf="showClientDetailsForm">
|
||||
<mat-form-field>
|
||||
<mat-label>First Name</mat-label>
|
||||
<input matInput required formControlName="firstname" required>
|
||||
<mat-error *ngIf="newGuarantorForm.controls.firstname.hasError('required')">
|
||||
First Name <strong>is required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Last Name</mat-label>
|
||||
<input matInput required formControlName="lastname" required>
|
||||
<mat-error *ngIf="newGuarantorForm.controls.lastname.hasError('required')">
|
||||
Last Name <strong>is required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Date Of Birth</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>Address Line 1</mat-label>
|
||||
<input matInput formControlName="addressLine1">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Address Line 2</mat-label>
|
||||
<input matInput formControlName="addressLine2">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>City</mat-label>
|
||||
<input matInput formControlName="city">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Zip</mat-label>
|
||||
<input matInput formControlName="zip">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Mobile</mat-label>
|
||||
<input type="number" matInput formControlName="mobileNumber">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Residence Phone #</mat-label>
|
||||
<input type="number" matInput formControlName="housePhoneNumber">
|
||||
</mat-form-field>
|
||||
|
||||
</ng-container>
|
||||
|
||||
</div>
|
||||
|
||||
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
||||
<button type="button" mat-raised-button [routerLink]="['../general']">Cancel</button>
|
||||
<button mat-raised-button color="primary" [disabled]="!newGuarantorForm.valid"
|
||||
*mifosxHasPermission="'CREATE_GUARANTOR'">Submit</button>
|
||||
</mat-card-actions>
|
||||
|
||||
</mat-card-content>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CreateGuarantorComponent } from './create-guarantor.component';
|
||||
|
||||
describe('CreateGuarantorComponent', () => {
|
||||
let component: CreateGuarantorComponent;
|
||||
let fixture: ComponentFixture<CreateGuarantorComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ CreateGuarantorComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CreateGuarantorComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
/** Angular Imports */
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { FormGroup, FormBuilder, Validators, FormControl } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
/** Custom Services */
|
||||
import { LoansService } from 'app/loans/loans.service';
|
||||
import { DatePipe } from '@angular/common';
|
||||
|
||||
/**
|
||||
* Create Guarantor Action
|
||||
*/
|
||||
@Component({
|
||||
selector: 'mifosx-create-guarantor',
|
||||
templateUrl: './create-guarantor.component.html',
|
||||
styleUrls: ['./create-guarantor.component.scss']
|
||||
})
|
||||
export class CreateGuarantorComponent implements OnInit {
|
||||
|
||||
@Input() dataObject: any;
|
||||
/** New Guarantor Form */
|
||||
newGuarantorForm: FormGroup;
|
||||
/** Loan ID */
|
||||
loanId: string;
|
||||
/** Relation Types */
|
||||
relationTypes: any;
|
||||
/** Show Client Details Form */
|
||||
showClientDetailsForm = false;
|
||||
/** Minimum date allowed. */
|
||||
minDate = new Date(2000, 0, 1);
|
||||
/** Maximum date allowed. */
|
||||
maxDate = new Date();
|
||||
|
||||
/**
|
||||
* @param {FormBuilder} formBuilder Form Builder.
|
||||
* @param {LoansService} loanService Loan Service.
|
||||
* @param {ActivatedRoute} route Activated Route.
|
||||
* @param {Router} router Router for navigation.
|
||||
* @param {DatePipe} datePipe Date Pipe.
|
||||
*/
|
||||
constructor(private formBuilder: FormBuilder,
|
||||
private loanService: LoansService,
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private datePipe: DatePipe) {
|
||||
this.loanId = this.route.parent.snapshot.params['loanId'];
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.createNewGuarantorForm();
|
||||
this.setNewGuarantorDetailsForm();
|
||||
this.buildDependencies();
|
||||
}
|
||||
|
||||
/** Create Guarantor Details Form */
|
||||
createNewGuarantorForm() {
|
||||
this.newGuarantorForm = this.formBuilder.group({
|
||||
'existingClient': [''],
|
||||
'name': ['', Validators.required],
|
||||
'clientRelationshipTypeId': ['']
|
||||
});
|
||||
}
|
||||
|
||||
/** Sets Guarantor Details Form */
|
||||
setNewGuarantorDetailsForm() {
|
||||
this.relationTypes = this.dataObject.allowedClientRelationshipTypes;
|
||||
this.newGuarantorForm.patchValue({
|
||||
existingClient: true
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add guarantor detail fields to the UI.
|
||||
*/
|
||||
buildDependencies() {
|
||||
this.newGuarantorForm.get('existingClient').valueChanges.subscribe(() => {
|
||||
this.showClientDetailsForm = !this.showClientDetailsForm;
|
||||
if (this.showClientDetailsForm) {
|
||||
this.newGuarantorForm.addControl('firstname', new FormControl(''));
|
||||
this.newGuarantorForm.addControl('lastname', new FormControl(''));
|
||||
this.newGuarantorForm.addControl('dob', new FormControl(''));
|
||||
this.newGuarantorForm.addControl('addressLine1', new FormControl(''));
|
||||
this.newGuarantorForm.addControl('addressLine2', new FormControl(''));
|
||||
this.newGuarantorForm.addControl('city', new FormControl(''));
|
||||
this.newGuarantorForm.addControl('zip', new FormControl(''));
|
||||
this.newGuarantorForm.addControl('mobileNumber', new FormControl(''));
|
||||
this.newGuarantorForm.addControl('housePhoneNumber', new FormControl(''));
|
||||
this.newGuarantorForm.removeControl('name');
|
||||
} else {
|
||||
this.newGuarantorForm.addControl('name', new FormControl(''));
|
||||
this.newGuarantorForm.removeControl('firstname');
|
||||
this.newGuarantorForm.removeControl('lastname');
|
||||
this.newGuarantorForm.removeControl('dob');
|
||||
this.newGuarantorForm.removeControl('addressLine1');
|
||||
this.newGuarantorForm.removeControl('addressLine2');
|
||||
this.newGuarantorForm.removeControl('city');
|
||||
this.newGuarantorForm.removeControl('zip');
|
||||
this.newGuarantorForm.removeControl('mobileNumber');
|
||||
this.newGuarantorForm.removeControl('housePhoneNumber');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Submits the new guarantor details form */
|
||||
submit() {
|
||||
const prevdob: Date = this.newGuarantorForm.value.dob;
|
||||
const guarantorTypeId: number = this.newGuarantorForm.value.existingClient ? this.dataObject.guarantorTypeOptions[0].id : this.dataObject.guarantorTypeOptions[2].id;
|
||||
// TODO: Update once language and date settings are setup
|
||||
const dateFormat = 'dd-MM-yyyy';
|
||||
const locale = 'en';
|
||||
const newGuarantorData = {
|
||||
... this.newGuarantorForm.value,
|
||||
dob: this.datePipe.transform(prevdob, dateFormat),
|
||||
locale,
|
||||
dateFormat,
|
||||
guarantorTypeId
|
||||
};
|
||||
delete newGuarantorData.existingClient;
|
||||
this.loanService.createNewGuarantor(this.loanId, newGuarantorData)
|
||||
.subscribe((response: any) => {
|
||||
this.router.navigate(['../general'], { relativeTo: this.route });
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,5 +11,7 @@
|
||||
<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>
|
||||
</mat-card>
|
||||
</div>
|
||||
|
||||
@@ -23,7 +23,9 @@ export class LoanAccountActionsComponent {
|
||||
waive_interest: boolean,
|
||||
close_as_rescheduled: boolean,
|
||||
reschedule: boolean,
|
||||
recovery_payment: boolean } = {
|
||||
recovery_payment: boolean,
|
||||
view_guarantors: boolean,
|
||||
create_guarantor: boolean } = {
|
||||
close: false,
|
||||
undo_approval: false,
|
||||
write_off: false,
|
||||
@@ -34,7 +36,9 @@ export class LoanAccountActionsComponent {
|
||||
waive_interest: false,
|
||||
close_as_rescheduled: false,
|
||||
reschedule: false,
|
||||
recovery_payment: false };
|
||||
recovery_payment: false,
|
||||
view_guarantors: false,
|
||||
create_guarantor: false };
|
||||
|
||||
actionButtonData: any;
|
||||
actionName: any;
|
||||
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
<div class="viewGuarantors-account-tables" fxLayout="row" fxLayoutGap="2%">
|
||||
|
||||
<div fxFlex="49%">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Disbursement Date</td>
|
||||
<td>{{dataObject.timeline.actualDisbursementDate}}<span
|
||||
*ngIf="!dataObject.timeline.actualDisbursementDate">Not Available</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Currency</td>
|
||||
<td>{{dataObject.currency.name}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Loan Officer</td>
|
||||
<td>{{dataObject.loanOfficerName}} <span *ngIf="!dataObject.loanOfficerName">Unassigned</span>
|
||||
<span *ngIf="dataObject.loanOfficerName">
|
||||
<fa-icon icon="times"></fa-icon>
|
||||
</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>External Id</td>
|
||||
<td>{{dataObject.externalId}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div fxFlex="49%">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Loan Purpose</td>
|
||||
<td>
|
||||
{{dataObject.loanPurposeName}} <span *ngIf="!dataObject.loanPurposeName"> Not Provided </span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Approved Amount</td>
|
||||
<td>
|
||||
<span>{{dataObject.approvedPrincipal | number}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Disburse Amount</td>
|
||||
<td>
|
||||
<span>{{dataObject.principal | number}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Arrears By</td>
|
||||
<td>{{dataObject.summary.totalOverdue | number}}
|
||||
<span *ngIf="dataObject.summary.totalOverdue < 0">Not Provided</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill *ngIf="guarantorDetails" fxLayout="row wrap" fxLayout.lt-md="column">
|
||||
|
||||
<!-- guarantors details table -->
|
||||
<div class="headingContent">
|
||||
<div fxLayout="column" fxFlex="50%">
|
||||
<div class="headingName">
|
||||
<h3>Guarantors Details</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div fxLayout="column" fxFlex="50%">
|
||||
<div fxLayout="row" fxLayoutAlign="flex-end">
|
||||
<button mat-raised-button class="f-right" color="primary"
|
||||
(click)="toggleGuarantorsDetailsOverview()">{{showDeletedGuarantorsAccounts?'Hide Deleted Guarantors':'Show Deleted Guarantors'}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table fxFlexFill mat-table [dataSource]="guarantorDetails|accountsFilter:'guarantor':showDeletedGuarantorsAccounts">
|
||||
<!-- <ng-container *ngIf="expression"> -->
|
||||
<ng-container matColumnDef="fullname">
|
||||
<th mat-header-cell *matHeaderCellDef> Name </th>
|
||||
<td mat-cell *matCellDef="let guarantor">
|
||||
<span *ngIf="!guarantor.guarantorFundingDetails">
|
||||
{{guarantor.firstname}} {{guarantor.lastname}}
|
||||
</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="relationship">
|
||||
<th mat-header-cell *matHeaderCellDef> Relationship </th>
|
||||
<td mat-cell *matCellDef="let guarantor">
|
||||
<span *ngIf="!guarantor.guarantorFundingDetails">
|
||||
{{guarantor.clientRelationshipType.name}}
|
||||
</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="guarantortype">
|
||||
<th mat-header-cell *matHeaderCellDef> Guarantor Type </th>
|
||||
<td mat-cell *matCellDef="let guarantor">
|
||||
<span *ngIf="!guarantor.guarantorFundingDetails">
|
||||
{{guarantor.guarantorType.value}}
|
||||
</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="depositAccount">
|
||||
<th mat-header-cell *matHeaderCellDef> Deposit Account </th>
|
||||
<td mat-cell *matCellDef="let guarantor">
|
||||
<span *ngIf="!guarantor.guarantorFundingDetails">
|
||||
|
||||
</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="amount">
|
||||
<th mat-header-cell *matHeaderCellDef> Amount </th>
|
||||
<td mat-cell *matCellDef="let guarantor">
|
||||
<span *ngIf="!guarantor.guarantorFundingDetails">
|
||||
|
||||
</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="remainingAmount">
|
||||
<th mat-header-cell *matHeaderCellDef> Remaining Amount </th>
|
||||
<td mat-cell *matCellDef="let guarantor">
|
||||
<span *ngIf="!guarantor.guarantorFundingDetails">
|
||||
|
||||
</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="status">
|
||||
<th mat-header-cell *matHeaderCellDef> Status </th>
|
||||
<td mat-cell *matCellDef="let guarantor">
|
||||
<span *ngIf="!guarantor.guarantorFundingDetails">
|
||||
<span *ngIf="guarantor.status">
|
||||
Active
|
||||
</span>
|
||||
<span *ngIf="!guarantor.status">
|
||||
Deleted
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="action">
|
||||
<th mat-header-cell *matHeaderCellDef> Action </th>
|
||||
<td mat-cell *matCellDef="let guarantor; let id = index">
|
||||
<span *ngIf="!guarantor.guarantorFundingDetails">
|
||||
<button mat-raised-button class="account-action-button" color="primary" (click)="viewGuarantorDetails(guarantor)">
|
||||
<fa-icon icon="eye"></fa-icon>
|
||||
</button>
|
||||
<button mat-raised-button class="account-action-button" color="primary" *ngIf="guarantor.status && guarantor.guarantorType.id == 3 && guarantor.id">
|
||||
<fa-icon icon="edit"></fa-icon>
|
||||
</button>
|
||||
<span *ngIf="guarantor.status">
|
||||
<button mat-raised-button class="account-action-button" color="warn" *mifosxHasPermission='"DELETE_GUARANTOR"' (click)="deleteGuarantor(guarantor.id)">
|
||||
<fa-icon icon="trash" ></fa-icon>
|
||||
</button>
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- </ng-container> -->
|
||||
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="guarantorsDisplayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: guarantorsDisplayedColumns"></tr>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
.viewGuarantors-account-tables {
|
||||
padding: 1%;
|
||||
margin: 1%;
|
||||
.table-headers {
|
||||
margin: 0;
|
||||
padding: 6px;
|
||||
}
|
||||
td {
|
||||
padding: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
.account-action-button{
|
||||
min-width: 26px;
|
||||
padding: 0 6px;
|
||||
margin: 4px;
|
||||
line-height: 25px;
|
||||
}
|
||||
}
|
||||
|
||||
.headingContent{
|
||||
margin-bottom: 1%;
|
||||
margin-top: 1%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.headingName {
|
||||
display: block;
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ViewGuarantorsComponent } from './view-guarantors.component';
|
||||
|
||||
describe('ViewGuarantorsComponent', () => {
|
||||
let component: ViewGuarantorsComponent;
|
||||
let fixture: ComponentFixture<ViewGuarantorsComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ ViewGuarantorsComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ViewGuarantorsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/** Angular Imports */
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { FormGroup, FormBuilder, Validators, FormControl } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { MatDialog } from '@angular/material';
|
||||
|
||||
/** Custom Services */
|
||||
import { LoansService } from 'app/loans/loans.service';
|
||||
import { DatePipe } from '@angular/common';
|
||||
|
||||
/** Dialog Components */
|
||||
import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
|
||||
import { LoansAccountViewGuarantorDetailsDialogComponent } from 'app/loans/custom-dialog/loans-account-view-guarantor-details-dialog/loans-account-view-guarantor-details-dialog.component';
|
||||
|
||||
/**
|
||||
* View Guarantors Action
|
||||
*/
|
||||
@Component({
|
||||
selector: 'mifosx-view-guarantors',
|
||||
templateUrl: './view-guarantors.component.html',
|
||||
styleUrls: ['./view-guarantors.component.scss']
|
||||
})
|
||||
export class ViewGuarantorsComponent implements OnInit {
|
||||
|
||||
@Input() dataObject: any;
|
||||
guarantorDetails: any;
|
||||
showDeletedGuarantorsAccounts = false;
|
||||
loanId: any;
|
||||
guarantorsDisplayedColumns: string[] = ['fullname', 'relationship', 'guarantortype', 'depositAccount', 'amount', 'remainingAmount', 'status', 'action'];
|
||||
|
||||
/** View and perform various action on existing list of guarantors
|
||||
* @param {MatDialog} dialog Dialog
|
||||
* @param {LoansService} loansService Loans Service
|
||||
* @param {route} Route Route
|
||||
* @param {router} Router Router
|
||||
*/
|
||||
constructor(public dialog: MatDialog,
|
||||
public loansService: LoansService,
|
||||
private route: ActivatedRoute,
|
||||
private router: Router) {
|
||||
this.loanId = this.route.parent.snapshot.params['loanId'];
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.guarantorDetails = this.dataObject.guarantors;
|
||||
}
|
||||
|
||||
toggleGuarantorsDetailsOverview() {
|
||||
this.showDeletedGuarantorsAccounts = !this.showDeletedGuarantorsAccounts;
|
||||
}
|
||||
|
||||
deleteGuarantor(id: any) {
|
||||
const deleteGuarantorDialogRef = this.dialog.open(DeleteDialogComponent, {
|
||||
data: { deleteContext: `the guarantor id: ${id}` }
|
||||
});
|
||||
deleteGuarantorDialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.delete) {
|
||||
this.loansService.deleteGuarantor(this.loanId, id).subscribe(() => {
|
||||
this.reload();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
viewGuarantorDetails(guarantorData: any) {
|
||||
const viewGuarantorDetailsDialogRef = this.dialog.open(LoansAccountViewGuarantorDetailsDialogComponent, {
|
||||
data: { guarantorData: guarantorData }
|
||||
});
|
||||
viewGuarantorDetailsDialogRef.afterClosed().subscribe(() => {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Refetches data for the component
|
||||
* TODO: Replace by a custom reload component instead of hard-coded back-routing.
|
||||
*/
|
||||
private reload() {
|
||||
const clientId = this.dataObject.clientId;
|
||||
const url: string = this.router.url;
|
||||
this.router.navigateByUrl(`/clients/${clientId}/loans`, { skipLocationChange: true })
|
||||
.then(() => this.router.navigate([url]));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +1,18 @@
|
||||
/** Angular Imports */
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { MatDialog } from '@angular/material';
|
||||
|
||||
/** Custom Services */
|
||||
import { LoansService } from '../loans.service';
|
||||
|
||||
// Custom Imports
|
||||
/** Custom Buttons Configuration */
|
||||
import { ButtonConfig } from './button-config';
|
||||
|
||||
/** Dialog Components */
|
||||
import { LoansConfirmationDialogBoxComponent } from '../custom-dialog/loans-confirmation-dialog-box/loans-confirmation-dialog-box.component';
|
||||
import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-loans-view',
|
||||
templateUrl: './loans-view.component.html',
|
||||
@@ -28,14 +36,18 @@ export class LoansViewComponent implements OnInit {
|
||||
}[]
|
||||
};
|
||||
loanId: number;
|
||||
clientId: any;
|
||||
|
||||
constructor(private route: ActivatedRoute,
|
||||
private router: Router) {
|
||||
private router: Router,
|
||||
public loansService: LoansService,
|
||||
public dialog: MatDialog) {
|
||||
this.route.data.subscribe((data: { loanDetailsData: any, loanDatatables: any}) => {
|
||||
this.loanDetailsData = data.loanDetailsData;
|
||||
this.loanDatatables = data.loanDatatables;
|
||||
});
|
||||
this.loanId = this.route.snapshot.params['loanId'];
|
||||
this.clientId = this.loanDetailsData.clientId;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -111,10 +123,62 @@ export class LoansViewComponent implements OnInit {
|
||||
}
|
||||
|
||||
loanAction(button: string) {
|
||||
button = button.replace(/\s/g, '-').toLowerCase();
|
||||
button = button.replace(/\(/g, '');
|
||||
button = button.replace(/\)/g, '');
|
||||
this.router.navigate([button], { relativeTo: this.route });
|
||||
console.log('button: ', button);
|
||||
|
||||
switch (button) {
|
||||
case 'Recover From Guarantor':
|
||||
this.recoverFromGuarantor();
|
||||
break;
|
||||
case 'Delete':
|
||||
this.deleteLoanAccount();
|
||||
break;
|
||||
default:
|
||||
button = button.replace(/\s/g, '-').toLowerCase();
|
||||
button = button.replace(/\(/g, '');
|
||||
button = button.replace(/\)/g, '');
|
||||
this.router.navigate([button], { relativeTo: this.route });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recover from guarantor action
|
||||
*/
|
||||
private recoverFromGuarantor() {
|
||||
const recoverFromGuarantorDialogRef = this.dialog.open(LoansConfirmationDialogBoxComponent, {
|
||||
data: { heading: 'Recover from Guarantor', dialogContext: 'Are you sure you want recover from Guarantor ?' }
|
||||
});
|
||||
recoverFromGuarantorDialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.confirm) {
|
||||
this.loansService.loanActionButtons(this.loanId, 'recoverGuarantees').subscribe(() => {
|
||||
this.reload();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private deleteLoanAccount() {
|
||||
const deleteGuarantorDialogRef = this.dialog.open(DeleteDialogComponent, {
|
||||
data: { deleteContext: `with loan id: ${this.loanId}` }
|
||||
});
|
||||
deleteGuarantorDialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.delete) {
|
||||
this.loansService.deleteLoanAccount(this.loanId).subscribe(() => {
|
||||
this.router.navigate(['../../'], { relativeTo: this.route });
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Refetches data for the component
|
||||
* TODO: Replace by a custom reload component instead of hard-coded back-routing.
|
||||
*/
|
||||
private reload() {
|
||||
const clientId = this.clientId;
|
||||
const url: string = this.router.url;
|
||||
this.router.navigateByUrl(`/clients/${clientId}/loans`, { skipLocationChange: true })
|
||||
.then(() => this.router.navigate([url]));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -41,8 +41,14 @@ import { LoansAccountDetailsStepComponent } from './loans-account-stepper/loans-
|
||||
import { LoansAccountTermsStepComponent } from './loans-account-stepper/loans-account-terms-step/loans-account-terms-step.component';
|
||||
import { LoansAccountChargesStepComponent } from './loans-account-stepper/loans-account-charges-step/loans-account-charges-step.component';
|
||||
import { LoansAccountPreviewStepComponent } from './loans-account-stepper/loans-account-preview-step/loans-account-preview-step.component';
|
||||
import { LoansAccountAddCollateralDialogComponent } from './loans-account-add-collateral-dialog/loans-account-add-collateral-dialog.component';
|
||||
import { RecoveryRepaymentComponent } from './loans-view/loan-account-actions/recovery-repayment/recovery-repayment.component';
|
||||
import { ViewGuarantorsComponent } from './loans-view/loan-account-actions/view-guarantors/view-guarantors.component';
|
||||
import { CreateGuarantorComponent } from './loans-view/loan-account-actions/create-guarantor/create-guarantor.component';
|
||||
|
||||
/** Dialog Components */
|
||||
import { LoansAccountViewGuarantorDetailsDialogComponent } from './custom-dialog/loans-account-view-guarantor-details-dialog/loans-account-view-guarantor-details-dialog.component';
|
||||
import { LoansAccountAddCollateralDialogComponent } from './custom-dialog/loans-account-add-collateral-dialog/loans-account-add-collateral-dialog.component';
|
||||
import { LoansConfirmationDialogBoxComponent } from './custom-dialog/loans-confirmation-dialog-box/loans-confirmation-dialog-box.component';
|
||||
|
||||
/**
|
||||
* Loans Module
|
||||
@@ -86,9 +92,15 @@ import { RecoveryRepaymentComponent } from './loans-view/loan-account-actions/re
|
||||
LoansAccountPreviewStepComponent,
|
||||
LoansAccountAddCollateralDialogComponent,
|
||||
RecoveryRepaymentComponent,
|
||||
ViewGuarantorsComponent,
|
||||
CreateGuarantorComponent,
|
||||
LoansAccountViewGuarantorDetailsDialogComponent,
|
||||
LoansConfirmationDialogBoxComponent,
|
||||
],
|
||||
entryComponents: [
|
||||
LoansAccountAddCollateralDialogComponent
|
||||
LoansAccountAddCollateralDialogComponent,
|
||||
LoansAccountViewGuarantorDetailsDialogComponent,
|
||||
LoansConfirmationDialogBoxComponent
|
||||
],
|
||||
providers: [DatePipe],
|
||||
})
|
||||
|
||||
@@ -26,6 +26,27 @@ export class LoansService {
|
||||
return this.http.get(`/loans/${loanId}/transactions/template`, { params: httpParams });
|
||||
}
|
||||
|
||||
getLoanAccountResource(loanId: string, associations: string): Observable<any> {
|
||||
const httpParams = new HttpParams().set('associations', associations);
|
||||
return this.http.get(`/loans/${loanId}`, { params: httpParams });
|
||||
}
|
||||
|
||||
getGuarantorTemplate(loanId: string): Observable<any> {
|
||||
return this.http.get(`/loans/${loanId}/guarantors/template`);
|
||||
}
|
||||
|
||||
createNewGuarantor(loanId: string, data: any): Observable<any> {
|
||||
return this.http.post(`/loans/${loanId}/guarantors`, data);
|
||||
}
|
||||
|
||||
deleteGuarantor(loanId: any, guarantorId: any): Observable<any> {
|
||||
return this.http.delete(`/loans/${loanId}/guarantors/${guarantorId}`);
|
||||
}
|
||||
|
||||
deleteLoanAccount(loanId: any): Observable<any> {
|
||||
return this.http.delete(`/loans/${loanId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the loan template data with specific condition
|
||||
* @param loanId Loan Id
|
||||
@@ -169,7 +190,7 @@ export class LoansService {
|
||||
* @param {any} data Data.
|
||||
* @returns {Observable<any>}
|
||||
*/
|
||||
loanActionButtons(loanId: string, data: any, command: any): Observable<any> {
|
||||
loanActionButtons(loanId: any, command: any, data?: any): Observable<any> {
|
||||
const httpParams = new HttpParams().set('command', command);
|
||||
return this.http.post(`/loans/${loanId}`, data, {params: httpParams});
|
||||
}
|
||||
|
||||
@@ -69,6 +69,15 @@ export class AccountsFilterPipe implements PipeTransform {
|
||||
});
|
||||
}
|
||||
}
|
||||
if (type === 'guarantor') {
|
||||
if (status === false) {
|
||||
accounts = accounts.filter((account: any) => {
|
||||
return (account.status === true);
|
||||
});
|
||||
} else {
|
||||
return accounts;
|
||||
}
|
||||
}
|
||||
return accounts;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user