Skip to content

Commit 7e69d4d

Browse files
committed
WEB-874 Prevent negative values in numeric fields of Group
1 parent f82ad09 commit 7e69d4d

4 files changed

Lines changed: 176 additions & 33 deletions

File tree

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

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ <h4 class="mat-h4 flex-98">
4747
matInput
4848
required
4949
formControlName="repaymentEvery"
50+
min="0"
5051
matTooltip="{{ 'tooltips.Fields are input to calculating the repayment schedule' | translate }}"
5152
/>
5253
@if (loansAccountTermsForm.controls.repaymentEvery.hasError('required')) {
@@ -55,6 +56,9 @@ <h4 class="mat-h4 flex-98">
5556
<strong>{{ 'labels.commons.required' | translate }}</strong>
5657
</mat-error>
5758
}
59+
@if (loansAccountTermsForm.controls.repaymentEvery.hasError('min')) {
60+
<mat-error> {{ 'labels.inputs.Repaid every' | translate }} must be at least <strong>0</strong> </mat-error>
61+
}
5862
</mat-form-field>
5963

6064
<mat-form-field class="flex-23">
@@ -72,13 +76,16 @@ <h4 class="mat-h4 flex-98">
7276
@if (loanProductService.isLoanProduct) {
7377
<mat-form-field class="flex-fill flex-23">
7478
<mat-label>{{ 'labels.inputs.Loan Term' | translate }}</mat-label>
75-
<input type="number" matInput required formControlName="loanTermFrequency" />
79+
<input type="number" matInput required formControlName="loanTermFrequency" min="0" />
7680
@if (loansAccountTermsForm.controls.loanTermFrequency.hasError('required')) {
7781
<mat-error>
7882
{{ 'labels.inputs.Loan Term' | translate }} {{ 'labels.commons.is' | translate }}
7983
<strong>{{ 'labels.commons.required' | translate }}</strong>
8084
</mat-error>
8185
}
86+
@if (loansAccountTermsForm.controls.loanTermFrequency.hasError('min')) {
87+
<mat-error> {{ 'labels.inputs.Loan Term' | translate }} must be at least <strong>0</strong> </mat-error>
88+
}
8289
</mat-form-field>
8390

8491
<mat-form-field class="flex-fill flex-23">
@@ -118,6 +125,7 @@ <h4 class="mat-h4 flex-98">{{ 'labels.inputs.Repayments' | translate }}</h4>
118125
type="number"
119126
matInput
120127
formControlName="numberOfRepayments"
128+
min="0"
121129
matTooltip="{{ 'tooltips.Enter the total count of repayments' | translate }}"
122130
/>
123131
@if (loansAccountTermsForm.controls.numberOfRepayments.hasError('required')) {
@@ -126,6 +134,11 @@ <h4 class="mat-h4 flex-98">{{ 'labels.inputs.Repayments' | translate }}</h4>
126134
<strong>{{ 'labels.commons.required' | translate }}</strong>
127135
</mat-error>
128136
}
137+
@if (loansAccountTermsForm.controls.numberOfRepayments.hasError('min')) {
138+
<mat-error>
139+
{{ 'labels.inputs.Number of repayments' | translate }} must be at least <strong>0</strong>
140+
</mat-error>
141+
}
129142
</mat-form-field>
130143

131144
@if (loansAccountTermsData?.canDefineInstallmentAmount) {
@@ -178,6 +191,7 @@ <h4 class="mat-h4 flex-98">
178191
matInput
179192
required
180193
formControlName="repaymentEvery"
194+
min="0"
181195
matTooltip="{{ 'tooltips.Fields are input to calculating the repayment schedule' | translate }}"
182196
/>
183197
@if (loansAccountTermsForm.controls.repaymentEvery.hasError('required')) {
@@ -186,6 +200,9 @@ <h4 class="mat-h4 flex-98">
186200
<strong>{{ 'labels.commons.required' | translate }}</strong>
187201
</mat-error>
188202
}
203+
@if (loansAccountTermsForm.controls.repaymentEvery.hasError('min')) {
204+
<mat-error> {{ 'labels.inputs.Repaid every' | translate }} must be at least <strong>0</strong> </mat-error>
205+
}
189206
</mat-form-field>
190207

191208
<mat-form-field class="flex-fill flex-23">
@@ -247,7 +264,12 @@ <h4 class="mat-h4 flex-98">{{ 'labels.inputs.Nominal interest rate' | translate
247264
@if (!loansAccountTermsData?.isLoanProductLinkedToFloatingRate) {
248265
<mat-form-field class="flex-fill flex-23">
249266
<mat-label>{{ 'labels.inputs.Nominal interest rate' | translate }} %</mat-label>
250-
<input type="number" matInput formControlName="interestRatePerPeriod" />
267+
<input type="number" matInput formControlName="interestRatePerPeriod" min="0.01" step="0.01" />
268+
@if (loansAccountTermsForm.controls.interestRatePerPeriod.hasError('min')) {
269+
<mat-error>
270+
{{ 'labels.inputs.Nominal interest rate' | translate }} must be at least <strong>0.01</strong>
271+
</mat-error>
272+
}
251273
</mat-form-field>
252274
<mat-form-field class="flex-fill flex-23">
253275
<mat-label>{{ 'labels.inputs.Frequency' | translate }}</mat-label>
@@ -428,17 +450,30 @@ <h4 class="mat-h4 flex-98">{{ 'labels.heading.Interest Calculations' | translate
428450
matInput
429451
type="number"
430452
formControlName="inArrearsTolerance"
453+
min="0"
431454
matTooltip="{{ 'tooltips.With Arrears tolerance' | translate }}"
432455
/>
456+
@if (loansAccountTermsForm.controls.inArrearsTolerance.hasError('min')) {
457+
<mat-error>
458+
{{ 'labels.inputs.Arrears tolerance' | translate }} must be at least <strong>0</strong>
459+
</mat-error>
460+
}
433461
</mat-form-field>
434462

435463
<mat-form-field class="flex-48">
436464
<mat-label>{{ 'labels.inputs.Interest free period' | translate }}</mat-label>
437465
<input
438466
matInput
467+
type="number"
439468
formControlName="graceOnInterestCharged"
469+
min="0"
440470
matTooltip="{{ 'tooltips.If the Interest Free Period' | translate }}"
441471
/>
472+
@if (loansAccountTermsForm.controls.graceOnInterestCharged.hasError('min')) {
473+
<mat-error>
474+
{{ 'labels.inputs.Interest free period' | translate }} must be at least <strong>0</strong>
475+
</mat-error>
476+
}
442477
</mat-form-field>
443478

444479
<h4 class="mat-h4 flex-98">
@@ -448,17 +483,32 @@ <h4 class="mat-h4 flex-98">
448483

449484
<mat-form-field class="flex-fill flex-23">
450485
<mat-label>{{ 'labels.inputs.Grace on principal payment' | translate }}</mat-label>
451-
<input type="number" matInput formControlName="graceOnPrincipalPayment" />
486+
<input type="number" matInput formControlName="graceOnPrincipalPayment" min="0" />
487+
@if (loansAccountTermsForm.controls.graceOnPrincipalPayment.hasError('min')) {
488+
<mat-error>
489+
{{ 'labels.inputs.Grace on principal payment' | translate }} must be at least <strong>0</strong>
490+
</mat-error>
491+
}
452492
</mat-form-field>
453493

454494
<mat-form-field class="flex-fill flex-23">
455495
<mat-label>{{ 'labels.inputs.Grace on interest payment' | translate }}</mat-label>
456-
<input type="number" matInput formControlName="graceOnInterestPayment" />
496+
<input type="number" matInput formControlName="graceOnInterestPayment" min="0" />
497+
@if (loansAccountTermsForm.controls.graceOnInterestPayment.hasError('min')) {
498+
<mat-error>
499+
{{ 'labels.inputs.Grace on interest payment' | translate }} must be at least <strong>0</strong>
500+
</mat-error>
501+
}
457502
</mat-form-field>
458503

459504
<mat-form-field class="flex-48">
460505
<mat-label>{{ 'labels.inputs.On arrears ageing' | translate }}</mat-label>
461-
<input type="number" matInput formControlName="graceOnArrearsAgeing" />
506+
<input type="number" matInput formControlName="graceOnArrearsAgeing" min="0" />
507+
@if (loansAccountTermsForm.controls.graceOnArrearsAgeing.hasError('min')) {
508+
<mat-error>
509+
{{ 'labels.inputs.On arrears ageing' | translate }} must be at least <strong>0</strong>
510+
</mat-error>
511+
}
462512
</mat-form-field>
463513

464514
@if (isDelinquencyEnabled()) {

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

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,38 @@ export class LoansAccountTermsStepComponent extends LoanProductBaseComponent imp
454454
repaymentFrequencyDayOfWeekType.updateValueAndValidity();
455455
});
456456
});
457+
const numericFieldsWithMinZero = [
458+
'graceOnPrincipalPayment',
459+
'graceOnInterestPayment',
460+
'graceOnArrearsAgeing',
461+
'inArrearsTolerance',
462+
'graceOnInterestCharged',
463+
'loanTermFrequency',
464+
'numberOfRepayments',
465+
'repaymentEvery'
466+
];
467+
468+
numericFieldsWithMinZero.forEach((fieldName) => {
469+
const control = this.loansAccountTermsForm.get(fieldName);
470+
if (control) {
471+
control.valueChanges.subscribe((value) => {
472+
if (typeof value === 'number' && value < 0) {
473+
control.setValue(0, { emitEvent: false });
474+
}
475+
});
476+
}
477+
});
478+
479+
const interestRateControl = this.loansAccountTermsForm.get('interestRatePerPeriod');
480+
if (interestRateControl) {
481+
interestRateControl.valueChanges.subscribe((value) => {
482+
if (typeof value === 'number' && value < 0.01 && value !== 0) {
483+
if (value < 0) {
484+
interestRateControl.setValue(0.01, { emitEvent: false });
485+
}
486+
}
487+
});
488+
}
457489
}
458490

459491
/** Custom Listeners for the form to calculate Loan Term */
@@ -527,19 +559,28 @@ export class LoansAccountTermsStepComponent extends LoanProductBaseComponent imp
527559
],
528560
loanTermFrequency: [
529561
{ value: '', disabled: true },
530-
Validators.required
562+
[
563+
Validators.required,
564+
Validators.min(0)
565+
]
531566
],
532567
loanTermFrequencyType: [
533568
'',
534569
Validators.required
535570
],
536571
numberOfRepayments: [
537572
'',
538-
Validators.required
573+
[
574+
Validators.required,
575+
Validators.min(0)
576+
]
539577
],
540578
repaymentEvery: [
541579
'',
542-
Validators.required
580+
[
581+
Validators.required,
582+
Validators.min(0)
583+
]
543584
],
544585
repaymentFrequencyType: [
545586
{ value: '', disabled: true },
@@ -549,7 +590,10 @@ export class LoansAccountTermsStepComponent extends LoanProductBaseComponent imp
549590
repaymentFrequencyDayOfWeekType: [''],
550591
repaymentsStartingFromDate: [''],
551592
interestChargedFromDate: [''],
552-
interestRatePerPeriod: [''],
593+
interestRatePerPeriod: [
594+
'',
595+
Validators.min(0.01)
596+
],
553597
interestType: [''],
554598
isFloatingInterestRate: [null],
555599
isEqualAmortization: [''],
@@ -559,11 +603,26 @@ export class LoansAccountTermsStepComponent extends LoanProductBaseComponent imp
559603
],
560604
interestCalculationPeriodType: [''],
561605
allowPartialPeriodInterestCalculation: [''],
562-
inArrearsTolerance: [''],
563-
graceOnInterestCharged: [''],
564-
graceOnPrincipalPayment: [''],
565-
graceOnInterestPayment: [''],
566-
graceOnArrearsAgeing: [''],
606+
inArrearsTolerance: [
607+
'',
608+
Validators.min(0)
609+
],
610+
graceOnInterestCharged: [
611+
'',
612+
Validators.min(0)
613+
],
614+
graceOnPrincipalPayment: [
615+
'',
616+
Validators.min(0)
617+
],
618+
graceOnInterestPayment: [
619+
'',
620+
Validators.min(0)
621+
],
622+
graceOnArrearsAgeing: [
623+
'',
624+
Validators.min(0)
625+
],
567626
loanIdToClose: [''],
568627
fixedEmiAmount: [''],
569628
isTopup: [''],

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

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,16 @@
2020

2121
<mat-form-field class="flex-48">
2222
<mat-label>{{ 'labels.inputs.Nominal Annual Interest' | translate }}</mat-label>
23-
<input type="number" matInput formControlName="nominalAnnualInterestRate" required />
24-
<mat-error>
25-
{{ 'labels.inputs.Nominal Annual Interest' | translate }} {{ 'labels.commons.is' | translate }}
26-
<strong>{{ 'labels.commons.required' | translate }}</strong>
27-
</mat-error>
23+
<input type="number" matInput formControlName="nominalAnnualInterestRate" required min="0" step="0.01" />
24+
@if (savingsAccountTermsForm.controls.nominalAnnualInterestRate.hasError('required')) {
25+
<mat-error>
26+
{{ 'labels.inputs.Nominal Annual Interest' | translate }} {{ 'labels.commons.is' | translate }}
27+
<strong>{{ 'labels.commons.required' | translate }}</strong>
28+
</mat-error>
29+
}
30+
@if (savingsAccountTermsForm.controls.nominalAnnualInterestRate.hasError('min')) {
31+
<mat-error> {{ 'labels.inputs.Nominal Annual Interest' | translate }} must be zero or greater </mat-error>
32+
}
2833
</mat-form-field>
2934

3035
<mat-form-field class="flex-48">
@@ -92,7 +97,7 @@
9297

9398
<mat-form-field class="flex-48">
9499
<mat-label>{{ 'labels.inputs.Minimum Opening Balance' | translate }}</mat-label>
95-
<input type="number" matInput formControlName="minRequiredOpeningBalance" />
100+
<input type="number" matInput formControlName="minRequiredOpeningBalance" min="0" />
96101
</mat-form-field>
97102

98103
<mat-checkbox labelPosition="before" formControlName="withdrawalFeeForTransfers" class="margin-v flex-48">
@@ -103,7 +108,7 @@ <h4 class="mat-h4 flex-98">{{ 'labels.inputs.Lock-in Period' | translate }}</h4>
103108

104109
<mat-form-field class="flex-48">
105110
<mat-label>{{ 'labels.inputs.Frequency' | translate }}</mat-label>
106-
<input type="number" matInput formControlName="lockinPeriodFrequency" />
111+
<input type="number" matInput formControlName="lockinPeriodFrequency" min="0" />
107112
</mat-form-field>
108113

109114
<mat-form-field class="flex-48">
@@ -129,15 +134,15 @@ <h3 class="mat-h3 flex-23">{{ 'labels.inputs.Overdraft' | translate }}</h3>
129134
<div class="flex-fill layout-row-wrap gap-2percent responsive-column">
130135
<mat-form-field class="flex-31">
131136
<mat-label>{{ 'labels.inputs.Minimum Overdraft Required for Interest Calculation' | translate }}</mat-label>
132-
<input type="number" matInput formControlName="minOverdraftForInterestCalculation" />
137+
<input type="number" matInput formControlName="minOverdraftForInterestCalculation" min="0" />
133138
</mat-form-field>
134139
<mat-form-field class="flex-31">
135140
<mat-label>{{ 'labels.inputs.Nominal Annual Interest for Overdraft' | translate }}</mat-label>
136-
<input type="number" matInput formControlName="nominalAnnualInterestRateOverdraft" />
141+
<input type="number" matInput formControlName="nominalAnnualInterestRateOverdraft" min="0" />
137142
</mat-form-field>
138143
<mat-form-field class="flex-31">
139144
<mat-label>{{ 'labels.inputs.Maximum Overdraft Amount Limit' | translate }}</mat-label>
140-
<input type="number" matInput formControlName="overdraftLimit" />
145+
<input type="number" matInput formControlName="overdraftLimit" min="0" />
141146
</mat-form-field>
142147
</div>
143148
}
@@ -150,13 +155,13 @@ <h3 class="mat-h3 flex-23">{{ 'labels.inputs.Overdraft' | translate }}</h3>
150155

151156
<mat-form-field class="flex-48">
152157
<mat-label>{{ 'labels.inputs.Minimum Balance' | translate }}</mat-label>
153-
<input type="number" matInput formControlName="minRequiredBalance" />
158+
<input type="number" matInput formControlName="minRequiredBalance" min="0" />
154159
</mat-form-field>
155160

156161
@if (savingsAccountTermsForm.controls.minBalanceForInterestCalculation.value) {
157162
<mat-form-field class="flex-48">
158163
<mat-label>{{ 'labels.inputs.Balance Required for Interest Calculation' | translate }}</mat-label>
159-
<input type="number" matInput formControlName="minBalanceForInterestCalculation" />
164+
<input type="number" matInput formControlName="minBalanceForInterestCalculation" min="0" />
160165
</mat-form-field>
161166
}
162167
</div>

0 commit comments

Comments
 (0)