Skip to content

Commit 0970516

Browse files
WEB-670: Working Capital loan delinquency grace days
1 parent b541079 commit 0970516

30 files changed

Lines changed: 272 additions & 75 deletions

src/app/directives/positive-number.directive.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import { Directive, ElementRef, HostListener, inject } from '@angular/core';
1010

11-
@Directive({ selector: '[mifosxPositiveNumber]' })
11+
@Directive({ selector: '[mifosxPositiveNumber]', standalone: true })
1212
export class PositiveNumberDirective {
1313
private el = inject(ElementRef);
1414

src/app/loans/common-resolvers/loan-delinquency-data.resolver.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export class LoanDelinquencyDataResolver extends LoanBaseResolver {
2727
constructor() {
2828
super();
2929
}
30+
3031
/**
3132
* Returns the Loans with Association data.
3233
* @returns {Observable<any>}

src/app/loans/common-resolvers/loan-originators.resolver.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@
99
import { Injectable, inject } from '@angular/core';
1010
import { ActivatedRouteSnapshot } from '@angular/router';
1111
import { LoansService } from 'app/loans/loans.service';
12+
import { LoanProductService } from 'app/products/loan-products/services/loan-product.service';
1213
import { Observable, throwError } from 'rxjs';
1314

1415
@Injectable({
1516
providedIn: 'root'
1617
})
1718
export class LoanOriginatorsResolver {
1819
private loansService = inject(LoansService);
20+
private loanProductService = inject(LoanProductService);
1921

2022
/**
2123
* Returns the Loans data.
@@ -26,6 +28,8 @@ export class LoanOriginatorsResolver {
2628
if (!loanId) {
2729
return throwError(() => new Error('Missing loanId route param'));
2830
}
29-
return this.loansService.getLoanOriginators(loanId);
31+
if (this.loanProductService.isLoanProduct) {
32+
return this.loansService.getLoanOriginators(loanId);
33+
}
3034
}
3135
}

src/app/loans/common-resolvers/loans-account-and-template.resolver.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,35 @@ import { Injectable, inject } from '@angular/core';
1111
import { ActivatedRouteSnapshot } from '@angular/router';
1212

1313
/** rxjs Imports */
14-
import { Observable } from 'rxjs';
14+
import { EMPTY, Observable } from 'rxjs';
1515

1616
/** Custom Services */
1717
import { LoansService } from '../loans.service';
18-
import { LoanProductService } from 'app/products/loan-products/services/loan-product.service';
18+
import { LoanBaseResolver } from './loan-base.resolver';
1919

2020
/**
2121
* Loan accounts template data resolver.
2222
*/
2323
@Injectable()
24-
export class LoansAccountAndTemplateResolver {
24+
export class LoansAccountAndTemplateResolver extends LoanBaseResolver {
2525
private loansService = inject(LoansService);
26-
private loanProductService = inject(LoanProductService);
26+
27+
constructor() {
28+
super();
29+
}
2730

2831
/**
2932
* Returns the loan account template data.
3033
* @returns {Observable<any>}
3134
*/
3235
resolve(route: ActivatedRouteSnapshot): Observable<any> {
36+
this.initialize(route);
3337
const loanId = route.paramMap.get('loanId') || route.parent.paramMap.get('loanId');
34-
return this.loanProductService.isLoanProduct
35-
? this.loansService.getLoansAccountAndTemplateResource(loanId)
36-
: this.loansService.getWorkingCapitalLoanDetails(loanId);
38+
if (!isNaN(+loanId)) {
39+
return this.isLoanProduct
40+
? this.loansService.getLoansAccountAndTemplateResource(loanId)
41+
: this.loansService.getWorkingCapitalLoanDetails(loanId);
42+
}
43+
return EMPTY;
3744
}
3845
}

src/app/loans/create-loans-account/create-loans-account.component.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,8 @@ export class CreateLoansAccountComponent extends LoanProductBaseComponent implem
124124
this.loansAccountProductTemplate.options = {
125125
delinquencyBucketOptions: templateData.delinquencyBucketOptions,
126126
fundOptions: templateData.fundOptions,
127-
periodFrequencyTypeOptions: templateData.periodFrequencyTypeOptions
127+
periodFrequencyTypeOptions: templateData.periodFrequencyTypeOptions,
128+
delinquencyStartTypeOptions: templateData.delinquencyStartTypeOptions
128129
};
129130
}
130131
this.currencyCode = this.loansAccountProductTemplate.currency.code;
@@ -290,6 +291,11 @@ export class CreateLoansAccountComponent extends LoanProductBaseComponent implem
290291
}
291292
}
292293

