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:
Muskan Khedia
2020-07-12 11:06:38 +05:30
committed by GitHub
parent e74fdcf27b
commit ff6ac7028e
30 changed files with 838 additions and 20 deletions
@@ -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;
}
@@ -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;
}
@@ -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>
@@ -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();
});
});
@@ -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');
}
}
@@ -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>
@@ -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();
});
});
@@ -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() {
}
}
@@ -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,
+3 -3
View File
@@ -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',
},
],
@@ -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>
@@ -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();
});
});
@@ -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;
@@ -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}} &nbsp; {{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>&nbsp;&nbsp;
</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>&nbsp;&nbsp;
</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>&nbsp;&nbsp;
</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>
@@ -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;
}
@@ -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();
});
});
@@ -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]));
}
}
+14 -2
View File
@@ -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],
})
+22 -1
View File
@@ -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});
}
+9
View File
@@ -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;
}
}