WEB-467 Interest Rates Field Allows Zero and Negative Values in Loan Product Creation Form

This commit is contained in:
Soni Jay
2025-12-30 08:43:10 +05:30
parent 7fad7ee756
commit 88b52c008b
15 changed files with 72 additions and 12 deletions
@@ -159,9 +159,12 @@
[min]="0"
[attr.disabled]="isZeroInterest()"
/>
<mat-error>
<mat-error *ngIf="loanProductTermsForm.get('minInterestRatePerPeriod')?.hasError('min')">
{{ 'labels.commons.Minimum Value must be' | translate }}
<strong>{{ 'labels.commons.greater equal to than 0' | translate }}</strong>
<strong>0</strong>
</mat-error>
<mat-error *ngIf="loanProductTermsForm.get('minInterestRatePerPeriod')?.hasError('pattern')">
{{ 'labels.commons.Only up to 6 decimal places allowed' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="flex-fill flex-23">
@@ -171,12 +174,20 @@
matInput
formControlName="interestRatePerPeriod"
required
[min]="0"
[attr.disabled]="isZeroInterest()"
/>
<mat-error>
<mat-error *ngIf="loanProductTermsForm.get('interestRatePerPeriod')?.hasError('required')">
{{ 'labels.catalogs.Default' | translate }} {{ 'labels.inputs.Nominal interest rate' | translate }}
<span class="text-danger">{{ 'labels.commons.is required' | translate }}</span>
</mat-error>
<mat-error *ngIf="loanProductTermsForm.get('interestRatePerPeriod')?.hasError('min')">
{{ 'labels.catalogs.Default' | translate }} {{ 'labels.inputs.Nominal interest rate' | translate }}
{{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
<strong>0</strong>
</mat-error>
<mat-error *ngIf="loanProductTermsForm.get('interestRatePerPeriod')?.hasError('pattern')">
{{ 'labels.commons.Only up to 6 decimal places allowed' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="flex-fill flex-23">
@@ -188,11 +199,17 @@
[min]="0"
[attr.disabled]="isZeroInterest()"
/>
<mat-error>
<mat-error *ngIf="loanProductTermsForm.get('maxInterestRatePerPeriod')?.hasError('min')">
{{ 'labels.commons.Minimum Value must be' | translate }}
<strong>0</strong>
</mat-error>
<mat-error *ngIf="loanProductTermsForm.errors?.['maxLessThanMin']">
{{ 'labels.commons.Maximum Value must be' | translate }}
<strong>{{ 'labels.commons.greater equal to than 0' | translate }}</strong>
{{ 'labels.commons.and must be greater than' | translate }}
<strong>{{ 'labels.commons.Minimum Principal' | translate }}</strong>
<strong>{{ 'labels.commons.greater equal to than' | translate }}</strong>
{{ 'labels.inputs.Minimum' | translate }}
</mat-error>
<mat-error *ngIf="loanProductTermsForm.get('maxInterestRatePerPeriod')?.hasError('pattern')">
{{ 'labels.commons.Only up to 6 decimal places allowed' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="flex-fill flex-23">
@@ -230,12 +230,28 @@ export class LoanProductTermsStepComponent implements OnInit, OnChanges {
allowApprovedDisbursedAmountsOverApplied: [false],
overAppliedCalculationType: [{ value: null, disabled: true }],
overAppliedNumber: [{ value: null, disabled: true }],
minInterestRatePerPeriod: [''],
minInterestRatePerPeriod: [
'',
[
Validators.min(0),
Validators.pattern(/^\d+([.,]\d{1,6})?$/)
]
],
interestRatePerPeriod: [
'',
Validators.required
[
Validators.required,
Validators.min(0),
Validators.pattern(/^\d+([.,]\d{1,6})?$/)
]
],
maxInterestRatePerPeriod: [
'',
[
Validators.min(0),
Validators.pattern(/^\d+([.,]\d{1,6})?$/)
]
],
maxInterestRatePerPeriod: [''],
interestRateFrequencyType: [
'',
Validators.required
@@ -487,7 +503,21 @@ export class LoanProductTermsStepComponent implements OnInit, OnChanges {
}
get loanProductTerms() {
return this.loanProductTermsForm.getRawValue();
const formValue = this.loanProductTermsForm.getRawValue();
// Normalize decimal separators: convert comma to dot for backend compatibility
const normalizeDecimal = (value: any) => {
if (typeof value === 'string' && value.includes(',')) {
return value.replace(',', '.');
}
return value;
};
return {
...formValue,
minInterestRatePerPeriod: normalizeDecimal(formValue.minInterestRatePerPeriod),
interestRatePerPeriod: normalizeDecimal(formValue.interestRatePerPeriod),
maxInterestRatePerPeriod: normalizeDecimal(formValue.maxInterestRatePerPeriod)
};
}
isZeroInterest(): boolean {
+1
View File
@@ -81,6 +81,7 @@
"validation.msg.loan.principal.is.greater.than.max": "Částka jistiny {{params[0].value}} je neplatná. Musí být částka menší nebo rovna maximální částce jistiny {{params[1].value}}.",
"validation.msg.loan.principal.is.less.than.min": "Částka jistiny {{params[0].value}} je neplatná. Musí být částka větší nebo rovna minimální částce jistiny {{params[1].value}}.",
"validation.msg.loanproduct.accountingType.cannot.be.blank": "Typ účetnictví je povinný.",
"labels.commons.Only up to 6 decimal places allowed": "Povoleno je maximálně 6 desetinných míst.",
"validation.msg.loanproduct.accountingType.is.not.within.expected.range": "Účetní typ je neplatný. Musí to být číslo mezi {{params[1].value}} a {{params[2].value}} včetně.",
"validation.msg.loanproduct.allowPartialPeriodInterestCalculation.not.supported.for.daily.calculations": "Povolit výpočet částečných splátek nelze pro denní výpočet nastavit jako true",
"validation.msg.loanproduct.allowVariableInstallments.not.supported.for.selected.interest.calculation.type": "Variabilní splátka by měla být použita buď s denním výpočtem úroku, nebo povolit výpočet částečného úroku true",
+1
View File
@@ -81,6 +81,7 @@
"validation.msg.loan.principal.is.greater.than.max": "Der Kapitalbetrag {{params[0].value}} ist ungültig. Muss ein Betrag sein, der kleiner oder gleich dem maximalen Kapitalbetrag {{params[1].value}} ist.",
"validation.msg.loan.principal.is.less.than.min": "Der Kapitalbetrag {{params[0].value}} ist ungültig. Muss ein Betrag sein, der größer oder gleich dem Mindestkapitalbetrag {{params[1].value}} ist.",
"validation.msg.loanproduct.accountingType.cannot.be.blank": "Der Abrechnungstyp ist obligatorisch.",
"labels.commons.Only up to 6 decimal places allowed": "Nur bis zu 6 Dezimalstellen erlaubt.",
"validation.msg.loanproduct.accountingType.is.not.within.expected.range": "Der Abrechnungstyp ist ungültig. Muss eine Zahl zwischen {{params[1].value}} und {{params[2].value}} (einschließlich) sein.",
"validation.msg.loanproduct.allowPartialPeriodInterestCalculation.not.supported.for.daily.calculations": "Teilzahlungsberechnung zulassen kann für die tägliche Berechnung nicht auf „Wahr“ gesetzt werden",
"validation.msg.loanproduct.allowVariableInstallments.not.supported.for.selected.interest.calculation.type": "Variable Ratenzahlung sollte entweder mit täglicher Zinsberechnung verwendet werden oder eine Teilzinsberechnung zulassen",
+1
View File
@@ -81,6 +81,7 @@
"validation.msg.loan.principal.is.greater.than.max": "Principal amount {{params[0].value}} is invalid. Must be an amount less than or equal to Maximum principal amount {{params[1].value}}.",
"validation.msg.loan.principal.is.less.than.min": "Principal amount {{params[0].value}} is invalid. Must be an amount greater than or equal to Minimum Principal amount {{params[1].value}}.",
"validation.msg.loanproduct.accountingType.cannot.be.blank": "Accounting type is mandatory.",
"labels.commons.Only up to 6 decimal places allowed": "Only up to 6 decimal places allowed.",
"validation.msg.loanproduct.accountingType.is.not.within.expected.range": "Accounting type is invalid. Must be a number between {{params[1].value}} and {{params[2].value}} inclusive.",
"validation.msg.loanproduct.allowPartialPeriodInterestCalculation.not.supported.for.daily.calculations": "Allow Partial Installment Calculation cannot be set as true for daily calculation",
"validation.msg.loanproduct.allowVariableInstallments.not.supported.for.selected.interest.calculation.type": "Variable Installment should be used with either daily interest calculation or allow partial interest calculation true",
+1
View File
@@ -81,6 +81,7 @@
"validation.msg.loan.principal.is.greater.than.max": "El importe principal {{params[0].value}} no es válido. Debe ser un monto menor o igual al monto principal máximo {{params[1].value}}.",
"validation.msg.loan.principal.is.less.than.min": "El importe principal {{params[0].value}} no es válido. Debe ser un monto mayor o igual al monto mínimo de capital {{params[1].value}}.",
"validation.msg.loanproduct.accountingType.cannot.be.blank": "El tipo de contabilidad es obligatorio.",
"labels.commons.Only up to 6 decimal places allowed": "Solo se permiten hasta 6 decimales.",
"validation.msg.loanproduct.accountingType.is.not.within.expected.range": "El tipo de contabilidad no es válido. Debe ser un número entre {{params[1].value}} y {{params[2].value}} inclusive.",
"validation.msg.loanproduct.allowPartialPeriodInterestCalculation.not.supported.for.daily.calculations": "Permitir el cálculo de cuotas parciales no se puede establecer como verdadero para el cálculo diario",
"validation.msg.loanproduct.allowVariableInstallments.not.supported.for.selected.interest.calculation.type": "La cuota variable debe usarse con el cálculo de interés diario o permitir el cálculo de interés parcial.",
+1
View File
@@ -81,6 +81,7 @@
"validation.msg.loan.principal.is.greater.than.max": "El importe principal {{params[0].value}} no es válido. Debe ser un monto menor o igual al monto principal máximo {{params[1].value}}.",
"validation.msg.loan.principal.is.less.than.min": "El importe principal {{params[0].value}} no es válido. Debe ser un monto mayor o igual al monto mínimo de capital {{params[1].value}}.",
"validation.msg.loanproduct.accountingType.cannot.be.blank": "El tipo de contabilidad es obligatorio.",
"labels.commons.Only up to 6 decimal places allowed": "Solo se permiten hasta 6 decimales.",
"validation.msg.loanproduct.accountingType.is.not.within.expected.range": "El tipo de contabilidad no es válido. Debe ser un número entre {{params[1].value}} y {{params[2].value}} inclusive.",
"validation.msg.loanproduct.allowPartialPeriodInterestCalculation.not.supported.for.daily.calculations": "Permitir el cálculo de cuotas parciales no se puede establecer como verdadero para el cálculo diario",
"validation.msg.loanproduct.allowVariableInstallments.not.supported.for.selected.interest.calculation.type": "La cuota variable debe usarse con el cálculo de interés diario o permitir el cálculo de interés parcial.",
+1
View File
@@ -81,6 +81,7 @@
"validation.msg.loan.principal.is.greater.than.max": "Le montant principal {{params[0].value}} n'est pas valide. Doit être un montant inférieur ou égal au montant principal maximum {{params[1].value}}.",
"validation.msg.loan.principal.is.less.than.min": "Le montant principal {{params[0].value}} n'est pas valide. Doit être un montant supérieur ou égal au montant principal minimum {{params[1].value}}.",
"validation.msg.loanproduct.accountingType.cannot.be.blank": "Le type de comptabilité est obligatoire.",
"labels.commons.Only up to 6 decimal places allowed": "Jusqu'à 6 décimales autorisées.",
"validation.msg.loanproduct.accountingType.is.not.within.expected.range": "Le type de comptabilité n'est pas valide. Doit être un nombre compris entre {{params[1].value}} et {{params[2].value}} inclus.",
"validation.msg.loanproduct.allowPartialPeriodInterestCalculation.not.supported.for.daily.calculations": "Autoriser le calcul des versements partiels ne peut pas être défini comme vrai pour le calcul quotidien",
"validation.msg.loanproduct.allowVariableInstallments.not.supported.for.selected.interest.calculation.type": "Le versement variable doit être utilisé avec le calcul des intérêts quotidiens ou permettre le calcul des intérêts partiels.",
+1
View File
@@ -84,6 +84,7 @@
"validation.msg.loanproduct.accountingType.is.not.within.expected.range": "Il tipo di contabilità non è valido. Deve essere un numero compreso tra {{params[1].value}} e {{params[2].value}} inclusi.",
"validation.msg.loanproduct.allowPartialPeriodInterestCalculation.not.supported.for.daily.calculations": "Consenti calcolo rata parziale non può essere impostato su vero per il calcolo giornaliero",
"validation.msg.loanproduct.allowVariableInstallments.not.supported.for.selected.interest.calculation.type": "La rata variabile deve essere utilizzata con il calcolo dell'interesse giornaliero o con il calcolo dell'interesse parziale vero",
"labels.commons.Only up to 6 decimal places allowed": "Sono consentiti solo fino a 6 decimali.",
"validation.msg.loanproduct.amortizationType.cannot.be.blank": "La tipologia di ammortamento è obbligatoria.",
"validation.msg.loanproduct.amortizationType.is.not.within.expected.range": "Il tipo di ammortamento non è valido. Deve essere un numero compreso tra {{params[1].value}} e {{params[2].value}} inclusi.",
"validation.msg.loanproduct.currencyCode.cannot.be.blank": "La valuta è obbligatoria.",
+1
View File
@@ -84,6 +84,7 @@
"validation.msg.loanproduct.accountingType.is.not.within.expected.range": "회계 유형이 잘못되었습니다. {{params[1].value}}와 {{params[2].value}} 사이의 숫자여야 합니다.",
"validation.msg.loanproduct.allowPartialPeriodInterestCalculation.not.supported.for.daily.calculations": "일일 계산에서는 부분 할부 계산 허용을 true로 설정할 수 없습니다.",
"validation.msg.loanproduct.allowVariableInstallments.not.supported.for.selected.interest.calculation.type": "변액할부는 일일이자 계산과 함께 사용하거나 부분이자 계산을 허용해야 합니다.",
"labels.commons.Only up to 6 decimal places allowed": "6자리 이하의 소수점만 허용됩니다.",
"validation.msg.loanproduct.amortizationType.cannot.be.blank": "분할 상환 유형은 필수입니다.",
"validation.msg.loanproduct.amortizationType.is.not.within.expected.range": "할부 상환 유형이 잘못되었습니다. {{params[1].value}}와 {{params[2].value}} 사이의 숫자여야 합니다.",
"validation.msg.loanproduct.currencyCode.cannot.be.blank": "통화는 필수입니다.",
+1
View File
@@ -81,6 +81,7 @@
"validation.msg.loan.principal.is.greater.than.max": "Pagrindinė suma {{params[0].value}} yra neteisinga. Turi būti suma, mažesnė arba lygi didžiausiai pagrindinei sumai {{params[1].value}}.",
"validation.msg.loan.principal.is.less.than.min": "Pagrindinė suma {{params[0].value}} yra neteisinga. Turi būti suma, didesnė arba lygi minimaliajai pagrindinei sumai {{params[1].value}}.",
"validation.msg.loanproduct.accountingType.cannot.be.blank": "Apskaitos tipas yra privalomas.",
"labels.commons.Only up to 6 decimal places allowed": "Leidžiama iki 6 dešimtainių skaičių.",
"validation.msg.loanproduct.accountingType.is.not.within.expected.range": "Netinkamas apskaitos tipas. Turi būti skaičius tarp {{params[1].value}} ir {{params[2].value}} imtinai.",
"validation.msg.loanproduct.allowPartialPeriodInterestCalculation.not.supported.for.daily.calculations": "Leisti dalinį įmokos apskaičiavimą negali būti nustatyta kaip teisinga atliekant kasdienį skaičiavimą",
"validation.msg.loanproduct.allowVariableInstallments.not.supported.for.selected.interest.calculation.type": "Kintamoji įmoka turėtų būti naudojama skaičiuojant kasdienes palūkanas arba leidžiant skaičiuoti dalines palūkanas",
+1
View File
@@ -81,6 +81,7 @@
"validation.msg.loan.principal.is.greater.than.max": "Pamatsumma {{params[0].value}} nav derīga. Jābūt summai, kas ir mazāka vai vienāda ar maksimālo pamatsummu {{params[1].value}}.",
"validation.msg.loan.principal.is.less.than.min": "Pamatsumma {{params[0].value}} nav derīga. Jābūt summai, kas ir lielāka vai vienāda ar minimālo pamatsummu {{params[1].value}}.",
"validation.msg.loanproduct.accountingType.cannot.be.blank": "Uzskaites veids ir obligāts.",
"labels.commons.Only up to 6 decimal places allowed": "Atļauts tikai līdz 6 zīmēm aiz komata.",
"validation.msg.loanproduct.accountingType.is.not.within.expected.range": "Uzskaites veids nav derīgs. Jābūt skaitlim starp {{params[1].value}} un {{params[2].value}} ieskaitot.",
"validation.msg.loanproduct.allowPartialPeriodInterestCalculation.not.supported.for.daily.calculations": "Atļaut daļējas iemaksas aprēķinu nevar iestatīt kā patiesu ikdienas aprēķinam",
"validation.msg.loanproduct.allowVariableInstallments.not.supported.for.selected.interest.calculation.type": "Mainīgā iemaksa jāizmanto, aprēķinot ikdienas procentus, vai arī pieļaujot daļēju procentu aprēķinu",
+1
View File
@@ -81,6 +81,7 @@
"validation.msg.loan.principal.is.greater.than.max": "मूल रकम {{params[0].value}} अमान्य छ। अधिकतम मूल रकम {{params[1].value}} भन्दा कम वा बराबरको रकम हुनुपर्छ।",
"validation.msg.loan.principal.is.less.than.min": "मूल रकम {{params[0].value}} अमान्य छ। न्यूनतम प्रिन्सिपल रकम {{params[1].value}} भन्दा बढी वा बराबरको रकम हुनुपर्छ।",
"validation.msg.loanproduct.accountingType.cannot.be.blank": "लेखा प्रकार अनिवार्य छ।",
"labels.commons.Only up to 6 decimal places allowed": "अधिकतम ६ दशमलव स्थानहरू मात्र अनुमति छ।",
"validation.msg.loanproduct.accountingType.is.not.within.expected.range": "लेखा प्रकार अमान्य छ। समावेशी {{params[1].value}} र {{params[2].value}} बीचको संख्या हुनुपर्छ।",
"validation.msg.loanproduct.allowPartialPeriodInterestCalculation.not.supported.for.daily.calculations": "अनुमति दिनुहोस् आंशिक किस्ता गणना दैनिक गणनाको लागि सत्यको रूपमा सेट गर्न सकिँदैन",
"validation.msg.loanproduct.allowVariableInstallments.not.supported.for.selected.interest.calculation.type": "चर किस्ता दैनिक ब्याज गणनाको साथ प्रयोग गरिनु पर्छ वा आंशिक ब्याज गणनालाई अनुमति दिनुपर्छ।",
+1
View File
@@ -81,6 +81,7 @@
"validation.msg.loan.principal.is.greater.than.max": "O valor principal {{params[0].value}} é inválido. Deve ser um valor menor ou igual ao valor principal máximo {{params[1].value}}.",
"validation.msg.loan.principal.is.less.than.min": "O valor principal {{params[0].value}} é inválido. Deve ser um valor maior ou igual ao valor principal mínimo {{params[1].value}}.",
"validation.msg.loanproduct.accountingType.cannot.be.blank": "O tipo de contabilidade é obrigatório.",
"labels.commons.Only up to 6 decimal places allowed": "Apenas até 6 casas decimais permitidas.",
"validation.msg.loanproduct.accountingType.is.not.within.expected.range": "O tipo de contabilidade é inválido. Deve ser um número entre {{params[1].value}} e {{params[2].value}} inclusive.",
"validation.msg.loanproduct.allowPartialPeriodInterestCalculation.not.supported.for.daily.calculations": "Permitir cálculo de parcela parcial não pode ser definido como verdadeiro para cálculo diário",
"validation.msg.loanproduct.allowVariableInstallments.not.supported.for.selected.interest.calculation.type": "A Parcela Variável deve ser usada com cálculo de juros diários ou permitir cálculo de juros parciais verdadeiro",
+1
View File
@@ -81,6 +81,7 @@
"validation.msg.loan.principal.is.greater.than.max": "Kiasi kikuu {{params[0].value}} si sahihi. Ni lazima kiwe kiasi kidogo kuliko au sawa na Kiwango cha juu kabisa cha msingi {{params[1].value}}.",
"validation.msg.loan.principal.is.less.than.min": "Kiasi kikuu {{params[0].value}} si sahihi. Ni lazima kiwe kiasi kikubwa kuliko au sawa na Kiasi cha Chini cha Msingi {{params[1].value}}.",
"validation.msg.loanproduct.accountingType.cannot.be.blank": "Aina ya uhasibu ni ya lazima.",
"labels.commons.Only up to 6 decimal places allowed": "Inaruhusiwa hadi sehemu 6 za desimali pekee.",
"validation.msg.loanproduct.accountingType.is.not.within.expected.range": "Aina ya uhasibu ni batili. Lazima iwe nambari kati ya {{params[1].value}} na {{params[2].value}} zikijumlishwa.",
"validation.msg.loanproduct.allowPartialPeriodInterestCalculation.not.supported.for.daily.calculations": "Ruhusu Ukokotoaji wa Usawa wa Kiasi hauwezi kuwekwa kuwa kweli kwa hesabu ya kila siku",
"validation.msg.loanproduct.allowVariableInstallments.not.supported.for.selected.interest.calculation.type": "Malipo ya Kubadilishana yanapaswa kutumiwa pamoja na hesabu ya maslahi ya kila siku au kuruhusu ukokotoaji wa riba kiasi kuwa kweli",