294+
// No Empty discount value to be sent
295+
if (payload['discount'] == null || payload['discount'] === '') {
296+
delete payload['discount'];
297+
}
298+
293299
this.loansService
294300
.createLoansAccount(this.loanProductService.loanAccountPath, payload)
295301
.subscribe((response: any) => {

src/app/loans/edit-loans-account/edit-loans-account.component.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ export class EditLoansAccountComponent extends LoanProductBaseComponent {
109109
this.loansAccountProductTemplate.options = {
110110
delinquencyBucketOptions: templateData.delinquencyBucketOptions,
111111
fundOptions: templateData.fundOptions,
112-
periodFrequencyTypeOptions: templateData.periodFrequencyTypeOptions
112+
periodFrequencyTypeOptions: templateData.periodFrequencyTypeOptions,
113+
delinquencyStartTypeOptions: templateData.delinquencyStartTypeOptions
113114
};
114115
}
115116
if (this.loansAccountProductTemplate.loanProductId) {
@@ -313,6 +314,11 @@ export class EditLoansAccountComponent extends LoanProductBaseComponent {
313314
}
314315
}
315316

317+
// No Empty discount value to be sent
318+
if (payload['discount'] == null || payload['discount'] === '') {
319+
delete payload['discount'];
320+
}
321+
316322
this.loansService
317323
.updateLoansAccount(this.loanProductService.loanAccountPath, this.loanId, payload)
318324
.subscribe((response: any) => {

src/app/loans/loans-account-stepper/loans-account-preview-step/loans-account-preview-step.component.html

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,20 @@ <h3 class="mat-h3 margin-t flex-fill">{{ 'labels.heading.Terms' | translate }}</
107107
</div>
108108
}
109109

110+
@if (loansAccount.delinquencyGraceDays) {
111+
<div class="flex-fill">
112+
<span class="flex-30">{{ 'labels.inputs.Delinquency Grace Days' | translate }}:</span>
113+
<span class="flex-70"> {{ loansAccount.delinquencyGraceDays | formatNumber }}</span>
114+
</div>
115+
}
116+
117+
@if (loansAccount.delinquencyStartType) {
118+
<div class="flex-fill">
119+
<span class="flex-30">{{ 'labels.inputs.Delinquency Start Type' | translate }}:</span>
120+
<span class="flex-60">{{ camalize(loansAccount.delinquencyStartType) | translateKey: 'catalogs' }}</span>
121+
</div>
122+
}
123+
110124
<div class="flex-fill">
111125
<span class="flex-30">{{ 'labels.inputs.Period Payment Rate' | translate }}:</span>
112126
<span class="flex-70"> {{ loansAccount.periodPaymentRate | formatNumber }} % </span>

src/app/loans/loans-account-stepper/loans-account-terms-step/loans-account-terms-step.component.html

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,17 @@ <h4 class="mat-h4 flex-98">
3636
}
3737
</mat-form-field>
3838

39-
<mat-form-field class="flex-48">
39+
<mat-form-field class="flex-23">
4040
<mat-label>{{ 'labels.inputs.Discount' | translate }}</mat-label>
4141
<input type="number" matInput mifosxPositiveNumber min="0" formControlName="discount" />
4242
</mat-form-field>
4343

44-
<mat-form-field class="flex-48">
44+
<mat-form-field class="flex-23">
4545
<mat-label>{{ 'labels.inputs.Period Payment Rate' | translate }}</mat-label>
4646
<input type="number" matInput mifosxPositiveNumber min="0" formControlName="periodPaymentRate" />
4747
</mat-form-field>
4848

49-
<mat-form-field class="flex-24">
49+
<mat-form-field class="flex-23">
5050
<mat-label>{{ 'labels.inputs.Period Payment Frequency' | translate }}</mat-label>
5151
<input
5252
type="number"
@@ -65,7 +65,7 @@ <h4 class="mat-h4 flex-98">
6565
}
6666
</mat-form-field>
6767

68-
<mat-form-field class="flex-24">
68+
<mat-form-field class="flex-23">
6969
<mat-label>{{ 'labels.inputs.Period Payment Frequency Type' | translate }}</mat-label>
7070
<mat-select formControlName="repaymentFrequencyType" required>
7171
@for (repaymentFrequencyType of termFrequencyTypeData; track repaymentFrequencyType) {
@@ -75,6 +75,22 @@ <h4 class="mat-h4 flex-98">
7575
}
7676
</mat-select>
7777
</mat-form-field>
78+
79+
<mat-form-field class="flex-23">
80+
<mat-label>{{ 'labels.inputs.Delinquency Grace Days' | translate }}</mat-label>
81+
<input type="number" min="0" matInput formControlName="delinquencyGraceDays" />
82+
</mat-form-field>
83+
84+
<mat-form-field class="flex-23">
85+
<mat-label>{{ 'labels.inputs.Delinquency Start Type' | translate }}</mat-label>
86+
<mat-select formControlName="delinquencyStartType">
87+
@for (delinquencyStartType of delinquencyStartTypeOptions; track delinquencyStartType) {
88+
<mat-option [value]="delinquencyStartType.id">
89+
{{ delinquencyStartType.value | translateKey: 'catalogs' }}
90+
</mat-option>
91+
}
92+
</mat-select>
93+
</mat-form-field>
7894
}
7995

