diff --git a/src/app/core/i18n/i18n.service.ts b/src/app/core/i18n/i18n.service.ts index 5190a5dd57..27d4d0e062 100644 --- a/src/app/core/i18n/i18n.service.ts +++ b/src/app/core/i18n/i18n.service.ts @@ -5,7 +5,7 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { Observable } from 'rxjs'; -@Injectable() +@Injectable({ providedIn: 'root' }) export class I18nService { constructor(private translateService: TranslateService) {} diff --git a/src/app/loans/glim-account/create-glim-account/create-glim-account.component.ts b/src/app/loans/glim-account/create-glim-account/create-glim-account.component.ts index c1d04dcfb7..90556cb826 100644 --- a/src/app/loans/glim-account/create-glim-account/create-glim-account.component.ts +++ b/src/app/loans/glim-account/create-glim-account/create-glim-account.component.ts @@ -1,5 +1,28 @@ +interface GLIMClient { + id: number; + principal: number; +} + +interface GLIMRequestData { + charges: Array<{ chargeId: number; amount: number; currency: any }>; + clientId: number; + totalLoan: number; + loanType: string; + applicationId: number; + amortizationType: number; + principal: number; + syncDisbursementWithMeeting: boolean; + expectedDisbursementDate: string; + submittedOnDate: string; + dateFormat: string; + locale: string; + groupId: number; + isParentAccount?: boolean; + lastApplication?: boolean; +} /** Angular Imports */ import { Component, QueryList, ViewChild, ViewChildren } from '@angular/core'; +import { Currency } from 'app/shared/models/general.model'; import { I18nService } from 'app/core/i18n/i18n.service'; import { ActivatedRoute, Router } from '@angular/router'; @@ -177,51 +200,61 @@ export class CreateGlimAccountComponent { }; } - setData(client: any, totalLoan: number): any { + setData(applicationId: number, client: GLIMClient, totalLoan: number, isFirst: boolean, isLast: boolean): string { const locale = this.settingsService.language.code; const dateFormat = this.settingsService.dateFormat; // const monthDayFormat = 'dd MMMM'; - const data = { + const data: GLIMRequestData = { ...this.loansAccount, charges: this.loansAccount.charges.map((charge: any) => ({ chargeId: charge.id, - amount: charge.amount + amount: charge.amount, + currency: charge.currency as Currency })), clientId: client.id, totalLoan: totalLoan, loanType: 'glim', + applicationId: applicationId, amortizationType: 1, - isParentAccount: true, principal: client.principal, syncDisbursementWithMeeting: false, expectedDisbursementDate: this.dateUtils.formatDate(this.loansAccount.expectedDisbursementDate, dateFormat), submittedOnDate: this.dateUtils.formatDate(this.loansAccount.submittedOnDate, dateFormat), - dateFormat, - // monthDayFormat, - locale + dateFormat: dateFormat, + locale: locale, + groupId: this.loansAccountTemplate.group.id }; - data.groupId = this.loansAccountTemplate.group.id; - - delete data.principalAmount; - // TODO: 2025-03-17: Apparently (?!) unsupported for GLIM - delete data.allowPartialPeriodInterestCalculation; - delete data.multiDisburseLoan; - delete data.isFloatingInterestRate; - + if (isFirst) { + data.isParentAccount = true; + } + if (isLast) { + data.lastApplication = true; + } return JSON.stringify(data); } /** Request Body Data */ - buildRequestData(): any[] { + buildRequestData(): Array<{ + requestId: string; + reference: string | null; + method: string; + relativeUrl: string; + body: string; + }> { const requestData = []; const memberSelected = this.selectedMembers?.selectedMembers ?? []; const totalLoan = this.totalLoanAmount(); + const applicationId = Math.floor(1000000000 + Math.random() * 9000000000); + for (let index = 0; index < memberSelected.length; index++) { + const isFirst = index === 0; + const isLast = index === memberSelected.length - 1; requestData.push({ requestId: index.toString(), + reference: index === 0 ? null : (index - 1).toString(), method: 'POST', relativeUrl: 'loans', - body: this.setData(memberSelected[index], totalLoan) + body: this.setData(applicationId, memberSelected[index] as GLIMClient, totalLoan, isFirst, isLast) }); } return requestData; @@ -236,57 +269,10 @@ export class CreateGlimAccountComponent { return total; } - /** - * Creates a new GLIM account. - */ - submit() { - this.selectedMembers = this.loansActiveClientMembers?.selectedClientMembers; - const memberSelected = this.loansActiveClientMembers?.selectedClientMembers?.selectedMembers ?? []; - if (!memberSelected.length) return; - const gsimMemberIds = new Set(this.dataSource.map((m: any) => Number(m.id))); - for (const member of memberSelected) { - const memberId = Number(member.id); - // Validate savings account ownership - const ownerId = Number(member.linkAccountOwnerId); - if (member.linkAccountId && member.linkAccountOwnerId && ownerId !== memberId) { - this.i18nService.translate('errors.linkedSavingsAccountOwnership').subscribe((msg: string) => { - this.notify({ defaultUserMessage: msg, errors: [] }, { memberId }); - }); - return; - } - // Validate GSIM membership - if (!gsimMemberIds.has(memberId)) { - this.i18nService.translate('errors.clientNotInGSIM', { id: memberId }).subscribe((msg: string) => { - this.notify({ defaultUserMessage: msg, errors: [] }, { memberId }); - }); - return; - } - } - - // Use date format from settingsService for interestChargedFromDate - const data = this.buildRequestData(); - this.loansService.createGlimAccount(data).subscribe((response: any) => { - const body = JSON.parse(response[0].body); - if (body.glimId) { - this.router.navigate( - [ - '../', - body.glimId - ], - { relativeTo: this.route } - ); - } else { - this.notify(body, { batchSize: data.length }); - } - }); - } - - notify(body: any, context?: { [k: string]: unknown }) { - const parts: string[] = [String(body?.defaultUserMessage ?? '')]; - if (Array.isArray(body?.errors)) { - for (const e of body.errors) parts.push(String(e?.developerMessage ?? '')); - } - if (context) parts.push(`Context: ${JSON.stringify(context)}`); - console.error(parts.join(' ').trim()); + notify(body: any, data: any) { + let message = body.defaultUserMessage + ' '; + body.errors?.forEach((error: any) => (message += error.developerMessage + ' ')); + message += 'Data: ' + JSON.stringify(data); + console.error(message); } } diff --git a/src/app/loans/loans-account-stepper/loans-account-charges-step/loans-account-charges-step.component.html b/src/app/loans/loans-account-stepper/loans-account-charges-step/loans-account-charges-step.component.html index bec25484fa..bd323915a2 100644 --- a/src/app/loans/loans-account-stepper/loans-account-charges-step/loans-account-charges-step.component.html +++ b/src/app/loans/loans-account-stepper/loans-account-charges-step/loans-account-charges-step.component.html @@ -24,7 +24,7 @@ {{ 'labels.inputs.name' | translate }} - {{ charge.name + ', ' + charge.currency.displaySymbol }} + {{ charge.name }}, {{ charge.currency.displaySymbol }} @@ -39,7 +39,13 @@ {{ 'labels.inputs.Amount' | translate }} {{ charge.amount }} - @@ -84,6 +90,8 @@ charge.chargeTimeType.value === 'Specified due date' " (click)="editChargeDate(charge)" + type="button" + aria-label="Edit charge date" > @@ -93,7 +101,7 @@ {{ 'labels.inputs.Actions' | translate }} - @@ -110,7 +118,9 @@

{{ 'labels.heading.Overdue Charges' | translate }} {{ 'labels.inputs.name' | translate }} - {{ charge.name }},{{ charge.currency.displaySymbol }} + + {{ charge.name }}, {{ charge.currency.displaySymbol }} + @@ -120,7 +130,18 @@

{{ 'labels.heading.Overdue Charges' | translate }} {{ 'labels.inputs.Amount' | translate }} - {{ charge.amount | formatNumber }} + + {{ charge.amount | formatNumber }} + + @@ -134,15 +155,15 @@

{{ 'labels.heading.Overdue Charges' | translate }}
- - -
diff --git a/src/app/loans/loans-account-stepper/loans-account-charges-step/loans-account-charges-step.component.ts b/src/app/loans/loans-account-stepper/loans-account-charges-step/loans-account-charges-step.component.ts index 1dc89530ea..f46faa39e5 100644 --- a/src/app/loans/loans-account-stepper/loans-account-charges-step/loans-account-charges-step.component.ts +++ b/src/app/loans/loans-account-stepper/loans-account-charges-step/loans-account-charges-step.component.ts @@ -24,6 +24,7 @@ import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.componen /** Custom Services */ import { DatepickerBase } from 'app/shared/form-dialog/formfield/model/datepicker-base'; import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base'; +import { take } from 'rxjs/operators'; import { InputBase } from 'app/shared/form-dialog/formfield/model/input-base'; import { SettingsService } from 'app/settings/settings.service'; import { Dates } from 'app/core/utils/dates'; @@ -226,13 +227,16 @@ export class LoansAccountChargesStepComponent implements OnInit, OnChanges { formfields: formfields }; const editNoteDialogRef = this.dialog.open(FormDialogComponent, { data }); - editNoteDialogRef.afterClosed().subscribe((response: any) => { - if (response.data) { - const newCharge = { ...charge, amount: response.data.value.amount }; - this.chargesDataSource.splice(this.chargesDataSource.indexOf(charge), 1, newCharge); - this.chargesDataSource = this.chargesDataSource.concat([]); - } - }); + editNoteDialogRef + .afterClosed() + .pipe(take(1)) + .subscribe((response: any) => { + if (response.data) { + const newCharge = { ...charge, amount: response.data.value.amount }; + this.chargesDataSource.splice(this.chargesDataSource.indexOf(charge), 1, newCharge); + this.chargesDataSource = this.chargesDataSource.concat([]); + } + }); this.pristine = false; } @@ -257,24 +261,27 @@ export class LoansAccountChargesStepComponent implements OnInit, OnChanges { formfields: formfields }; const editNoteDialogRef = this.dialog.open(FormDialogComponent, { data }); - editNoteDialogRef.afterClosed().subscribe((response: any) => { - if (response.data) { - let newCharge: any; - const dateFormat = this.settingsService.dateFormat; - const date = this.dateUtils.formatDate(response.data.value.date, dateFormat); - switch (charge.chargeTimeType.value) { - case 'Specified due date': - case 'Weekly Fee': - newCharge = { ...charge, dueDate: date }; - break; - case 'Annual Fee': - newCharge = { ...charge, feeOnMonthDay: date }; - break; + editNoteDialogRef + .afterClosed() + .pipe(take(1)) + .subscribe((response: any) => { + if (response.data) { + let newCharge: any; + const dateFormat = this.settingsService.dateFormat; + const date = this.dateUtils.formatDate(response.data.value.date, dateFormat); + switch (charge.chargeTimeType.value) { + case 'Specified due date': + case 'Weekly Fee': + newCharge = { ...charge, dueDate: date }; + break; + case 'Annual Fee': + newCharge = { ...charge, feeOnMonthDay: date }; + break; + } + this.chargesDataSource.splice(this.chargesDataSource.indexOf(charge), 1, newCharge); + this.chargesDataSource = this.chargesDataSource.concat([]); } - this.chargesDataSource.splice(this.chargesDataSource.indexOf(charge), 1, newCharge); - this.chargesDataSource = this.chargesDataSource.concat([]); - } - }); + }); this.pristine = false; } @@ -299,13 +306,16 @@ export class LoansAccountChargesStepComponent implements OnInit, OnChanges { formfields: formfields }; const editNoteDialogRef = this.dialog.open(FormDialogComponent, { data }); - editNoteDialogRef.afterClosed().subscribe((response: any) => { - if (response.data) { - const newCharge = { ...charge, feeInterval: response.data.value.feeInterval }; - this.chargesDataSource.splice(this.chargesDataSource.indexOf(charge), 1, newCharge); - this.chargesDataSource = this.chargesDataSource.concat([]); - } - }); + editNoteDialogRef + .afterClosed() + .pipe(take(1)) + .subscribe((response: any) => { + if (response.data) { + const newCharge = { ...charge, feeInterval: response.data.value.feeInterval }; + this.chargesDataSource.splice(this.chargesDataSource.indexOf(charge), 1, newCharge); + this.chargesDataSource = this.chargesDataSource.concat([]); + } + }); this.pristine = false; } @@ -317,13 +327,46 @@ export class LoansAccountChargesStepComponent implements OnInit, OnChanges { const deleteChargeDialogRef = this.dialog.open(DeleteDialogComponent, { data: { deleteContext: `charge ${charge.name}` } }); - deleteChargeDialogRef.afterClosed().subscribe((response: any) => { - if (response.delete) { - this.chargesDataSource.splice(this.chargesDataSource.indexOf(charge), 1); - this.chargesDataSource = this.chargesDataSource.concat([]); - this.pristine = false; - } - }); + deleteChargeDialogRef + .afterClosed() + .pipe(take(1)) + .subscribe((response: any) => { + if (response.delete) { + this.chargesDataSource.splice(this.chargesDataSource.indexOf(charge), 1); + this.chargesDataSource = this.chargesDataSource.concat([]); + this.pristine = false; + } + }); + } + + editOverdueChargeAmount(charge: { amount: number; [key: string]: any }) { + const formfields: FormfieldBase[] = [ + new InputBase({ + controlName: 'amount', + label: 'Amount', + value: charge.amount, + type: 'number', + required: false + }) + + ]; + const data = { + title: 'Edit Overdue Charge Amount', + layout: { addButtonText: 'Confirm' }, + formfields: formfields + }; + const editNoteDialogRef = this.dialog.open(FormDialogComponent, { data }); + editNoteDialogRef + .afterClosed() + .pipe(take(1)) + .subscribe((response?: { data?: { value: { amount: number } } }) => { + if (response?.data) { + const newCharge = { ...charge, amount: response.data.value.amount }; + this.overDueChargesDataSource.splice(this.overDueChargesDataSource.indexOf(charge), 1, newCharge); + this.overDueChargesDataSource = this.overDueChargesDataSource.concat([]); + this.pristine = false; + } + }); } get isValid() { diff --git a/src/app/loans/loans-account-stepper/loans-account-preview-step/loans-account-preview-step.component.html b/src/app/loans/loans-account-stepper/loans-account-preview-step/loans-account-preview-step.component.html index cbe1a36f47..2ecaafc1fd 100644 --- a/src/app/loans/loans-account-stepper/loans-account-preview-step/loans-account-preview-step.component.html +++ b/src/app/loans/loans-account-stepper/loans-account-preview-step/loans-account-preview-step.component.html @@ -262,14 +262,14 @@

{{ 'labels.heading.Charges' | translate }}

{{ 'labels.inputs.name' | translate }} - {{ charge.name + ', ' + charge.currency.displaySymbol }} + {{ charge.name }}, {{ charge.currency.displaySymbol }} {{ 'labels.inputs.Type' | translate }} - {{ charge.chargeCalculationType.value }} + {{ charge.chargeCalculationType?.value || '' }} @@ -283,7 +283,7 @@

{{ 'labels.heading.Charges' | translate }}

{{ 'labels.inputs.Collected On' | translate }} - {{ charge.chargeTimeType.value }} + {{ charge.chargeTimeType?.value || '' }} @@ -291,20 +291,22 @@

{{ 'labels.heading.Charges' | translate }}

{{ 'labels.inputs.Date' | translate }} {{ (charge.dueDate | dateFormat) || 'Unassigned' }} - + {{ (charge.feeOnMonthDay | dateFormat) || 'Unassigned' }} @@ -329,7 +331,9 @@

{{ 'labels.heading.Overdue Charges' | translate }} {{ 'labels.inputs.name' | translate }} - {{ charge.name }},{{ charge.currency.displaySymbol }} + + {{ charge.name }},{{ charge.currency.displaySymbol }} + diff --git a/src/app/loans/loans-account-stepper/loans-account-terms-step/loans-account-terms-step.component.html b/src/app/loans/loans-account-stepper/loans-account-terms-step/loans-account-terms-step.component.html index 82b3c03e95..cc837b2b2d 100644 --- a/src/app/loans/loans-account-stepper/loans-account-terms-step/loans-account-terms-step.component.html +++ b/src/app/loans/loans-account-stepper/loans-account-terms-step/loans-account-terms-step.component.html @@ -1,4 +1,28 @@
+
+ + {{ 'labels.inputs.Moratorium on Principal (months)' | translate }} + + + + {{ 'labels.inputs.Moratorium on Interest (months)' | translate }} + + +
{{ 'labels.inputs.Loan Term' | translate }} - + {{ 'labels.inputs.Loan Term' | translate }} {{ 'labels.commons.is' | translate }} {{ 'labels.commons.required' | translate }} @@ -39,7 +63,7 @@

{{ 'labels.inputs.Fixed Length' | translate }} - + {{ loansAccountTermsForm.value.loanTermFrequencyType | find: termFrequencyTypeData : 'id' : 'value' @@ -54,6 +78,7 @@

{{ 'labels.inputs.Repayments' | translate }}

matInput formControlName="numberOfRepayments" matTooltip="{{ 'tooltips.Enter the total count of repayments' | translate }}" + aria-label="Number of repayments" /> {{ 'labels.inputs.Number of repayments' | translate }} {{ 'labels.commons.is' | translate }} @@ -63,7 +88,7 @@

{{ 'labels.inputs.Repayments' | translate }}

{{ 'labels.inputs.Installment Amount' | translate }} - + @@ -75,6 +100,7 @@

{{ 'labels.inputs.Repayments' | translate }}

matTooltip="{{ 'tooltips.May be entered to override' | translate }}" [matDatepicker]="repaymentsPicker" formControlName="repaymentsStartingFromDate" + aria-label="First repayment on" /> @@ -89,6 +115,7 @@

{{ 'labels.inputs.Repayments' | translate }}

[matDatepicker]="interestPicker" matTooltip="{{ 'tooltips.May be entered to override the date' | translate }}" formControlName="interestChargedFromDate" + aria-label="Interest charged from" /> @@ -110,6 +137,7 @@

required formControlName="repaymentEvery" matTooltip="{{ 'tooltips.Fields are input to calculating the repayment schedule' | translate }}" + aria-label="Repaid every" /> {{ 'labels.inputs.Repaid every' | translate }} {{ 'labels.commons.is' | translate }} @@ -165,7 +193,7 @@

{{ 'labels.inputs.Nominal interest rate' | translate {{ 'labels.inputs.Nominal interest rate' | translate }} % - + @@ -212,7 +240,12 @@

{{ 'labels.inputs.Nominal interest rate' | translate {{ 'labels.inputs.Principal Percentage Per Installment' | translate }} - + {{ 'labels.heading.Interest Calculations' | translate type="number" formControlName="inArrearsTolerance" matTooltip="{{ 'tooltips.With Arrears tolerance' | translate }}" + aria-label="Arrears tolerance" /> @@ -338,6 +372,7 @@

{{ 'labels.heading.Interest Calculations' | translate matInput formControlName="graceOnInterestCharged" matTooltip="{{ 'tooltips.If the Interest Free Period' | translate }}" + aria-label="Interest free period" /> @@ -348,17 +383,17 @@

{{ 'labels.inputs.Grace on principal payment' | translate }} - + {{ 'labels.inputs.Grace on interest payment' | translate }} - + {{ 'labels.inputs.On arrears ageing' | translate }} - +
@@ -490,7 +525,14 @@

{{ 'labels.heading.Loan Tranche Details' | translate
{{ 'labels.inputs.Maximum allowed outstanding balance' | translate }} - + {{ 'labels.inputs.Maximum allowed outstanding balance' | translate }} {{ 'labels.commons.is' | translate }} {{ 'labels.commons.required' | translate }} @@ -501,6 +543,7 @@

{{ 'labels.heading.Loan Tranche Details' | translate type="button" mat-icon-button color="primary" + aria-label="Add Disbursement Data Entry" required (click)="addDisbursementDataEntry(disbursementData)" [disabled]="isMultiDisbursedCompleted" @@ -537,6 +580,7 @@

type="button" mat-icon-button color="warn" + aria-label="Remove Disbursement Data Entry" (click)="removeDisbursementDataEntry(rowIndex)" matTooltip="{{ 'tooltips.Delete' | translate }}" matTooltipPosition="left" @@ -614,7 +658,7 @@

{{ 'labels.heading.Collaterals Data' | translate }}
-
@@ -644,7 +688,13 @@

{{ 'labels.heading.Collaterals Data' | translate }} {{ 'labels.inputs.Actions' | translate }} - @@ -656,15 +706,15 @@

{{ 'labels.heading.Collaterals Data' | translate }}
- - -
diff --git a/src/app/loans/loans-account-stepper/loans-account-terms-step/loans-account-terms-step.component.ts b/src/app/loans/loans-account-stepper/loans-account-terms-step/loans-account-terms-step.component.ts index 464de16a37..e3379a7f01 100644 --- a/src/app/loans/loans-account-stepper/loans-account-terms-step/loans-account-terms-step.component.ts +++ b/src/app/loans/loans-account-stepper/loans-account-terms-step/loans-account-terms-step.component.ts @@ -219,7 +219,10 @@ export class LoansAccountTermsStepComponent implements OnInit, OnChanges { multiDisburseLoan: this.loansAccountTermsData.multiDisburseLoan, interestRateFrequencyType: this.loansAccountTermsData.interestRateFrequencyType.id, balloonRepaymentAmount: this.loansAccountTermsData.balloonRepaymentAmount, - interestRecognitionOnDisbursementDate: this.loansAccountTermsData.interestRecognitionOnDisbursementDate || false + interestRecognitionOnDisbursementDate: + this.loansAccountTermsData.interestRecognitionOnDisbursementDate || false, + moratoriumPrincipal: this.loansAccountTermsData.moratoriumPrincipal ?? 0, + moratoriumInterest: this.loansAccountTermsData.moratoriumInterest ?? 0 }); this.setAdvancedPaymentStrategyControls(); @@ -317,58 +320,58 @@ export class LoansAccountTermsStepComponent implements OnInit, OnChanges { formattedDate = this.formatDateToDDMMYYYY(repaymentDate); } this.loansAccountTermsForm.patchValue({ - repaymentsStartingFromDate: this.loansAccountTermsData.expectedFirstRepaymentOnDate && formattedDate + repaymentsStartingFromDate: this.loansAccountTermsData.expectedFirstRepaymentOnDate && formattedDate, + principalAmount: this.loansAccountTermsData.principal, + loanTermFrequency: this.loansAccountTermsData.termFrequency, + loanTermFrequencyType: this.loansAccountTermsData.termPeriodFrequencyType.id, + numberOfRepayments: this.loansAccountTermsData.numberOfRepayments, + repaymentEvery: this.loansAccountTermsData.repaymentEvery, + repaymentFrequencyType: this.loansAccountTermsData.repaymentFrequencyType.id, + amortizationType: this.loansAccountTermsData.amortizationType.id, + isEqualAmortization: this.loansAccountTermsData.isEqualAmortization, + interestType: this.loansAccountTermsData.interestType.id, + isFloatingInterestRate: this.loansAccountTermsData.isLoanProductLinkedToFloatingRate ? false : null, + interestCalculationPeriodType: this.loansAccountTermsData.interestCalculationPeriodType.id, + allowPartialPeriodInterestCalculation: this.loansAccountTermsData.allowPartialPeriodInterestCalculation, + inArrearsTolerance: this.loansAccountTermsData.inArrearsTolerance, + graceOnPrincipalPayment: this.loansAccountTermsData.graceOnPrincipalPayment, + graceOnInterestPayment: this.loansAccountTermsData.graceOnInterestPayment, + graceOnArrearsAgeing: this.loansAccountTermsData.graceOnArrearsAgeing, + graceOnInterestCharged: this.loansAccountTermsData.graceOnInterestCharged, + fixedEmiAmount: this.loansAccountTermsData.fixedEmiAmount, + maxOutstandingLoanBalance: this.loansAccountTermsData.maxOutstandingLoanBalance, + transactionProcessingStrategyCode: this.loansAccountTermsData.transactionProcessingStrategyCode, + interestRateDifferential: this.loansAccountTermsData.interestRateDifferential, + multiDisburseLoan: this.loansAccountTermsData.multiDisburseLoan, + interestRateFrequencyType: this.loansAccountTermsData.interestRateFrequencyType.id, + balloonRepaymentAmount: this.loansAccountTermsData.balloonRepaymentAmount, + interestRecognitionOnDisbursementDate: + this.loansAccountTermsData.interestRecognitionOnDisbursementDate || false, + moratoriumPrincipal: this.loansAccountTermsData.moratoriumPrincipal ?? 0, + moratoriumInterest: this.loansAccountTermsData.moratoriumInterest ?? 0 }); } - this.loansAccountTermsForm.patchValue({ - principalAmount: this.loansAccountTermsData.principal, - loanTermFrequency: this.loansAccountTermsData.termFrequency, - loanTermFrequencyType: this.loansAccountTermsData.termPeriodFrequencyType.id, - numberOfRepayments: this.loansAccountTermsData.numberOfRepayments, - repaymentEvery: this.loansAccountTermsData.repaymentEvery, - repaymentFrequencyType: this.loansAccountTermsData.repaymentFrequencyType.id, - amortizationType: this.loansAccountTermsData.amortizationType.id, - isEqualAmortization: this.loansAccountTermsData.isEqualAmortization, - interestType: this.loansAccountTermsData.interestType.id, - isFloatingInterestRate: this.loansAccountTermsData.isLoanProductLinkedToFloatingRate ? false : null, - interestCalculationPeriodType: this.loansAccountTermsData.interestCalculationPeriodType.id, - allowPartialPeriodInterestCalculation: this.loansAccountTermsData.allowPartialPeriodInterestCalculation, - inArrearsTolerance: this.loansAccountTermsData.inArrearsTolerance, - graceOnPrincipalPayment: this.loansAccountTermsData.graceOnPrincipalPayment, - graceOnInterestPayment: this.loansAccountTermsData.graceOnInterestPayment, - graceOnArrearsAgeing: this.loansAccountTermsData.graceOnArrearsAgeing, - graceOnInterestCharged: this.loansAccountTermsData.graceOnInterestCharged, - fixedEmiAmount: this.loansAccountTermsData.fixedEmiAmount, - maxOutstandingLoanBalance: this.loansAccountTermsData.maxOutstandingLoanBalance, - transactionProcessingStrategyCode: this.loansAccountTermsData.transactionProcessingStrategyCode, - interestRateDifferential: this.loansAccountTermsData.interestRateDifferential, - multiDisburseLoan: this.loansAccountTermsData.multiDisburseLoan, - interestRateFrequencyType: this.loansAccountTermsData.interestRateFrequencyType.id, - balloonRepaymentAmount: this.loansAccountTermsData.balloonRepaymentAmount, - interestRecognitionOnDisbursementDate: this.loansAccountTermsData.interestRecognitionOnDisbursementDate || false - }); - } - this.createloansAccountTermsForm(); - this.setAdvancedPaymentStrategyControls(); - // this.setCustomValidators(); - this.setLoanTermListener(); + this.setAdvancedPaymentStrategyControls(); + // this.setCustomValidators(); + this.setLoanTermListener(); - this.loansAccountTermsForm.removeControl('maxOutstandingLoanBalance'); - if (this.allowAddDisbursementDetails()) { this.loansAccountTermsForm.removeControl('maxOutstandingLoanBalance'); - this.loansAccountTermsForm.addControl( - 'maxOutstandingLoanBalance', - new UntypedFormControl(this.loansAccountTermsData?.maxOutstandingLoanBalance ?? null, Validators.required) - ); - } else { - this.loansAccountTermsForm.addControl( - 'maxOutstandingLoanBalance', - new UntypedFormControl(this.loansAccountTermsData?.maxOutstandingLoanBalance ?? null) - ); + if (this.allowAddDisbursementDetails()) { + this.loansAccountTermsForm.removeControl('maxOutstandingLoanBalance'); + this.loansAccountTermsForm.addControl( + 'maxOutstandingLoanBalance', + new UntypedFormControl(this.loansAccountTermsData?.maxOutstandingLoanBalance ?? null, Validators.required) + ); + } else { + this.loansAccountTermsForm.addControl( + 'maxOutstandingLoanBalance', + new UntypedFormControl(this.loansAccountTermsData?.maxOutstandingLoanBalance ?? null) + ); + } } } - allowAddDisbursementDetails() { + allowAddDisbursementDetails(): boolean { return this.multiDisburseLoan && !this.loansAccountTermsData.disallowExpectedDisbursements; } @@ -380,7 +383,7 @@ export class LoansAccountTermsStepComponent implements OnInit, OnChanges { } /** Custom Validators for the form */ - setCustomValidators() { + setCustomValidators(): void { const repaymentFrequencyNthDayType = this.loansAccountTermsForm.get('repaymentFrequencyNthDayType'); const repaymentFrequencyDayOfWeekType = this.loansAccountTermsForm.get('repaymentFrequencyDayOfWeekType'); @@ -399,7 +402,7 @@ export class LoansAccountTermsStepComponent implements OnInit, OnChanges { } /** Custom Listeners for the form to calculate Loan Term */ - setLoanTermListener() { + setLoanTermListener(): void { this.loansAccountTermsForm.get('numberOfRepayments').valueChanges.subscribe((numberOfRepayments) => { const repaymentEvery: number = this.loansAccountTermsForm.value.repaymentEvery; this.calculateLoanTerm(numberOfRepayments, repaymentEvery); @@ -517,7 +520,9 @@ export class LoansAccountTermsStepComponent implements OnInit, OnChanges { multiDisburseLoan: [false], interestRateFrequencyType: [''], balloonRepaymentAmount: [''], - interestRecognitionOnDisbursementDate: [false] + interestRecognitionOnDisbursementDate: [false], + moratoriumPrincipal: [0], + moratoriumInterest: [0] }); } diff --git a/src/app/login/login-form/login-form.component.ts b/src/app/login/login-form/login-form.component.ts index dcf93cae15..445179c0fd 100644 --- a/src/app/login/login-form/login-form.component.ts +++ b/src/app/login/login-form/login-form.component.ts @@ -10,7 +10,7 @@ import { AuthenticationService } from '../../core/authentication/authentication. import { MatFormField, MatPrefix, MatLabel, MatError, MatSuffix } from '@angular/material/form-field'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { MatIconButton, MatButton } from '@angular/material/button'; -import { MatCheckbox } from '@angular/material/checkbox'; +import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatProgressBar } from '@angular/material/progress-bar'; import { MatProgressSpinner } from '@angular/material/progress-spinner'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; @@ -31,6 +31,7 @@ import { environment } from '../../../environments/environment'; MatPrefix, FaIconComponent, MatIconButton, + MatCheckboxModule, MatProgressBar, MatProgressSpinner ] diff --git a/src/app/web-app.component.ts b/src/app/web-app.component.ts index d70c97dafb..a2246812ca 100644 --- a/src/app/web-app.component.ts +++ b/src/app/web-app.component.ts @@ -90,8 +90,6 @@ registerLocaleData(localeSW); export class WebAppComponent implements OnInit, OnDestroy { buttonConfig: KeyboardShortcutsConfiguration; - i18nService: I18nService; - private authSubscription: Subscription; private destroy$ = new Subject(); @@ -123,7 +121,8 @@ export class WebAppComponent implements OnInit, OnDestroy { private dateUtils: Dates, private idle: IdleTimeoutService, private dialog: MatDialog, - private authService: AuthService + private authService: AuthService, + private i18nService: I18nService ) {} @HostBinding('class') public cssClass: string; @@ -165,8 +164,6 @@ export class WebAppComponent implements OnInit, OnDestroy { this.translateService.use(environment.defaultLanguage); } - this.i18nService = new I18nService(this.translateService); - // Change page title on navigation or language change, based on route data const onNavigationEnd = this.router.events.pipe(filter((event) => event instanceof NavigationEnd)); merge(this.translateService.onLangChange, onNavigationEnd)