Delinquency buckets management for Loans
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
<div fxLayout="row" fxLayoutGap="32px" class="performance-history-container">
|
||||
<p>
|
||||
# of Repayments :{{loanDetails?.numberOfRepayments}}
|
||||
</p>
|
||||
<p>
|
||||
Maturity Date :{{loanDetails?.timeline.expectedMaturityDate | dateFormat}}
|
||||
</p>
|
||||
@@ -69,7 +70,7 @@
|
||||
|
||||
<ng-container matColumnDef="Value">
|
||||
<th mat-header-cell *matHeaderCellDef> Value </th>
|
||||
<td mat-cell *matCellDef="let ele">
|
||||
<td mat-cell *matCellDef="let ele">
|
||||
<ng-container *ngIf="ele.key === 'Disbursement Date'" >
|
||||
<span *ngIf="loanDetails.timeline.actualDisbursementDate"> {{loanDetails.timeline.actualDisbursementDate | dateFormat}} </span>
|
||||
<span *ngIf="!loanDetails.timeline.actualDisbursementDate"> Not Available </span>
|
||||
@@ -124,7 +125,7 @@
|
||||
|
||||
<ng-container matColumnDef="Value">
|
||||
<th mat-header-cell *matHeaderCellDef> Value </th>
|
||||
<td mat-cell *matCellDef="let ele">
|
||||
<td mat-cell *matCellDef="let ele">
|
||||
<ng-container *ngIf="ele.key === 'Disbursement Date'" >
|
||||
<span *ngIf="loanDetails.timeline.actualDisbursementDate"> {{loanDetails.timeline.actualDisbursementDate | dateFormat}} </span>
|
||||
<span *ngIf="!loanDetails.timeline.actualDisbursementDate"> Not Available </span>
|
||||
|
||||
+6
-2
@@ -1,5 +1,9 @@
|
||||
<div class="container">
|
||||
|
||||
<ng-container *ngIf="loanDetails.delinquencyRange">
|
||||
<h3>Loan Account Classification : {{loanDetails?.delinquencyRange.classification}}</h3>
|
||||
</ng-container>
|
||||
|
||||
<table mat-table [dataSource]="repaymentScheduleDetails.periods">
|
||||
|
||||
<ng-container matColumnDef="number">
|
||||
@@ -29,7 +33,7 @@
|
||||
<ng-container matColumnDef="check">
|
||||
<th mat-header-cell *matHeaderCellDef> </th>
|
||||
<td mat-cell *matCellDef="let ele">
|
||||
<span *ngIf="ele.obligationsMetOnDate"> <i class='fa fa-check'></i> </span>
|
||||
<span *ngIf="ele.obligationsMetOnDate"> <i class='fa fa-check'></i> </span>
|
||||
</td>
|
||||
<td mat-footer-cell *matFooterCellDef> </td>
|
||||
</ng-container>
|
||||
@@ -135,4 +139,4 @@
|
||||
|
||||
</div>
|
||||
|
||||
<!-- <p>It works</p> -->
|
||||
<!-- <p>It works</p> -->
|
||||
|
||||
+1
-1
@@ -9,4 +9,4 @@ table {
|
||||
|
||||
.check {
|
||||
padding-left: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { ActivatedRoute } from '@angular/router';
|
||||
})
|
||||
export class RepaymentScheduleTabComponent implements OnInit {
|
||||
|
||||
loanDetails: any;
|
||||
/** Loan Repayment Schedule Details Data */
|
||||
repaymentScheduleDetails: any;
|
||||
/** Stores if there is any waived amount */
|
||||
@@ -21,6 +22,7 @@ export class RepaymentScheduleTabComponent implements OnInit {
|
||||
*/
|
||||
constructor(private route: ActivatedRoute) {
|
||||
this.route.parent.data.subscribe((data: { loanDetailsData: any }) => {
|
||||
this.loanDetails = data.loanDetailsData;
|
||||
this.repaymentScheduleDetails = data.loanDetailsData.repaymentSchedule;
|
||||
});
|
||||
}
|
||||
|
||||
+5
@@ -346,6 +346,11 @@
|
||||
<span fxFlex="60%">{{ loanProduct.overdueDaysForNPA }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Delinquency Bucket:</span>
|
||||
<span fxFlex="60%">{{ loanProduct.delinquencyBucketId ? 'Yes' : 'No' }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Account moves out of NPA only after all arrears have been cleared:</span>
|
||||
<span fxFlex="60%">{{ loanProduct.accountMovesOutOfNPAOnlyOnArrearsCompletion ? 'Yes' : 'No' }}</span>
|
||||
|
||||
+9
@@ -72,6 +72,15 @@
|
||||
<input type="number" matInput formControlName="graceOnInterestPayment">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Delinquency Bucket</mat-label>
|
||||
<mat-select formControlName="delinquencyBucketId">
|
||||
<mat-option *ngFor="let delinquencyBucket of delinquencyBucketData" [value]="delinquencyBucket.id">
|
||||
{{ delinquencyBucket.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-divider fxFlex="98%"></mat-divider>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
|
||||
+6
-2
@@ -26,6 +26,7 @@ export class LoanProductSettingsStepComponent implements OnInit {
|
||||
interestRecalculationNthDayTypeData: any;
|
||||
interestRecalculationDayOfWeekTypeData: any;
|
||||
interestRecalculationOnDayTypeData: any;
|
||||
delinquencyBucketData: any;
|
||||
|
||||
constructor(private formBuilder: FormBuilder) {
|
||||
this.createLoanProductSettingsForm();
|
||||
@@ -54,6 +55,7 @@ export class LoanProductSettingsStepComponent implements OnInit {
|
||||
this.interestRecalculationNthDayTypeData.push({ 'id': -2, 'code': 'onDay', 'value': 'on day' });
|
||||
this.interestRecalculationDayOfWeekTypeData = this.loanProductsTemplate.interestRecalculationDayOfWeekTypeOptions;
|
||||
this.interestRecalculationOnDayTypeData = Array.from({ length: 28 }, (_, index) => index + 1);
|
||||
this.delinquencyBucketData = this.loanProductsTemplate.delinquencyBucketOptions;
|
||||
|
||||
this.loanProductSettingsForm.patchValue({
|
||||
'amortizationType': this.loanProductsTemplate.amortizationType.id,
|
||||
@@ -82,7 +84,8 @@ export class LoanProductSettingsStepComponent implements OnInit {
|
||||
'holdGuaranteeFunds': this.loanProductsTemplate.holdGuaranteeFunds,
|
||||
'multiDisburseLoan': this.loanProductsTemplate.multiDisburseLoan,
|
||||
'maxTrancheCount': this.loanProductsTemplate.maxTrancheCount,
|
||||
'outstandingLoanBalance': this.loanProductsTemplate.outstandingLoanBalance
|
||||
'outstandingLoanBalance': this.loanProductsTemplate.outstandingLoanBalance,
|
||||
'delinquencyBucketId': this.loanProductsTemplate.delinquencyBucket.id
|
||||
});
|
||||
|
||||
if (this.loanProductsTemplate.isInterestRecalculationEnabled) {
|
||||
@@ -170,7 +173,8 @@ export class LoanProductSettingsStepComponent implements OnInit {
|
||||
'repaymentEvery': [true],
|
||||
'graceOnPrincipalAndInterestPayment': [true],
|
||||
'graceOnArrearsAgeing': [true]
|
||||
})
|
||||
}),
|
||||
'delinquencyBucketId': ['']
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -506,6 +506,8 @@
|
||||
<span fxFlex="60%">{{ loanProduct.allowAttributeOverrides.graceOnPrincipalAndInterestPayment ? 'Yes' : 'No' }}</span>
|
||||
<span fxFlex="40%">Number of days a loan may be overdue before moving into arrears:</span>
|
||||
<span fxFlex="60%">{{ loanProduct.allowAttributeOverrides.graceOnArrearsAgeing ? 'Yes' : 'No' }}</span>
|
||||
<span fxFlex="40%">Delinquency Bucket:</span>
|
||||
<span fxFlex="60%">{{ loanProduct.delinquencyBucket.id ? 'Yes' : 'No' }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill *ngIf="loanProduct.charges.length" fxLayout="row wrap" fxLayout.lt-md="column">
|
||||
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
<div class="container">
|
||||
|
||||
<mat-card>
|
||||
|
||||
<form [formGroup]="bucketForm" (ngSubmit)="submit()">
|
||||
|
||||
<mat-card-content>
|
||||
|
||||
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||
|
||||
<mat-form-field fxFlex="100%">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput required formControlName="name">
|
||||
<mat-error *ngIf="bucketForm.controls.name.hasError('required')">
|
||||
Name is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<h3 fxFlex="40%" class="mat-h3">Delinquency Ranges</h3>
|
||||
|
||||
<div fxFlex="40%" fxLayout="row" fxLayoutAlign="start center">
|
||||
<button type="button" mat-raised-button color="primary" (click)="addDelinquencyRange()">
|
||||
<fa-icon icon="plus"></fa-icon>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<table mat-table [dataSource]="rangesDataSource" [hidden]="rangesDataSource.length === 0">
|
||||
|
||||
<ng-container matColumnDef="classification">
|
||||
<th mat-header-cell *matHeaderCellDef> Classification </th>
|
||||
<td mat-cell *matCellDef="let row">
|
||||
{{ row.rangeId | find: delinquencyRangesData:'id':'classification'}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="minimumAgeDays">
|
||||
<th mat-header-cell *matHeaderCellDef> Days From </th>
|
||||
<td mat-cell *matCellDef="let row">
|
||||
{{ row.rangeId | find: delinquencyRangesData:'id':'minimumAgeDays'}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="maximumAgeDays">
|
||||
<th mat-header-cell *matHeaderCellDef> Days Till </th>
|
||||
<td mat-cell *matCellDef="let row">
|
||||
{{ row.rangeId | find: delinquencyRangesData:'id':'maximumAgeDays'}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
||||
<td mat-cell *matCellDef="let row; let rowIndex = index">
|
||||
<button type="button" mat-icon-button color="warn"
|
||||
(click)="deleteDelinquencyRange(rowIndex)" matTooltip="Delete"
|
||||
matTooltipPosition="left">
|
||||
<fa-icon icon="trash"></fa-icon>
|
||||
</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</mat-card-content>
|
||||
|
||||
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
||||
<button type="button" mat-raised-button [routerLink]="['../']">Cancel</button>
|
||||
<button mat-raised-button color="primary" [disabled]="!bucketForm.valid" *mifosxHasPermission="'CREATE_DELINQUENCY_BUCKET'">Submit</button>
|
||||
</mat-card-actions>
|
||||
|
||||
</form>
|
||||
|
||||
</mat-card>
|
||||
|
||||
</div>
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
.container {
|
||||
max-width: 37rem;
|
||||
|
||||
.content {
|
||||
div {
|
||||
margin: 0.8rem 0;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CreateBucketComponent } from './create-bucket.component';
|
||||
|
||||
describe('CreateBucketComponent', () => {
|
||||
let component: CreateBucketComponent;
|
||||
let fixture: ComponentFixture<CreateBucketComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ CreateBucketComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CreateBucketComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ProductsService } from 'app/products/products.service';
|
||||
import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
|
||||
import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component';
|
||||
import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base';
|
||||
import { SelectBase } from 'app/shared/form-dialog/formfield/model/select-base';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-create-bucket',
|
||||
templateUrl: './create-bucket.component.html',
|
||||
styleUrls: ['./create-bucket.component.scss']
|
||||
})
|
||||
export class CreateBucketComponent implements OnInit {
|
||||
/** Delinquency Bucket form. */
|
||||
bucketForm: FormGroup;
|
||||
/** Delinquency Bucket template data. */
|
||||
bucketTemplateData: any;
|
||||
/** Delinquency Range Data Source */
|
||||
rangesDataSource: {}[];
|
||||
/** Delinquency Range Options */
|
||||
delinquencyRangesData: any;
|
||||
delinquencyRangesIds: any;
|
||||
|
||||
/** Delinquency Range Displayed Columns */
|
||||
displayedColumns: string[] = ['classification', 'minimumAgeDays', 'maximumAgeDays', 'actions'];
|
||||
|
||||
constructor(private formBuilder: FormBuilder,
|
||||
private productsService: ProductsService,
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
public dialog: MatDialog) {
|
||||
this.route.data.subscribe((data: { delinquencyRanges: any }) => {
|
||||
this.delinquencyRangesData = data.delinquencyRanges;
|
||||
this.delinquencyRangesData = this.delinquencyRangesData.sort(
|
||||
(objA: { minimumAgeDays: number; }, objB: { minimumAgeDays: number; }) => objA.minimumAgeDays - objB.minimumAgeDays,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.setupForm();
|
||||
this.rangesDataSource = [];
|
||||
this.delinquencyRangesIds = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the Delinquency Bucket form
|
||||
*/
|
||||
setupForm(): void {
|
||||
this.bucketForm = this.formBuilder.group({
|
||||
'name': ['', Validators.required]
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Delinquency Range for a Delinquency Bucket
|
||||
*/
|
||||
addDelinquencyRange() {
|
||||
let delinquencyRanges = this.delinquencyRangesData;
|
||||
if (this.delinquencyRangesIds.length > 0) {
|
||||
delinquencyRanges = this.delinquencyRangesData.filter((item: any) => {
|
||||
return (this.delinquencyRangesIds.indexOf(item.id) < 0);
|
||||
});
|
||||
}
|
||||
const formfields: FormfieldBase[] = [
|
||||
new SelectBase({
|
||||
controlName: 'rangeId',
|
||||
label: 'Delinquency Range',
|
||||
options: { label: 'classification', value: 'id', data: delinquencyRanges },
|
||||
order: 1
|
||||
})
|
||||
];
|
||||
const data = {
|
||||
title: 'Add Delinquency Range',
|
||||
layout: { addButtonText: 'Add' },
|
||||
formfields: formfields
|
||||
};
|
||||
const rangeDialogRef = this.dialog.open(FormDialogComponent, { data });
|
||||
rangeDialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.data) {
|
||||
this.rangesDataSource = this.rangesDataSource.concat(response.data.value);
|
||||
this.delinquencyRangesIds.push(response.data.value.rangeId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete particular Delinquency Range in Delinquency Bucket
|
||||
*/
|
||||
deleteDelinquencyRange(index: number) {
|
||||
const dialogRef = this.dialog.open(DeleteDialogComponent, {
|
||||
data: { deleteContext: `this` }
|
||||
});
|
||||
dialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.delete) {
|
||||
this.delinquencyRangesIds.splice(index, 1);
|
||||
this.rangesDataSource.splice(index, 1);
|
||||
this.rangesDataSource = this.rangesDataSource.concat([]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the Delinquency Bucket form and creates the Delinquency Bucket,
|
||||
* if successful redirects to Delinquency Buckets.
|
||||
*/
|
||||
submit() {
|
||||
const ranges: any = [];
|
||||
this.rangesDataSource.forEach((item: any) => { ranges.push(item.rangeId); });
|
||||
if (ranges.length > 0) {
|
||||
const data = {
|
||||
...this.bucketForm.value,
|
||||
ranges: ranges
|
||||
};
|
||||
|
||||
this.productsService.createDelinquencyBucket(data).subscribe((response: any) => {
|
||||
this.router.navigate(['../', response.resourceId], { relativeTo: this.route });
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
<div class="container m-b-20" fxLayout="row" fxLayoutAlign="end" fxLayoutGap="20px">
|
||||
<button mat-raised-button color="primary" [routerLink]="['create']" *mifosxHasPermission="'CREATE_DELINQUENCY_BUCKET'">
|
||||
<fa-icon icon="plus"></fa-icon>
|
||||
Create Delinquency Bucket
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<div fxLayout="row">
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>Filter</mat-label>
|
||||
<input matInput (keyup)="applyFilter($event.target.value)">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="mat-elevation-z8">
|
||||
|
||||
<table mat-table [dataSource]="dataSource" matSort>
|
||||
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Name </th>
|
||||
<td mat-cell *matCellDef="let delinquencyBucket"> {{ delinquencyBucket.name }} </td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [routerLink]="[row.id]" class="select-row"></tr>
|
||||
|
||||
</table>
|
||||
|
||||
<mat-paginator [pageSizeOptions]="[10, 25, 50, 100]" showFirstLastButtons></mat-paginator>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/** Angular Imports */
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
|
||||
|
||||
/** rxjs Imports */
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
/** Custom Services */
|
||||
import { ProductsService } from '../../products.service';
|
||||
|
||||
/**
|
||||
* Delinquency Bucket Component data resolver.
|
||||
*/
|
||||
@Injectable()
|
||||
export class DelinquencyBucketComponentsResolver implements Resolve<Object> {
|
||||
|
||||
/**
|
||||
* @param {ProductsService} productsService Products service.
|
||||
*/
|
||||
constructor(private productsService: ProductsService) {}
|
||||
|
||||
/**
|
||||
* Returns the delinquency buckets data.
|
||||
* @returns {Observable<any>}
|
||||
*/
|
||||
resolve(route: ActivatedRouteSnapshot): Observable<any> {
|
||||
const delinquentcyBucketId = route.paramMap.get('bucketId');
|
||||
if (delinquentcyBucketId === null) {
|
||||
return this.productsService.getDelinquencyBuckets();
|
||||
} else {
|
||||
return this.productsService.getDelinquencyBucket(delinquentcyBucketId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
.container {
|
||||
.action-button {
|
||||
margin-left: auto;
|
||||
}
|
||||
.search-button {
|
||||
min-width: 30px;
|
||||
margin: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
tr.select-row:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
tr:nth-child(odd).td{
|
||||
color : black;
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DelinquencyBucketComponent } from './delinquency-bucket.component';
|
||||
|
||||
describe('DelinquencyBucketComponent', () => {
|
||||
let component: DelinquencyBucketComponent;
|
||||
let fixture: ComponentFixture<DelinquencyBucketComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ DelinquencyBucketComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(DelinquencyBucketComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { MatPaginator } from '@angular/material/paginator';
|
||||
import { MatSort } from '@angular/material/sort';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-delinquency-bucket',
|
||||
templateUrl: './delinquency-bucket.component.html',
|
||||
styleUrls: ['./delinquency-bucket.component.scss']
|
||||
})
|
||||
export class DelinquencyBucketComponent implements OnInit {
|
||||
|
||||
delinquencyBucketData: any;
|
||||
/** Columns to be displayed in delinquency bucket table. */
|
||||
displayedColumns: string[] = ['name'];
|
||||
/** Data source for delinquency bucket table. */
|
||||
dataSource: MatTableDataSource<any>;
|
||||
|
||||
/** Paginator for delinquency bucket table. */
|
||||
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
|
||||
/** Sorter for delinquency bucket table. */
|
||||
@ViewChild(MatSort, { static: true }) sort: MatSort;
|
||||
|
||||
constructor(private route: ActivatedRoute) {
|
||||
this.route.data.subscribe(( data: { delinquencyBuckets: any }) => {
|
||||
this.delinquencyBucketData = data.delinquencyBuckets;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.setDatasource();
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters data in delinquency bucket table based on passed value.
|
||||
* @param {string} filterValue Value to filter data.
|
||||
*/
|
||||
applyFilter(filterValue: string) {
|
||||
this.dataSource.filter = filterValue.trim().toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the data source, paginator and sorter for delinquency bucket table.
|
||||
*/
|
||||
setDatasource() {
|
||||
this.dataSource = new MatTableDataSource(this.delinquencyBucketData);
|
||||
this.dataSource.paginator = this.paginator;
|
||||
this.dataSource.sort = this.sort;
|
||||
}
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
<div class="container">
|
||||
|
||||
<mat-card>
|
||||
|
||||
<form [formGroup]="bucketForm" (ngSubmit)="submit()">
|
||||
|
||||
<mat-card-content>
|
||||
|
||||
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||
|
||||
<mat-form-field fxFlex="100%">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput required formControlName="name">
|
||||
<mat-error *ngIf="bucketForm.controls.name.hasError('required')">
|
||||
Name is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<h3 fxFlex="40%" class="mat-h3">Delinquency Ranges</h3>
|
||||
|
||||
<div fxFlex="40%" fxLayout="row" fxLayoutAlign="start center">
|
||||
<button type="button" mat-raised-button color="primary" (click)="addDelinquencyRange()">
|
||||
<fa-icon icon="plus"></fa-icon>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<table mat-table [dataSource]="rangesDataSource" [hidden]="rangesDataSource.length === 0">
|
||||
|
||||
<ng-container matColumnDef="classification">
|
||||
<th mat-header-cell *matHeaderCellDef> Classification </th>
|
||||
<td mat-cell *matCellDef="let row"> {{ row.classification }}</td>
|
||||
<td mat-cell *matCellDef="let row">
|
||||
{{ row.rangeId | find: delinquencyRangesData:'id':'classification'}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="minimumAgeDays">
|
||||
<th mat-header-cell *matHeaderCellDef> Days From </th>
|
||||
<td mat-cell *matCellDef="let row"> {{ row.minimumAgeDays }}</td>
|
||||
<td mat-cell *matCellDef="let row">
|
||||
{{ row.rangeId | find: delinquencyRangesData:'id':'minimumAgeDays'}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="maximumAgeDays">
|
||||
<th mat-header-cell *matHeaderCellDef> Days Till </th>
|
||||
<td mat-cell *matCellDef="let row"> {{ row.maximumAgeDays }}</td>
|
||||
<td mat-cell *matCellDef="let row">
|
||||
{{ row.rangeId | find: delinquencyRangesData:'id':'maximumAgeDays'}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
||||
<td mat-cell *matCellDef="let row; let rowIndex = index">
|
||||
<button type="button" mat-icon-button color="warn"
|
||||
(click)="deleteDelinquencyRange(rowIndex)" matTooltip="Delete"
|
||||
matTooltipPosition="left">
|
||||
<fa-icon icon="trash"></fa-icon>
|
||||
</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</mat-card-content>
|
||||
|
||||
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
||||
<button type="button" mat-raised-button [routerLink]="['../']">Cancel</button>
|
||||
<button mat-raised-button color="primary" [disabled]="!dataWasChanged" *mifosxHasPermission="'UPDATE_DELINQUENCY_BUCKET'">Submit</button>
|
||||
</mat-card-actions>
|
||||
|
||||
</form>
|
||||
|
||||
</mat-card>
|
||||
|
||||
</div>
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
.container {
|
||||
max-width: 37rem;
|
||||
|
||||
.content {
|
||||
div {
|
||||
margin: 0.8rem 0;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { EditBucketComponent } from './edit-bucket.component';
|
||||
|
||||
describe('EditBucketComponent', () => {
|
||||
let component: EditBucketComponent;
|
||||
let fixture: ComponentFixture<EditBucketComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ EditBucketComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(EditBucketComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ProductsService } from 'app/products/products.service';
|
||||
import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
|
||||
import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component';
|
||||
import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base';
|
||||
import { SelectBase } from 'app/shared/form-dialog/formfield/model/select-base';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-edit-bucket',
|
||||
templateUrl: './edit-bucket.component.html',
|
||||
styleUrls: ['./edit-bucket.component.scss']
|
||||
})
|
||||
export class EditBucketComponent implements OnInit {
|
||||
/** Delinquency Bucket form. */
|
||||
bucketForm: FormGroup;
|
||||
/** Delinquency Bucket template data. */
|
||||
bucketTemplateData: any;
|
||||
/** Delinquency Range Data Source */
|
||||
rangesDataSource: {}[];
|
||||
/** Delinquency Range Options */
|
||||
delinquencyRangesData: any;
|
||||
/** Delinquency Bucket data */
|
||||
delinquencyBucketData: any;
|
||||
delinquencyRangesIds: any;
|
||||
/** Delinquency Bucket Id */
|
||||
delinquencyBucketId: any;
|
||||
/** Data was changed */
|
||||
dataWasChanged = false;
|
||||
|
||||
/** Delinquency Range Displayed Columns */
|
||||
displayedColumns: string[] = ['classification', 'minimumAgeDays', 'maximumAgeDays', 'actions'];
|
||||
|
||||
constructor(private formBuilder: FormBuilder,
|
||||
private productsService: ProductsService,
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
public dialog: MatDialog) {
|
||||
this.route.data.subscribe((data: { delinquencyBucket: any, delinquencyRanges: any }) => {
|
||||
this.delinquencyRangesData = data.delinquencyRanges;
|
||||
this.rangesDataSource = [];
|
||||
this.delinquencyRangesIds = [];
|
||||
this.delinquencyRangesData = this.delinquencyRangesData.sort(
|
||||
(objA: { minimumAgeDays: number; }, objB: { minimumAgeDays: number; }) => objA.minimumAgeDays - objB.minimumAgeDays,
|
||||
);
|
||||
this.delinquencyBucketData = data.delinquencyBucket;
|
||||
this.delinquencyBucketId = data.delinquencyBucket.id;
|
||||
this.rangesDataSource = this.delinquencyBucketData.ranges;
|
||||
this.rangesDataSource.forEach((item: any) => {
|
||||
this.delinquencyRangesIds.push(item.id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.setupForm();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the Delinquency Bucket form
|
||||
*/
|
||||
setupForm(): void {
|
||||
this.bucketForm = this.formBuilder.group({
|
||||
'name': [{value: this.delinquencyBucketData.name, disabled: true}, Validators.required]
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Delinquency Range for a Delinquency Bucket
|
||||
*/
|
||||
addDelinquencyRange() {
|
||||
let delinquencyRanges = this.delinquencyRangesData;
|
||||
if (this.delinquencyRangesIds.length > 0) {
|
||||
delinquencyRanges = this.delinquencyRangesData.filter((item: any) => {
|
||||
return (this.delinquencyRangesIds.indexOf(item.id) < 0);
|
||||
});
|
||||
}
|
||||
const formfields: FormfieldBase[] = [
|
||||
new SelectBase({
|
||||
controlName: 'rangeId',
|
||||
label: 'Delinquency Range',
|
||||
options: { label: 'classification', value: 'id', data: delinquencyRanges },
|
||||
order: 1
|
||||
})
|
||||
];
|
||||
const data = {
|
||||
title: 'Add Delinquency Range',
|
||||
layout: { addButtonText: 'Add' },
|
||||
formfields: formfields
|
||||
};
|
||||
const rangeDialogRef = this.dialog.open(FormDialogComponent, { data });
|
||||
rangeDialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.data) {
|
||||
const item = response.data.value;
|
||||
item.id = item.rangeId;
|
||||
this.rangesDataSource = this.rangesDataSource.concat(item);
|
||||
this.delinquencyRangesIds.push(item.id);
|
||||
this.dataWasChanged = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete particular Delinquency Range in Delinquency Bucket
|
||||
*/
|
||||
deleteDelinquencyRange(index: number) {
|
||||
const dialogRef = this.dialog.open(DeleteDialogComponent, {
|
||||
data: { deleteContext: `this` }
|
||||
});
|
||||
dialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.delete) {
|
||||
this.delinquencyRangesIds.splice(index, 1);
|
||||
this.rangesDataSource.splice(index, 1);
|
||||
this.rangesDataSource = this.rangesDataSource.concat([]);
|
||||
this.dataWasChanged = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the Delinquency Bucket form and creates the Delinquency Bucket,
|
||||
* if successful redirects to Delinquency Buckets.
|
||||
*/
|
||||
submit() {
|
||||
const ranges: any = [];
|
||||
this.rangesDataSource.forEach((item: any) => { ranges.push(item.id); });
|
||||
if (ranges.length > 0) {
|
||||
const data = {
|
||||
...this.bucketForm.value,
|
||||
ranges: ranges
|
||||
};
|
||||
|
||||
this.productsService.updateDelinquencyBucket(this.delinquencyBucketId, data).subscribe(() => {
|
||||
this.router.navigate(['../'], { relativeTo: this.route });
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
<div class="container m-b-20" fxLayout="row" fxLayout.lt-md="column" fxLayoutAlign="end" fxLayoutGap="2%">
|
||||
<button mat-raised-button color="primary" [routerLink]="['edit']" *mifosxHasPermission="'UPDATE_DELINQUENCY_BUCKET'">
|
||||
<fa-icon icon="edit"></fa-icon>
|
||||
Edit
|
||||
</button>
|
||||
<button mat-raised-button color="warn" (click)="deleteDelinquencyBucket()" *mifosxHasPermission="'DELETE_DELINQUENCY_BUCKET'">
|
||||
<fa-icon icon="trash"></fa-icon>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<mat-card>
|
||||
|
||||
<mat-card-content>
|
||||
|
||||
<div fxLayout="row wrap" class="content">
|
||||
|
||||
<div fxFlex="50%" class="mat-body-strong">
|
||||
Name
|
||||
</div>
|
||||
|
||||
<div fxFlex="50%">
|
||||
{{ delinquencyBucketData.name }}
|
||||
</div>
|
||||
|
||||
<div fxFlex="50%" class="mat-body-strong">
|
||||
Classification Name
|
||||
</div>
|
||||
|
||||
<div fxFlex="25%" class="mat-body-strong">
|
||||
Days From
|
||||
</div>
|
||||
|
||||
<div fxFlex="25%" class="mat-body-strong">
|
||||
Days Till
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div fxLayout="row wrap" class="content" *ngFor="let range of delinquencyBucketData.ranges">
|
||||
|
||||
<div fxFlex="50%">
|
||||
{{ range.classification }}
|
||||
</div>
|
||||
|
||||
<div fxFlex="25%">
|
||||
{{ range.minimumAgeDays }}
|
||||
</div>
|
||||
|
||||
<div fxFlex="25%">
|
||||
{{ range.maximumAgeDays }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</mat-card-content>
|
||||
|
||||
</mat-card>
|
||||
|
||||
</div>
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
.container {
|
||||
max-width: 37rem;
|
||||
|
||||
.content {
|
||||
div {
|
||||
margin: 0.8rem 0;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ViewBucketComponent } from './view-bucket.component';
|
||||
|
||||
describe('ViewBucketComponent', () => {
|
||||
let component: ViewBucketComponent;
|
||||
let fixture: ComponentFixture<ViewBucketComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ViewBucketComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ViewBucketComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ProductsService } from 'app/products/products.service';
|
||||
import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-view-bucket',
|
||||
templateUrl: './view-bucket.component.html',
|
||||
styleUrls: ['./view-bucket.component.scss']
|
||||
})
|
||||
export class ViewBucketComponent implements OnInit {
|
||||
|
||||
/** Delinquency Bucket Data. */
|
||||
delinquencyBucketData: any;
|
||||
|
||||
constructor(private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private dialog: MatDialog,
|
||||
private productsService: ProductsService) {
|
||||
this.route.data.subscribe((data: { delinquencyBucket: any }) => {
|
||||
this.delinquencyBucketData = data.delinquencyBucket;
|
||||
this.delinquencyBucketData.ranges = this.delinquencyBucketData.ranges.sort(
|
||||
(objA: { minimumAge: number; }, objB: { minimumAge: number; }) => objA.minimumAge - objB.minimumAge,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
deleteDelinquencyBucket() {
|
||||
const dialogRef = this.dialog.open(DeleteDialogComponent, {
|
||||
data: { deleteContext: this.delinquencyBucketData.name }
|
||||
});
|
||||
dialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.delete) {
|
||||
this.productsService.deleteDelinquencyBucket(this.delinquencyBucketData.id).subscribe(() => {
|
||||
this.router.navigate(['../'], { relativeTo: this.route });
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
<div class="container">
|
||||
|
||||
<mat-card>
|
||||
|
||||
<form [formGroup]="delinquencyRangeForm" (ngSubmit)="submit()">
|
||||
|
||||
<mat-card-content>
|
||||
|
||||
<div fxLayout="column">
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Classification</mat-label>
|
||||
<input matInput required formControlName="classification">
|
||||
<mat-error *ngIf="delinquencyRangeForm.controls.classification.hasError('required')">
|
||||
Classification is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Days From</mat-label>
|
||||
<input matInput type="number" required formControlName="minimumAgeDays">
|
||||
<mat-error *ngIf="delinquencyRangeForm.controls.minimumAgeDays.hasError('required')">
|
||||
Days From is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Days Till</mat-label>
|
||||
<input matInput type="number" formControlName="maximumAgeDays">
|
||||
</mat-form-field>
|
||||
|
||||
</div>
|
||||
|
||||
</mat-card-content>
|
||||
|
||||
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
||||
<button type="button" mat-raised-button [routerLink]="['../']">Cancel</button>
|
||||
<button mat-raised-button color="primary" [disabled]="!delinquencyRangeForm.valid" *mifosxHasPermission="'CREATE_DELINQUENCY_RANGE'">Submit</button>
|
||||
</mat-card-actions>
|
||||
|
||||
</form>
|
||||
|
||||
</mat-card>
|
||||
|
||||
</div>
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
.container {
|
||||
max-width: 37rem;
|
||||
|
||||
.content {
|
||||
div {
|
||||
margin: 0.8rem 0;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CreateRangeComponent } from './create-range.component';
|
||||
|
||||
describe('CreateRangeComponent', () => {
|
||||
let component: CreateRangeComponent;
|
||||
let fixture: ComponentFixture<CreateRangeComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ CreateRangeComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CreateRangeComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ProductsService } from 'app/products/products.service';
|
||||
import { SettingsService } from 'app/settings/settings.service';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-create-range',
|
||||
templateUrl: './create-range.component.html',
|
||||
styleUrls: ['./create-range.component.scss']
|
||||
})
|
||||
export class CreateRangeComponent implements OnInit {
|
||||
|
||||
/** Delinquency Range form. */
|
||||
delinquencyRangeForm: FormGroup;
|
||||
|
||||
constructor(private formBuilder: FormBuilder,
|
||||
private productsService: ProductsService,
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private settingsService: SettingsService) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.setInputForm();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Input form.
|
||||
*/
|
||||
setInputForm(): void {
|
||||
this.delinquencyRangeForm = this.formBuilder.group({
|
||||
'classification': ['', [Validators.required]],
|
||||
'minimumAgeDays': [0, [Validators.required, Validators.pattern('^(0*[1-9][0-9]*?)$'), Validators.max(1000)]],
|
||||
'maximumAgeDays': ['', [Validators.pattern('^(0*[1-9][0-9]*?)$'), Validators.max(10000)]],
|
||||
});
|
||||
}
|
||||
|
||||
submit(): void {
|
||||
const delinquencyRangeFormData = this.delinquencyRangeForm.value;
|
||||
const locale = this.settingsService.language.code;
|
||||
const data = {
|
||||
...delinquencyRangeFormData,
|
||||
locale
|
||||
};
|
||||
this.productsService.createDelinquencyRange(data).subscribe((response: any) => {
|
||||
this.router.navigate(['../', response.resourceId], { relativeTo: this.route });
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
<div class="container m-b-20" fxLayout="row" fxLayoutAlign="end" fxLayoutGap="20px">
|
||||
<button mat-raised-button color="primary" [routerLink]="['create']" *mifosxHasPermission="'CREATE_DELINQUENCY_RANGE'">
|
||||
<fa-icon icon="plus"></fa-icon>
|
||||
Create Delinquency Range
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<div fxLayout="row">
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>Filter</mat-label>
|
||||
<input matInput (keyup)="applyFilter($event.target.value)">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="mat-elevation-z8">
|
||||
|
||||
<table mat-table [dataSource]="dataSource" matSort>
|
||||
|
||||
<ng-container matColumnDef="classification">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header="classification"> Classification </th>
|
||||
<td mat-cell *matCellDef="let delinquencyRange"> {{ delinquencyRange.classification }} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="minimumAgeDays">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header="minimumAgeDays"> Days From </th>
|
||||
<td mat-cell *matCellDef="let delinquencyRange"> {{ delinquencyRange.minimumAgeDays }} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="maximumAgeDays">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header="maximumAgeDays"> Days Till </th>
|
||||
<td mat-cell *matCellDef="let delinquencyRange"> {{ delinquencyRange.maximumAgeDays }} </td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [routerLink]="[row.id]" class="select-row"></tr>
|
||||
|
||||
</table>
|
||||
|
||||
<mat-paginator [pageSizeOptions]="[10, 25, 50, 100]" showFirstLastButtons></mat-paginator>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/** Angular Imports */
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
|
||||
|
||||
/** rxjs Imports */
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
/** Custom Services */
|
||||
import { ProductsService } from '../../products.service';
|
||||
|
||||
/**
|
||||
* Delinquency Range Component data resolver.
|
||||
*/
|
||||
@Injectable()
|
||||
export class DelinquencyRangeComponentsResolver implements Resolve<Object> {
|
||||
|
||||
/**
|
||||
* @param {ProductsService} productsService Products service.
|
||||
*/
|
||||
constructor(private productsService: ProductsService) {}
|
||||
|
||||
/**
|
||||
* Returns the delinquency ranges data.
|
||||
* @returns {Observable<any>}
|
||||
*/
|
||||
resolve(route: ActivatedRouteSnapshot): Observable<any> {
|
||||
const delinquentcyRangeId = route.paramMap.get('rangeId');
|
||||
if (delinquentcyRangeId === null) {
|
||||
return this.productsService.getDelinquencyRanges();
|
||||
} else {
|
||||
return this.productsService.getDelinquencyRange(delinquentcyRangeId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
.container {
|
||||
.action-button {
|
||||
margin-left: auto;
|
||||
}
|
||||
.search-button {
|
||||
min-width: 30px;
|
||||
margin: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
tr.select-row:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
tr:nth-child(odd).td{
|
||||
color : black;
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DelinquencyRangeComponent } from './delinquency-range.component';
|
||||
|
||||
describe('DelinquencyRangeComponent', () => {
|
||||
let component: DelinquencyRangeComponent;
|
||||
let fixture: ComponentFixture<DelinquencyRangeComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ DelinquencyRangeComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(DelinquencyRangeComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { MatPaginator } from '@angular/material/paginator';
|
||||
import { MatSort } from '@angular/material/sort';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-delinquency-range',
|
||||
templateUrl: './delinquency-range.component.html',
|
||||
styleUrls: ['./delinquency-range.component.scss']
|
||||
})
|
||||
export class DelinquencyRangeComponent implements OnInit {
|
||||
|
||||
delinquencyRangeData: any;
|
||||
/** Columns to be displayed in delinquency range table. */
|
||||
displayedColumns: string[] = ['classification', 'minimumAgeDays', 'maximumAgeDays'];
|
||||
/** Data source for delinquency range table. */
|
||||
dataSource: MatTableDataSource<any>;
|
||||
|
||||
/** Paginator for delinquency range table. */
|
||||
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
|
||||
/** Sorter for delinquency range table. */
|
||||
@ViewChild(MatSort, { static: true }) sort: MatSort;
|
||||
|
||||
constructor(private route: ActivatedRoute) {
|
||||
this.route.data.subscribe(( data: { delinquencyRanges: any }) => {
|
||||
this.delinquencyRangeData = data.delinquencyRanges;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.setDatasource();
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters data in delinquency range table based on passed value.
|
||||
* @param {string} filterValue Value to filter data.
|
||||
*/
|
||||
applyFilter(filterValue: string) {
|
||||
this.dataSource.filter = filterValue.trim().toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the data source, paginator and sorter for delinquency range table.
|
||||
*/
|
||||
setDatasource() {
|
||||
this.dataSource = new MatTableDataSource(this.delinquencyRangeData);
|
||||
this.dataSource.paginator = this.paginator;
|
||||
this.dataSource.sort = this.sort;
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
<div class="container">
|
||||
|
||||
<mat-card>
|
||||
|
||||
<form [formGroup]="delinquencyRangeForm" (ngSubmit)="submit()">
|
||||
|
||||
<mat-card-content>
|
||||
|
||||
<div fxLayout="column">
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Classification</mat-label>
|
||||
<input matInput required formControlName="classification">
|
||||
<mat-error *ngIf="delinquencyRangeForm.controls.classification.hasError('required')">
|
||||
Classification is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Days From</mat-label>
|
||||
<input matInput type="number" required formControlName="minimumAgeDays">
|
||||
<mat-error *ngIf="delinquencyRangeForm.controls.minimumAgeDays.hasError('required')">
|
||||
Days From is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Days Till</mat-label>
|
||||
<input matInput type="number" formControlName="maximumAgeDays">
|
||||
</mat-form-field>
|
||||
|
||||
</div>
|
||||
|
||||
</mat-card-content>
|
||||
|
||||
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
|
||||
<button type="button" mat-raised-button [routerLink]="['../']">Cancel</button>
|
||||
<button mat-raised-button color="primary" [disabled]="!delinquencyRangeForm.valid" *mifosxHasPermission="'UPDATE_DELINQUENCY_RANGE'">Submit</button>
|
||||
</mat-card-actions>
|
||||
|
||||
</form>
|
||||
|
||||
</mat-card>
|
||||
|
||||
</div>
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
.container {
|
||||
max-width: 37rem;
|
||||
|
||||
.content {
|
||||
div {
|
||||
margin: 0.8rem 0;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { EditRangeComponent } from './edit-range.component';
|
||||
|
||||
describe('EditRangeComponent', () => {
|
||||
let component: EditRangeComponent;
|
||||
let fixture: ComponentFixture<EditRangeComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ EditRangeComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(EditRangeComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ProductsService } from 'app/products/products.service';
|
||||
import { SettingsService } from 'app/settings/settings.service';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-edit-range',
|
||||
templateUrl: './edit-range.component.html',
|
||||
styleUrls: ['./edit-range.component.scss']
|
||||
})
|
||||
export class EditRangeComponent implements OnInit {
|
||||
|
||||
/** Delinquency Range Data. */
|
||||
delinquencyRangeData: any;
|
||||
/** Delinquency Range form. */
|
||||
delinquencyRangeForm: FormGroup;
|
||||
|
||||
constructor(private formBuilder: FormBuilder,
|
||||
private productsService: ProductsService,
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private settingsService: SettingsService) {
|
||||
this.route.data.subscribe((data: { delinquencyRange: any }) => {
|
||||
this.delinquencyRangeData = data.delinquencyRange;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.setInputForm();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Input form.
|
||||
*/
|
||||
setInputForm(): void {
|
||||
this.delinquencyRangeForm = this.formBuilder.group({
|
||||
'classification': [this.delinquencyRangeData.classification, [Validators.required]],
|
||||
'minimumAgeDays': [this.delinquencyRangeData.minimumAgeDays, [Validators.required, Validators.pattern('^(0*[1-9][0-9]*?)$'), Validators.max(1000)]],
|
||||
'maximumAgeDays': [this.delinquencyRangeData.maximumAgeDays, [Validators.pattern('^(0*[1-9][0-9]*?)$'), Validators.max(10000)]],
|
||||
});
|
||||
}
|
||||
|
||||
submit(): void {
|
||||
const delinquencyRangeFormData = this.delinquencyRangeForm.value;
|
||||
const locale = this.settingsService.language.code;
|
||||
const data = {
|
||||
...delinquencyRangeFormData,
|
||||
locale
|
||||
};
|
||||
this.productsService.updateDelinquencyRange(this.delinquencyRangeData.id, data).subscribe((response: any) => {
|
||||
this.router.navigate(['../../', response.resourceId], { relativeTo: this.route });
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
<div class="container m-b-20" fxLayout="row" fxLayout.lt-md="column" fxLayoutAlign="end" fxLayoutGap="2%">
|
||||
<button mat-raised-button color="primary" [routerLink]="['edit']" *mifosxHasPermission="'UPDATE_DELINQUENCY_RANGE'">
|
||||
<fa-icon icon="edit"></fa-icon>
|
||||
Edit
|
||||
</button>
|
||||
<button mat-raised-button color="warn" (click)="deleteDelinquencyRange()" *mifosxHasPermission="'DELETE_DELINQUENCY_RANGE'">
|
||||
<fa-icon icon="trash"></fa-icon>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<mat-card>
|
||||
|
||||
<mat-card-content>
|
||||
|
||||
<div fxLayout="row wrap" class="content">
|
||||
|
||||
<div fxFlex="50%" class="mat-body-strong">
|
||||
Classification
|
||||
</div>
|
||||
|
||||
<div fxFlex="50%">
|
||||
{{ delinquencyRangeData.classification }}
|
||||
</div>
|
||||
|
||||
<div fxFlex="50%" class="mat-body-strong">
|
||||
Days From
|
||||
</div>
|
||||
|
||||
<div fxFlex="50%">
|
||||
{{ delinquencyRangeData.minimumAgeDays }}
|
||||
</div>
|
||||
|
||||
<div fxFlex="50%" class="mat-body-strong">
|
||||
Days Till
|
||||
</div>
|
||||
|
||||
<div fxFlex="50%">
|
||||
{{ delinquencyRangeData.maximumAgeDays }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</mat-card-content>
|
||||
|
||||
</mat-card>
|
||||
|
||||
</div>
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
.container {
|
||||
max-width: 37rem;
|
||||
|
||||
.content {
|
||||
div {
|
||||
margin: 0.8rem 0;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ViewRangeComponent } from './view-range.component';
|
||||
|
||||
describe('ViewRangeComponent', () => {
|
||||
let component: ViewRangeComponent;
|
||||
let fixture: ComponentFixture<ViewRangeComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ViewRangeComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ViewRangeComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ProductsService } from 'app/products/products.service';
|
||||
import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-view-range',
|
||||
templateUrl: './view-range.component.html',
|
||||
styleUrls: ['./view-range.component.scss']
|
||||
})
|
||||
export class ViewRangeComponent implements OnInit {
|
||||
|
||||
/** Delinquency Range Data. */
|
||||
delinquencyRangeData: any;
|
||||
|
||||
constructor(private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private dialog: MatDialog,
|
||||
private productsService: ProductsService) {
|
||||
this.route.data.subscribe((data: { delinquencyRange: any }) => {
|
||||
this.delinquencyRangeData = data.delinquencyRange;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
deleteDelinquencyRange() {
|
||||
const dialogRef = this.dialog.open(DeleteDialogComponent, {
|
||||
data: { deleteContext: this.delinquencyRangeData.classification }
|
||||
});
|
||||
dialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.delete) {
|
||||
this.productsService.deleteDelinquencyRange(this.delinquencyRangeData.id).subscribe(() => {
|
||||
this.router.navigate(['../'], { relativeTo: this.route });
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<div class="container">
|
||||
|
||||
<mat-card>
|
||||
|
||||
<div fxLayout="row" fxLayout.lt-md="column">
|
||||
|
||||
<div fxFlex="50%">
|
||||
|
||||
<mat-nav-list>
|
||||
|
||||
<mat-list-item [routerLink]="['ranges']" *mifosxHasPermission="'READ_DELINQUENCY_RANGE'">
|
||||
<mat-icon matListIcon>
|
||||
<fa-icon icon="building" size="sm"></fa-icon>
|
||||
</mat-icon>
|
||||
<h4 matLine>Manage Delinquency Ranges</h4>
|
||||
<p matLine>Define delinquency day ranges</p>
|
||||
</mat-list-item>
|
||||
|
||||
</mat-nav-list>
|
||||
|
||||
</div>
|
||||
|
||||
<div fxFlex="50%">
|
||||
|
||||
<mat-nav-list>
|
||||
|
||||
<mat-list-item [routerLink]="['buckets']" *mifosxHasPermission="'READ_DELINQUENCY_BUCKET'">
|
||||
<mat-icon matListIcon>
|
||||
<fa-icon icon="building" size="sm"></fa-icon>
|
||||
</mat-icon>
|
||||
<h4 matLine>Manage Delinquency Buckets</h4>
|
||||
<p matLine>Define delinquency bucket as set of ranges</p>
|
||||
</mat-list-item>
|
||||
|
||||
</mat-nav-list>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</mat-card>
|
||||
|
||||
</div>
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ManageDelinquencyBucketsComponent } from './manage-delinquency-buckets.component';
|
||||
|
||||
describe('ManageDelinquencyBucketsComponent', () => {
|
||||
let component: ManageDelinquencyBucketsComponent;
|
||||
let fixture: ComponentFixture<ManageDelinquencyBucketsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ManageDelinquencyBucketsComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ManageDelinquencyBucketsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-manage-delinquency-buckets',
|
||||
templateUrl: './manage-delinquency-buckets.component.html',
|
||||
styleUrls: ['./manage-delinquency-buckets.component.scss']
|
||||
})
|
||||
export class ManageDelinquencyBucketsComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -101,6 +101,17 @@ import { FixedDepositProductAndTemplateResolver } from './fixed-deposit-products
|
||||
import { CollateralResolver } from './collaterals/collateral.resolver';
|
||||
import { CollateralsResolver } from './collaterals/collaterals.resolver';
|
||||
import { CollateralTemplateResolver } from './collaterals/collaterals-template.resolver';
|
||||
import { ManageDelinquencyBucketsComponent } from './manage-delinquency-buckets/manage-delinquency-buckets.component';
|
||||
import { DelinquencyBucketComponent } from './manage-delinquency-buckets/delinquency-bucket/delinquency-bucket.component';
|
||||
import { DelinquencyRangeComponent } from './manage-delinquency-buckets/delinquency-range/delinquency-range.component';
|
||||
import { DelinquencyBucketComponentsResolver } from './manage-delinquency-buckets/delinquency-bucket/delinquency-bucket.component.resolver';
|
||||
import { DelinquencyRangeComponentsResolver } from './manage-delinquency-buckets/delinquency-range/delinquency-range.component.resolver';
|
||||
import { ViewRangeComponent } from './manage-delinquency-buckets/delinquency-range/view-range/view-range.component';
|
||||
import { EditRangeComponent } from './manage-delinquency-buckets/delinquency-range/edit-range/edit-range.component';
|
||||
import { CreateRangeComponent } from './manage-delinquency-buckets/delinquency-range/create-range/create-range.component';
|
||||
import { CreateBucketComponent } from './manage-delinquency-buckets/delinquency-bucket/create-bucket/create-bucket.component';
|
||||
import { EditBucketComponent } from './manage-delinquency-buckets/delinquency-bucket/edit-bucket/edit-bucket.component';
|
||||
import { ViewBucketComponent } from './manage-delinquency-buckets/delinquency-bucket/view-bucket/view-bucket.component';
|
||||
|
||||
/** Products Routes */
|
||||
const routes: Routes = [
|
||||
@@ -377,6 +388,104 @@ const routes: Routes = [
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'delinquency-bucket-configurations',
|
||||
data: { title: extract('Manage Delinquency Bucket Configurations'), breadcrumb: 'Manage Delinquency Bucket Configurations' },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: ManageDelinquencyBucketsComponent,
|
||||
},
|
||||
{
|
||||
path: 'ranges',
|
||||
data: { title: extract('Manage Delinquency Ranges'), breadcrumb: 'Delinquency Ranges'},
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: DelinquencyRangeComponent,
|
||||
resolve: {
|
||||
delinquencyRanges: DelinquencyRangeComponentsResolver
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
component: CreateRangeComponent,
|
||||
data: { title: extract('Create Delinquency Range'), breadcrumb: 'Create' }
|
||||
},
|
||||
{
|
||||
path: ':rangeId',
|
||||
data: { title: extract('View Delinquency Range'), routeParamBreadcrumb: 'id' },
|
||||
resolve: {
|
||||
delinquencyRange: DelinquencyRangeComponentsResolver
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: ViewRangeComponent,
|
||||
resolve: {
|
||||
delinquencyRange: DelinquencyRangeComponentsResolver
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'edit',
|
||||
data: { title: extract('Edit Delinquency Range'), breadcrumb: 'Edit', routeParamBreadcrumb: false },
|
||||
component: EditRangeComponent,
|
||||
resolve: {
|
||||
delinquencyRange: DelinquencyRangeComponentsResolver
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'buckets',
|
||||
data: { title: extract('Manage Delinquency Bucket'), breadcrumb: 'Delinquency Buckets'},
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: DelinquencyBucketComponent,
|
||||
resolve: {
|
||||
delinquencyBuckets: DelinquencyBucketComponentsResolver
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
component: CreateBucketComponent,
|
||||
data: { title: extract('Create Delinquency Bucket'), breadcrumb: 'Create' },
|
||||
resolve: {
|
||||
delinquencyRanges: DelinquencyRangeComponentsResolver
|
||||
}
|
||||
},
|
||||
{
|
||||
path: ':bucketId',
|
||||
data: { title: extract('View Delinquency Bucket'), routeParamBreadcrumb: 'id' },
|
||||
resolve: {
|
||||
delinquencyBucket: DelinquencyBucketComponentsResolver
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: ViewBucketComponent,
|
||||
resolve: {
|
||||
delinquencyBucket: DelinquencyBucketComponentsResolver
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'edit',
|
||||
data: { title: extract('Edit Delinquency Bucket'), breadcrumb: 'Edit', routeParamBreadcrumb: false },
|
||||
component: EditBucketComponent,
|
||||
resolve: {
|
||||
delinquencyBucket: DelinquencyBucketComponentsResolver,
|
||||
delinquencyRanges: DelinquencyRangeComponentsResolver
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'recurring-deposit-products',
|
||||
data: { title: extract('Recurring Deposit Products'), breadcrumb: 'Recurring Deposit Products' },
|
||||
@@ -703,7 +812,9 @@ const routes: Routes = [
|
||||
FloatingRatesResolver,
|
||||
CollateralResolver,
|
||||
CollateralsResolver,
|
||||
CollateralTemplateResolver
|
||||
CollateralTemplateResolver,
|
||||
DelinquencyRangeComponentsResolver,
|
||||
DelinquencyBucketComponentsResolver
|
||||
]
|
||||
})
|
||||
export class ProductsRoutingModule { }
|
||||
|
||||
@@ -48,6 +48,14 @@
|
||||
<p matLine>Define collaterals for Collateral Management</p>
|
||||
</mat-list-item>
|
||||
|
||||
<mat-list-item [routerLink]="['delinquency-bucket-configurations']" *mifosxHasPermission="'READ_DELINQUENCY_BUCKET'">
|
||||
<mat-icon matListIcon>
|
||||
<fa-icon icon="briefcase" size="sm"></fa-icon>
|
||||
</mat-icon>
|
||||
<h4 matLine>Delinquency Buckets</h4>
|
||||
<p matLine>Define delinquency day ranges and bucket set for loan products</p>
|
||||
</mat-list-item>
|
||||
|
||||
</mat-nav-list>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -97,6 +97,15 @@ import { CollateralsComponent } from './collaterals/collaterals.component';
|
||||
import { CreateCollateralComponent } from './collaterals/create-collateral/create-collateral.component';
|
||||
import { EditCollateralComponent } from './collaterals/edit-collateral/edit-collateral.component';
|
||||
import { ViewCollateralComponent } from './collaterals/view-collateral/view-collateral.component';
|
||||
import { ManageDelinquencyBucketsComponent } from './manage-delinquency-buckets/manage-delinquency-buckets.component';
|
||||
import { DelinquencyBucketComponent } from './manage-delinquency-buckets/delinquency-bucket/delinquency-bucket.component';
|
||||
import { DelinquencyRangeComponent } from './manage-delinquency-buckets/delinquency-range/delinquency-range.component';
|
||||
import { CreateRangeComponent } from './manage-delinquency-buckets/delinquency-range/create-range/create-range.component';
|
||||
import { ViewRangeComponent } from './manage-delinquency-buckets/delinquency-range/view-range/view-range.component';
|
||||
import { EditRangeComponent } from './manage-delinquency-buckets/delinquency-range/edit-range/edit-range.component';
|
||||
import { ViewBucketComponent } from './manage-delinquency-buckets/delinquency-bucket/view-bucket/view-bucket.component';
|
||||
import { CreateBucketComponent } from './manage-delinquency-buckets/delinquency-bucket/create-bucket/create-bucket.component';
|
||||
import { EditBucketComponent } from './manage-delinquency-buckets/delinquency-bucket/edit-bucket/edit-bucket.component';
|
||||
|
||||
/**
|
||||
* Products Module
|
||||
@@ -201,7 +210,16 @@ import { ViewCollateralComponent } from './collaterals/view-collateral/view-coll
|
||||
CollateralsComponent,
|
||||
CreateCollateralComponent,
|
||||
EditCollateralComponent,
|
||||
ViewCollateralComponent
|
||||
ViewCollateralComponent,
|
||||
ManageDelinquencyBucketsComponent,
|
||||
DelinquencyBucketComponent,
|
||||
DelinquencyRangeComponent,
|
||||
CreateRangeComponent,
|
||||
ViewRangeComponent,
|
||||
EditRangeComponent,
|
||||
ViewBucketComponent,
|
||||
CreateBucketComponent,
|
||||
EditBucketComponent
|
||||
],
|
||||
providers: [ ]
|
||||
})
|
||||
|
||||
@@ -299,6 +299,86 @@ export class ProductsService {
|
||||
return this.http.put(`/taxes/group/${taxGroupId}`, taxGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Observable<any>} Delinquency Range data
|
||||
*/
|
||||
getDelinquencyRanges(): Observable<any> {
|
||||
return this.http.get('/delinquency/ranges');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} delinquencyRateId Delinquency Range Id.
|
||||
* @returns {Observable<any>} Delinquency Range data.
|
||||
*/
|
||||
getDelinquencyRange(delinquencyRateId: any): Observable<any> {
|
||||
return this.http.get(`/delinquency/ranges/${delinquencyRateId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} payload Delinquency Range data
|
||||
* @returns {Observable<any>} Delinquency Range Resource Id
|
||||
*/
|
||||
createDelinquencyRange(payload: any): Observable<any> {
|
||||
return this.http.post('/delinquency/ranges', payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} delinquencyRateId Delinquency Range ID
|
||||
* @param {any} payload Delinquency Range data
|
||||
* @returns {Observable<any>} Changes in the Delinquency Range
|
||||
*/
|
||||
updateDelinquencyRange(delinquencyRateId: any, payload: any): Observable<any> {
|
||||
return this.http.put(`/delinquency/ranges/${delinquencyRateId}`, payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} delinquencyRateId Delinquency Range ID
|
||||
* @returns {Observable<any>} Changes in the Delinquency Range
|
||||
*/
|
||||
deleteDelinquencyRange(delinquencyRateId: any): Observable<any> {
|
||||
return this.http.delete(`/delinquency/ranges/${delinquencyRateId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Observable<any>} Delinquency Bucket data
|
||||
*/
|
||||
getDelinquencyBuckets(): Observable<any> {
|
||||
return this.http.get('/delinquency/buckets');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} delinquencyBucketId Delinquency Bucket Id.
|
||||
* @returns {Observable<any>} Delinquency Bucket data.
|
||||
*/
|
||||
getDelinquencyBucket(delinquencyBucketId: any): Observable<any> {
|
||||
return this.http.get(`/delinquency/buckets/${delinquencyBucketId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} payload Delinquency Bucket data
|
||||
* @returns {Observable<any>} Delinquency Bucket Resource Id
|
||||
*/
|
||||
createDelinquencyBucket(payload: any): Observable<any> {
|
||||
return this.http.post('/delinquency/buckets', payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} delinquencyBucketId Delinquency Bucket ID
|
||||
* @param {any} payload Delinquency Bucket data
|
||||
* @returns {Observable<any>} Changes in the Delinquency Bucket
|
||||
*/
|
||||
updateDelinquencyBucket(delinquencyBucketId: any, payload: any): Observable<any> {
|
||||
return this.http.put(`/delinquency/buckets/${delinquencyBucketId}`, payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} delinquencyBucketId Delinquency Bucket ID
|
||||
* @returns {Observable<any>} Changes in the Delinquency Bucket
|
||||
*/
|
||||
deleteDelinquencyBucket(delinquencyBucketId: any): Observable<any> {
|
||||
return this.http.delete(`/delinquency/buckets/${delinquencyBucketId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Observable<any>} Product mixes data
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user