8096
@if (loanProductService.isLoanProduct) {

src/app/loans/loans-account-stepper/loans-account-terms-step/loans-account-terms-step.component.ts

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { DatepickerBase } from 'app/shared/form-dialog/formfield/model/datepicke
2121
import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base';
2222
import { InputBase } from 'app/shared/form-dialog/formfield/model/input-base';
2323
import { Currency } from 'app/shared/models/general.model';
24-
import { CodeName, OptionData } from 'app/shared/models/option-data.model';
24+
import { CodeName, OptionData, StringEnumOptionData } from 'app/shared/models/option-data.model';
2525
import { InputAmountComponent } from '../../../shared/input-amount/input-amount.component';
2626
import { MatTooltip } from '@angular/material/tooltip';
2727
import { MatCheckbox } from '@angular/material/checkbox';
@@ -174,6 +174,8 @@ export class LoansAccountTermsStepComponent extends LoanProductBaseComponent imp
174174

175175
allowAttributeOverrides: any | null = null;
176176

177+
delinquencyStartTypeOptions: StringEnumOptionData[] = [];
178+
177179
constructor() {
178180
super();
179181
this.createloansAccountTermsForm();
@@ -319,6 +321,7 @@ export class LoansAccountTermsStepComponent extends LoanProductBaseComponent imp
319321
this.loansAccountTermsData = this.loansAccountProductTemplate;
320322
this.currency = this.loansAccountTermsData.currency;
321323
this.termFrequencyTypeData = this.loansAccountTermsData.options?.periodFrequencyTypeOptions;
324+
this.delinquencyStartTypeOptions = this.loansAccountTermsData.options?.delinquencyStartTypeOptions;
322325
if (this.loanId != null && 'accountNo' in this.loansAccountTemplate) {
323326
this.loansAccountTermsData = this.loansAccountTemplate;
324327
this.loansAccountTermsForm.patchValue({
@@ -327,11 +330,16 @@ export class LoansAccountTermsStepComponent extends LoanProductBaseComponent imp
327330
periodPaymentRate: this.loansAccountTermsData.periodPaymentRate,
328331
totalPayment: this.loansAccountTermsData.balance?.totalPayment,
329332
repaymentEvery: this.loansAccountTermsData.repaymentEvery,
330-
repaymentFrequencyType: this.loansAccountTermsData.repaymentFrequencyType?.id
333+
repaymentFrequencyType: this.loansAccountTermsData.repaymentFrequencyType?.id,
334+
delinquencyGraceDays: this.loansAccountTermsData.delinquencyGraceDays,
335+
delinquencyStartType: this.loansAccountTermsData.delinquencyStartType?.code
331336
});
332337
} else {
333338
this.loansAccountTermsForm.patchValue({
334-
principalAmount: this.loansAccountTermsData.product.principal
339+
discount: this.loansAccountTermsData.product.discount || '',
340+
principalAmount: this.loansAccountTermsData.product.principal,
341+
delinquencyGraceDays: this.loansAccountTermsData.product.delinquencyGraceDays || '',
342+
delinquencyStartType: this.loansAccountTermsData.product.delinquencyStartType?.code || ''
335343
});
336344
}
337345
this.allowAttributeOverrides = this.loansAccountProductTemplate.product.allowAttributeOverrides;
@@ -436,7 +444,12 @@ export class LoansAccountTermsStepComponent extends LoanProductBaseComponent imp
436444
principalAmount: this.loansAccountTermsData.principal || this.loansAccountTermsData.product.principal,
437445
periodPaymentRate: this.loansAccountTermsData.periodPaymentRate,
438446
repaymentEvery: this.loansAccountTermsData.repaymentEvery,
439-
repaymentFrequencyType: this.loansAccountTermsData.repaymentFrequencyType.id
447+
repaymentFrequencyType: this.loansAccountTermsData.repaymentFrequencyType.id,
448+
delinquencyGraceDays:
449+
this.loansAccountTermsData.delinquencyGraceDays || this.loansAccountTermsData.product.delinquencyGraceDays,
450+
delinquencyStartType:
451+
this.loansAccountTermsData.delinquencyStartType?.id ||
452+
this.loansAccountTermsData.product.delinquencyStartType?.id
440453
});
441454
}
442455
}
@@ -628,7 +641,14 @@ export class LoansAccountTermsStepComponent extends LoanProductBaseComponent imp
628641
repaymentFrequencyType: [
629642
'',
630643
Validators.required
631-
]
644+
],
645+
delinquencyGraceDays: [
646+
'',
647+
[
648+
Validators.min(0)
649+
]
650+
],
651+
delinquencyStartType: ['']
632652
});
633653
}
634654
}

src/app/loans/loans-view/account-details/account-details.component.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ <h3>{{ 'labels.heading.Loan Details' | translate }}</h3>
3939
<span class="flex-50">{{ loanDetails.discount | formatNumber }}</span>
4040
</div>
4141
}
42+
43+
<div class="flex-fill layout-row">
44+
<span class="flex-50"> {{ 'labels.inputs.Delinquency Grace Days' | translate }} </span>
45+
<span class="flex-50">{{ loanDetails.delinquencyGraceDays | formatNumber }}</span>
46+
</div>
47+
48+
<div class="flex-fill layout-row">
49+
<span class="flex-50"> {{ 'labels.inputs.Delinquency Start Type' | translate }} </span>
50+
<span class="flex-50">{{ loanDetails.delinquencyStartType?.value | translateKey: 'catalogs' }}</span>
51+
</div>
4252
}
4353

4454
@if (loanProductService.isLoanProduct) {

0 commit comments

Comments
 (0)