Maturity Date :{{loanDetails?.timeline.expectedMaturityDate | dateFormat}}
Value |
-
+ |
{{loanDetails.timeline.actualDisbursementDate | dateFormat}}
Not Available
@@ -124,7 +125,7 @@
| Value |
-
+ |
{{loanDetails.timeline.actualDisbursementDate | dateFormat}}
Not Available
diff --git a/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.html b/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.html
index ff00de384..39526b7cb 100644
--- a/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.html
+++ b/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.html
@@ -1,5 +1,9 @@
+
+ Loan Account Classification : {{loanDetails?.delinquencyRange.classification}}
+
+
@@ -29,7 +33,7 @@
| |
-
+
|
|
@@ -135,4 +139,4 @@
-
\ No newline at end of file
+
diff --git a/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.scss b/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.scss
index 6a37a3d69..e38332f65 100644
--- a/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.scss
+++ b/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.scss
@@ -9,4 +9,4 @@ table {
.check {
padding-left: 15px;
-}
\ No newline at end of file
+}
diff --git a/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.ts b/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.ts
index 97ec0bf74..12ed05da8 100644
--- a/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.ts
+++ b/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.ts
@@ -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;
});
}
diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-preview-step/loan-product-preview-step.component.html b/src/app/products/loan-products/loan-product-stepper/loan-product-preview-step/loan-product-preview-step.component.html
index bf38f9dc3..d3b4f79ff 100644
--- a/src/app/products/loan-products/loan-product-stepper/loan-product-preview-step/loan-product-preview-step.component.html
+++ b/src/app/products/loan-products/loan-product-stepper/loan-product-preview-step/loan-product-preview-step.component.html
@@ -346,6 +346,11 @@
{{ loanProduct.overdueDaysForNPA }}
+
+ Delinquency Bucket:
+ {{ loanProduct.delinquencyBucketId ? 'Yes' : 'No' }}
+
+
Account moves out of NPA only after all arrears have been cleared:
{{ loanProduct.accountMovesOutOfNPAOnlyOnArrearsCompletion ? 'Yes' : 'No' }}
diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.html b/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.html
index 815b04c48..61c698984 100644
--- a/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.html
+++ b/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.html
@@ -72,6 +72,15 @@
+
+ Delinquency Bucket
+
+
+ {{ delinquencyBucket.name }}
+
+
+
+
diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.ts b/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.ts
index 2f82c9940..b86a19273 100644
--- a/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.ts
+++ b/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.ts
@@ -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': ['']
});
}
diff --git a/src/app/products/loan-products/view-loan-product/view-loan-product.component.html b/src/app/products/loan-products/view-loan-product/view-loan-product.component.html
index 7fdee8d37..f5a104875 100644
--- a/src/app/products/loan-products/view-loan-product/view-loan-product.component.html
+++ b/src/app/products/loan-products/view-loan-product/view-loan-product.component.html
@@ -506,6 +506,8 @@
{{ loanProduct.allowAttributeOverrides.graceOnPrincipalAndInterestPayment ? 'Yes' : 'No' }}
Number of days a loan may be overdue before moving into arrears:
{{ loanProduct.allowAttributeOverrides.graceOnArrearsAgeing ? 'Yes' : 'No' }}
+ Delinquency Bucket:
+ {{ loanProduct.delinquencyBucket.id ? 'Yes' : 'No' }}
diff --git a/src/app/products/manage-delinquency-buckets/delinquency-bucket/create-bucket/create-bucket.component.html b/src/app/products/manage-delinquency-buckets/delinquency-bucket/create-bucket/create-bucket.component.html
new file mode 100644
index 000000000..49f501592
--- /dev/null
+++ b/src/app/products/manage-delinquency-buckets/delinquency-bucket/create-bucket/create-bucket.component.html
@@ -0,0 +1,77 @@
+
diff --git a/src/app/products/manage-delinquency-buckets/delinquency-bucket/create-bucket/create-bucket.component.scss b/src/app/products/manage-delinquency-buckets/delinquency-bucket/create-bucket/create-bucket.component.scss
new file mode 100644
index 000000000..b99efaa71
--- /dev/null
+++ b/src/app/products/manage-delinquency-buckets/delinquency-bucket/create-bucket/create-bucket.component.scss
@@ -0,0 +1,10 @@
+.container {
+ max-width: 37rem;
+
+ .content {
+ div {
+ margin: 0.8rem 0;
+ word-wrap: break-word;
+ }
+ }
+}
diff --git a/src/app/products/manage-delinquency-buckets/delinquency-bucket/create-bucket/create-bucket.component.spec.ts b/src/app/products/manage-delinquency-buckets/delinquency-bucket/create-bucket/create-bucket.component.spec.ts
new file mode 100644
index 000000000..da9ee7ab6
--- /dev/null
+++ b/src/app/products/manage-delinquency-buckets/delinquency-bucket/create-bucket/create-bucket.component.spec.ts
@@ -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 ;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ CreateBucketComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(CreateBucketComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/products/manage-delinquency-buckets/delinquency-bucket/create-bucket/create-bucket.component.ts b/src/app/products/manage-delinquency-buckets/delinquency-bucket/create-bucket/create-bucket.component.ts
new file mode 100644
index 000000000..6334f365f
--- /dev/null
+++ b/src/app/products/manage-delinquency-buckets/delinquency-bucket/create-bucket/create-bucket.component.ts
@@ -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 });
+ });
+ }
+ }
+}
diff --git a/src/app/products/manage-delinquency-buckets/delinquency-bucket/delinquency-bucket.component.html b/src/app/products/manage-delinquency-buckets/delinquency-bucket/delinquency-bucket.component.html
new file mode 100644
index 000000000..92c835353
--- /dev/null
+++ b/src/app/products/manage-delinquency-buckets/delinquency-bucket/delinquency-bucket.component.html
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+ Filter
+
+
+
+
+
+
+
+
+
+ | Name |
+ {{ delinquencyBucket.name }} |
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/app/products/manage-delinquency-buckets/delinquency-bucket/delinquency-bucket.component.resolver.ts b/src/app/products/manage-delinquency-buckets/delinquency-bucket/delinquency-bucket.component.resolver.ts
new file mode 100644
index 000000000..c1994c1b9
--- /dev/null
+++ b/src/app/products/manage-delinquency-buckets/delinquency-bucket/delinquency-bucket.component.resolver.ts
@@ -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
diff --git a/src/app/products/products.module.ts b/src/app/products/products.module.ts
index 049af78b6..7872fef26 100644
--- a/src/app/products/products.module.ts
+++ b/src/app/products/products.module.ts
@@ -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: [ ]
})
diff --git a/src/app/products/products.service.ts b/src/app/products/products.service.ts
index 7fb060fab..d60627239 100644
--- a/src/app/products/products.service.ts
+++ b/src/app/products/products.service.ts
@@ -299,6 +299,86 @@ export class ProductsService {
return this.http.put(`/taxes/group/${taxGroupId}`, taxGroup);
}
+ /**
+ * @returns {Observable} Delinquency Range data
+ */
+ getDelinquencyRanges(): Observable {
+ return this.http.get('/delinquency/ranges');
+ }
+
+ /**
+ * @param {any} delinquencyRateId Delinquency Range Id.
+ * @returns {Observable} Delinquency Range data.
+ */
+ getDelinquencyRange(delinquencyRateId: any): Observable {
+ return this.http.get(`/delinquency/ranges/${delinquencyRateId}`);
+ }
+
+ /**
+ * @param {any} payload Delinquency Range data
+ * @returns {Observable} Delinquency Range Resource Id
+ */
+ createDelinquencyRange(payload: any): Observable {
+ return this.http.post('/delinquency/ranges', payload);
+ }
+
+ /**
+ * @param {any} delinquencyRateId Delinquency Range ID
+ * @param {any} payload Delinquency Range data
+ * @returns {Observable} Changes in the Delinquency Range
+ */
+ updateDelinquencyRange(delinquencyRateId: any, payload: any): Observable {
+ return this.http.put(`/delinquency/ranges/${delinquencyRateId}`, payload);
+ }
+
+ /**
+ * @param {any} delinquencyRateId Delinquency Range ID
+ * @returns {Observable} Changes in the Delinquency Range
+ */
+ deleteDelinquencyRange(delinquencyRateId: any): Observable {
+ return this.http.delete(`/delinquency/ranges/${delinquencyRateId}`);
+ }
+
+ /**
+ * @returns {Observable} Delinquency Bucket data
+ */
+ getDelinquencyBuckets(): Observable {
+ return this.http.get('/delinquency/buckets');
+ }
+
+ /**
+ * @param {any} delinquencyBucketId Delinquency Bucket Id.
+ * @returns {Observable} Delinquency Bucket data.
+ */
+ getDelinquencyBucket(delinquencyBucketId: any): Observable {
+ return this.http.get(`/delinquency/buckets/${delinquencyBucketId}`);
+ }
+
+ /**
+ * @param {any} payload Delinquency Bucket data
+ * @returns {Observable} Delinquency Bucket Resource Id
+ */
+ createDelinquencyBucket(payload: any): Observable {
+ return this.http.post('/delinquency/buckets', payload);
+ }
+
+ /**
+ * @param {any} delinquencyBucketId Delinquency Bucket ID
+ * @param {any} payload Delinquency Bucket data
+ * @returns {Observable} Changes in the Delinquency Bucket
+ */
+ updateDelinquencyBucket(delinquencyBucketId: any, payload: any): Observable {
+ return this.http.put(`/delinquency/buckets/${delinquencyBucketId}`, payload);
+ }
+
+ /**
+ * @param {any} delinquencyBucketId Delinquency Bucket ID
+ * @returns {Observable} Changes in the Delinquency Bucket
+ */
+ deleteDelinquencyBucket(delinquencyBucketId: any): Observable {
+ return this.http.delete(`/delinquency/buckets/${delinquencyBucketId}`);
+ }
+
/**
* @returns {Observable} Product mixes data
*/
| |