From 033e132c04b6bdf0297fe3374d56de192f922394 Mon Sep 17 00:00:00 2001 From: Jose Alberto Hernandez Date: Mon, 2 Mar 2026 13:22:02 -0500 Subject: [PATCH] WEB-813: Working Capital loan account creation --- .../general-tab/general-tab.component.html | 54 +- .../general-tab/general-tab.component.ts | 26 +- .../shell/breadcrumb/breadcrumb.component.ts | 5 +- .../loan-action-button.resolver.ts | 6 +- .../common-resolvers/loan-details.resolver.ts | 13 +- .../loan-products.resolver.ts | 33 + .../create-loans-account.component.html | 209 +-- .../create-loans-account.component.ts | 223 ++- .../edit-loans-account.component.html | 43 +- .../edit-loans-account.component.ts | 104 +- .../loans-account-details-step.component.html | 96 +- .../loans-account-details-step.component.scss | 57 + .../loans-account-details-step.component.ts | 168 ++- .../loans-account-preview-step.component.html | 646 +++++---- .../loans-account-preview-step.component.ts | 31 +- .../loans-account-terms-step.component.html | 1247 +++++++++-------- .../loans-account-terms-step.component.ts | 223 ++- src/app/loans/loans-routing.module.ts | 9 +- .../account-details.component.html | 492 ++++--- .../account-details.component.ts | 9 +- .../charges-tab/charges-tab.component.ts | 26 +- .../external-asset-owner-tab.component.ts | 26 +- .../general-tab/general-tab.component.html | 67 +- .../general-tab/general-tab.component.ts | 49 +- .../add-collateral.component.html | 2 +- .../add-collateral.component.ts | 27 +- .../add-interest-pause.component.html | 2 +- .../add-interest-pause.component.ts | 29 +- .../add-loan-charge.component.html | 2 +- .../add-loan-charge.component.ts | 28 +- .../adjust-loan-charge.component.html | 21 +- .../adjust-loan-charge.component.ts | 43 +- .../approve-loan/approve-loan.component.html | 2 +- .../approve-loan/approve-loan.component.ts | 27 +- .../asset-transfer-loan.component.html | 2 +- .../asset-transfer-loan.component.ts | 18 +- .../assign-loan-officer.component.html | 2 +- .../assign-loan-officer.component.ts | 25 +- .../attach-originator.component.html | 2 +- .../attach-originator.component.ts | 18 +- .../charge-off/charge-off.component.html | 2 +- .../charge-off/charge-off.component.ts | 26 +- .../close-as-rescheduled.component.html | 2 +- .../close-as-rescheduled.component.ts | 26 +- .../create-guarantor.component.html | 2 +- .../create-guarantor.component.ts | 29 +- ...disburse-to-savings-account.component.html | 2 +- .../disburse-to-savings-account.component.ts | 31 +- .../disburse/disburse.component.html | 2 +- .../disburse/disburse.component.ts | 26 +- .../edit-repayment-schedule.component.html | 2 +- .../edit-repayment-schedule.component.ts | 32 +- .../foreclosure/foreclosure.component.html | 2 +- .../foreclosure/foreclosure.component.ts | 28 +- .../loan-account-actions-base.component.ts | 56 + .../loan-account-actions.component.ts | 4 +- .../loan-credit-balance-refund.component.html | 2 +- .../loan-credit-balance-refund.component.ts | 28 +- .../loan-reaging/loan-reaging.component.html | 2 +- .../loan-reaging/loan-reaging.component.ts | 19 +- .../loan-reamortize.component.html | 2 +- .../loan-reamortize.component.ts | 19 +- .../loan-reschedule.component.html | 2 +- .../loan-reschedule.component.ts | 29 +- .../loan-screen-reports.component.html | 2 +- .../loan-screen-reports.component.ts | 18 +- .../loans-account-close.component.html | 2 +- .../loans-account-close.component.ts | 34 +- .../make-repayment.component.html | 2 +- .../make-repayment.component.ts | 19 +- .../prepay-loan/prepay-loan.component.html | 2 +- .../prepay-loan/prepay-loan.component.ts | 34 +- .../recovery-repayment.component.html | 2 +- .../recovery-repayment.component.ts | 32 +- .../reject-loan/reject-loan.component.html | 2 +- .../reject-loan/reject-loan.component.ts | 24 +- .../undo-approval.component.html | 2 +- .../undo-approval/undo-approval.component.ts | 23 +- .../undo-disbursal.component.html | 2 +- .../undo-disbursal.component.ts | 21 +- .../undo-write-off.component.html | 2 +- .../undo-write-off.component.ts | 23 +- .../view-guarantors.component.ts | 44 +- .../waive-interest.component.html | 2 +- .../waive-interest.component.ts | 25 +- .../withdrawn-by-client.component.html | 2 +- .../withdrawn-by-client.component.ts | 28 +- .../write-off-page.component.html | 2 +- .../write-off-page.component.ts | 29 +- .../loan-account-dashboard.component.scss | 6 - .../loan-account-tab-base.component.ts | 29 + .../loan-originators-tab.component.ts | 17 +- .../loan-term-variations-tab.component.ts | 19 +- .../loan-tranche-details.component.ts | 14 +- .../loans-view/loans-view.component.html | 142 +- .../loans/loans-view/loans-view.component.ts | 48 +- .../reschedule-loan-tab.component.ts | 17 +- .../transactions-tab.component.ts | 20 +- .../edit-transaction.component.ts | 24 +- .../view-transaction.component.ts | 31 +- .../view-charge/view-charge.component.ts | 26 +- src/app/loans/loans.service.ts | 25 +- .../loan-product.model.ts} | 11 + .../common/loan-product-base.component.ts | 21 + .../loan-product-summary.component.html | 4 - .../create-loan-product.component.ts | 3 +- .../edit-loan-product.component.ts | 3 +- .../loan-product-settings-step.component.html | 3 - .../loan-product-settings-step.component.ts | 4 - .../loan-products/loan-products.component.ts | 3 +- .../services/loan-product.service.ts | 18 +- src/app/products/products.service.ts | 7 + src/app/shared/footer/footer.component.ts | 2 + .../shared/long-text/long-text.component.html | 2 - .../shared/long-text/long-text.component.ts | 4 +- src/assets/translations/cs-CS.json | 10 +- src/assets/translations/de-DE.json | 10 +- src/assets/translations/en-US.json | 10 +- src/assets/translations/es-CL.json | 10 +- src/assets/translations/es-MX.json | 10 +- src/assets/translations/fr-FR.json | 10 +- src/assets/translations/it-IT.json | 10 +- src/assets/translations/ko-KO.json | 10 +- src/assets/translations/lt-LT.json | 10 +- src/assets/translations/lv-LV.json | 10 +- src/assets/translations/ne-NE.json | 10 +- src/assets/translations/pt-PT.json | 10 +- src/assets/translations/sw-SW.json | 12 +- 128 files changed, 3087 insertions(+), 2413 deletions(-) create mode 100644 src/app/loans/common-resolvers/loan-products.resolver.ts create mode 100644 src/app/loans/loans-view/loan-account-actions/loan-account-actions-base.component.ts create mode 100644 src/app/loans/loans-view/loan-account-tab-base.component.ts rename src/app/loans/{loans-view/loan-account-actions/loan-account-actions.component.scss => models/loan-product.model.ts} (52%) diff --git a/src/app/clients/clients-view/general-tab/general-tab.component.html b/src/app/clients/clients-view/general-tab/general-tab.component.html index 6ff73a94dc..87a732ad4b 100644 --- a/src/app/clients/clients-view/general-tab/general-tab.component.html +++ b/src/app/clients/clients-view/general-tab/general-tab.component.html @@ -153,6 +153,12 @@

{{ 'labels.heading.Loan Accounts' | translate }}

+ + {{ 'labels.inputs.Product Type' | translate }} + + {{ loanProductTypeLabel(element.productType) | translate }} + + {{ 'labels.inputs.Loan Product' | translate }} @@ -180,29 +186,19 @@

{{ 'labels.heading.Loan Accounts' | translate }}

{{ 'labels.inputs.Type' | translate }} - + @if (element.productType === 'loan') { + + } {{ 'labels.inputs.Actions' | translate }} - - @if (element.status.active) { - + @@ -368,6 +359,7 @@

{{ 'labels.heading.Loan Accounts' | translate }}

mat-row *matRowDef="let row; columns: closedLoansColumns" [routerLink]="['../', 'loans-accounts', row.id, 'general']" + [queryParams]="{ productType: row.productType }" class="select-row" > { this.clientAccountData = data.clientAccountsData; this.savingAccounts = data.clientAccountsData?.savingsAccounts ?? []; - this.loanAccounts = data.clientAccountsData?.loanAccounts ?? []; + this.loanAccounts = []; + this.processLoanAccounts(data.clientAccountsData?.loanAccounts ?? [], 'loan'); + this.processLoanAccounts(data.clientAccountsData?.workingCapitalLoanAccounts ?? [], 'working-capital'); + this.workingCapitalLoanAccounts = data.clientAccountsData?.workingCapitalLoanAccounts ?? []; this.shareAccounts = data.clientAccountsData?.shareAccounts ?? []; this.upcomingCharges = data.clientChargesData?.pageItems ?? []; @@ -417,4 +424,17 @@ export class GeneralTabComponent implements OnDestroy { return 'labels.buttons.View Closed Accounts'; } } + + loanProductTypeLabel(productType: string): string { + return LoanProductService.productTypeLabel(productType); + } + + private processLoanAccounts(accounts: any[], productType: string): void { + accounts.map((account: any) => { + this.loanAccounts.push({ + productType: productType, + ...account + }); + }); + } } diff --git a/src/app/core/shell/breadcrumb/breadcrumb.component.ts b/src/app/core/shell/breadcrumb/breadcrumb.component.ts index d12fb6a040..fd1f35b5d2 100644 --- a/src/app/core/shell/breadcrumb/breadcrumb.component.ts +++ b/src/app/core/shell/breadcrumb/breadcrumb.component.ts @@ -8,7 +8,7 @@ /** Angular Imports */ import { Component, TemplateRef, ElementRef, ViewChild, AfterViewInit, OnDestroy, inject } from '@angular/core'; -import { ActivatedRoute, Router, NavigationEnd, Data, RouterLink } from '@angular/router'; +import { ActivatedRoute, Router, NavigationEnd, Data } from '@angular/router'; /** rxjs Imports */ import { filter, takeUntil } from 'rxjs/operators'; @@ -243,6 +243,9 @@ export class BreadcrumbComponent implements AfterViewInit, OnDestroy { } printableValue(value: string): string { + if (!value) { + return ''; + } if (value.length <= 30) { return value; } diff --git a/src/app/loans/common-resolvers/loan-action-button.resolver.ts b/src/app/loans/common-resolvers/loan-action-button.resolver.ts index 02e6992013..b8974f3269 100644 --- a/src/app/loans/common-resolvers/loan-action-button.resolver.ts +++ b/src/app/loans/common-resolvers/loan-action-button.resolver.ts @@ -17,6 +17,7 @@ import { catchError } from 'rxjs/operators'; /** Custom Services */ import { LoansService } from '../loans.service'; import { OrganizationService } from 'app/organization/organization.service'; +import { LoanProductService } from 'app/products/loan-products/services/loan-product.service'; /** * Loans notes data resolver. @@ -25,6 +26,7 @@ import { OrganizationService } from 'app/organization/organization.service'; export class LoanActionButtonResolver { private loansService = inject(LoansService); private organizationService = inject(OrganizationService); + private loanProductService = inject(LoanProductService); /** * Returns the Loans Notes Data. @@ -74,7 +76,9 @@ export class LoanActionButtonResolver { } else if (loanActionButton === 'Loan Screen Reports') { return this.loansService.getLoanScreenReportsData(); } else if (loanActionButton === 'Approve') { - return this.loansService.getLoanApprovalTemplate(loanId); + return this.loanProductService.isLoanProduct + ? this.loansService.getLoanApprovalTemplate(loanId) + : this.loansService.getWorkingCapitalLoanActionTemplate(loanId, loanActionButton.toLowerCase()); } else if (loanActionButton === 'Add Loan Charge') { return this.loansService.getLoanChargeTemplateResource(loanId); } else if (loanActionButton === 'Foreclosure') { diff --git a/src/app/loans/common-resolvers/loan-details.resolver.ts b/src/app/loans/common-resolvers/loan-details.resolver.ts index f249fcde3f..a3cb4d8866 100644 --- a/src/app/loans/common-resolvers/loan-details.resolver.ts +++ b/src/app/loans/common-resolvers/loan-details.resolver.ts @@ -15,6 +15,8 @@ import { Observable } from 'rxjs'; /** Custom Services */ import { LoansService } from '../loans.service'; +import { LoanProductService } from 'app/products/loan-products/services/loan-product.service'; +import { LOAN_PRODUCT_TYPE } from 'app/products/loan-products/models/loan-product.model'; /** * Clients data resolver. @@ -22,6 +24,7 @@ import { LoansService } from '../loans.service'; @Injectable() export class LoanDetailsResolver { private loansService = inject(LoansService); + private loanProductService = inject(LoanProductService); /** * Returns the Loans with Association data. @@ -29,8 +32,16 @@ export class LoanDetailsResolver { */ resolve(route: ActivatedRouteSnapshot): Observable { const loanId = route.paramMap.get('loanId') || route.parent.paramMap.get('loanId'); + const productType = route.queryParams['productType']; + const resolvedProductType = + productType === LOAN_PRODUCT_TYPE.WORKING_CAPITAL ? LOAN_PRODUCT_TYPE.WORKING_CAPITAL : LOAN_PRODUCT_TYPE.LOAN; + this.loanProductService.initialize(resolvedProductType); if (!isNaN(+loanId)) { - return this.loansService.getLoanAccountAssociationDetails(loanId); + if (resolvedProductType === LOAN_PRODUCT_TYPE.LOAN) { + return this.loansService.getLoanAccountAssociationDetails(loanId); + } else { + return this.loansService.getWorkingCapitalLoannDetails(loanId); + } } } } diff --git a/src/app/loans/common-resolvers/loan-products.resolver.ts b/src/app/loans/common-resolvers/loan-products.resolver.ts new file mode 100644 index 0000000000..6844169eee --- /dev/null +++ b/src/app/loans/common-resolvers/loan-products.resolver.ts @@ -0,0 +1,33 @@ +/** + * Copyright since 2025 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/** Angular Imports */ +import { Injectable, inject } from '@angular/core'; +import { ActivatedRouteSnapshot } from '@angular/router'; + +/** rxjs Imports */ +import { Observable } from 'rxjs'; + +/** Custom Services */ +import { ProductsService } from 'app/products/products.service'; + +/** + * Loan Product list data resolver. + */ +@Injectable() +export class LoanProductsResolver { + private productsService = inject(ProductsService); + + /** + * Returns the loan account template data. + * @returns {Observable} + */ + resolve(route: ActivatedRouteSnapshot): Observable { + return this.productsService.getLoanProductsBasicDetails(); + } +} diff --git a/src/app/loans/create-loans-account/create-loans-account.component.html b/src/app/loans/create-loans-account/create-loans-account.component.html index 1f438bbef0..eea84d5ab7 100644 --- a/src/app/loans/create-loans-account/create-loans-account.component.html +++ b/src/app/loans/create-loans-account/create-loans-account.component.html @@ -7,103 +7,124 @@ -->
- - - - - - - - - - - - - - - - - - - - - - - {{ 'labels.inputs.DETAILS' | translate }} - - - - - - - {{ 'labels.inputs.TERMS' | translate }} - - - - - - - {{ 'labels.inputs.CHARGES' | translate }} - - - - - - @if (loansAccountFormValid) { - - {{ 'labels.inputs.REPAYMENT SCHEDULE' | translate }} - - - - } + @if (loanProductsBasicDetails.length > 0) { + + + + - @for (datatable of datatables; track datatable) { - - {{ datatable.registeredTableName }} - - - } + + + + + + + + + + + + + + + + + + {{ 'labels.inputs.DETAILS' | translate }} - @if (loansAccountFormValid) { - - {{ 'labels.inputs.PREVIEW' | translate }} - - + - } - + + @if (productId) { + + {{ 'labels.inputs.TERMS' | translate }} + + + + + + @if (loanProductService.isLoanProduct) { + + {{ 'labels.inputs.CHARGES' | translate }} + + + + + + @if (loansAccountFormValid) { + + {{ 'labels.inputs.REPAYMENT SCHEDULE' | translate }} + + + + } + + @for (datatable of datatables; track datatable) { + + {{ datatable.registeredTableName }} + + + } + } + + @if (loansAccountFormValid) { + + {{ 'labels.inputs.PREVIEW' | translate }} + + + + } + } + + } + + @if (loanProductsBasicDetails.length === 0) { +
+
+ + {{ 'labels.text.No Loan Product was found' | translate }} +
+
+ }
diff --git a/src/app/loans/create-loans-account/create-loans-account.component.ts b/src/app/loans/create-loans-account/create-loans-account.component.ts index 14cb149fd8..0f2b68e3ab 100644 --- a/src/app/loans/create-loans-account/create-loans-account.component.ts +++ b/src/app/loans/create-loans-account/create-loans-account.component.ts @@ -7,8 +7,8 @@ */ /** Angular Imports */ -import { Component, QueryList, ViewChild, ViewChildren, inject } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; +import { AfterViewInit, ChangeDetectorRef, Component, QueryList, ViewChild, ViewChildren, inject } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; /** Custom Services */ import { LoansService } from '../loans.service'; @@ -25,6 +25,9 @@ import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { LoansAccountScheduleStepComponent } from '../loans-account-stepper/loans-account-schedule-step/loans-account-schedule-step.component'; import { LoansAccountPreviewStepComponent } from '../loans-account-stepper/loans-account-preview-step/loans-account-preview-step.component'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; +import { LoanProductBasicDetails } from '../models/loan-product.model'; +import { LoanProductBaseComponent } from 'app/products/loan-products/common/loan-product-base.component'; +import { Dates } from 'app/core/utils/dates'; /** * Create loans account @@ -48,18 +51,19 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; LoansAccountPreviewStepComponent ] }) -export class CreateLoansAccountComponent { +export class CreateLoansAccountComponent extends LoanProductBaseComponent implements AfterViewInit { private route = inject(ActivatedRoute); - private router = inject(Router); private loansService = inject(LoansService); private settingsService = inject(SettingsService); private clientService = inject(ClientsService); + private cdr = inject(ChangeDetectorRef); + private dateUtils = inject(Dates); /** Imports all the step component */ - @ViewChild(LoansAccountDetailsStepComponent, { static: true }) + @ViewChild(LoansAccountDetailsStepComponent, { static: false }) loansAccountDetailsStep: LoansAccountDetailsStepComponent; - @ViewChild(LoansAccountTermsStepComponent, { static: true }) loansAccountTermsStep: LoansAccountTermsStepComponent; - @ViewChild(LoansAccountChargesStepComponent, { static: true }) + @ViewChild(LoansAccountTermsStepComponent, { static: false }) loansAccountTermsStep: LoansAccountTermsStepComponent; + @ViewChild(LoansAccountChargesStepComponent, { static: false }) loansAccountChargesStep: LoansAccountChargesStepComponent; /** Get handle on dtloan tags in the template */ @ViewChildren('dtloan') loanDatatables: QueryList; @@ -78,6 +82,13 @@ export class CreateLoansAccountComponent { /** Currency Code */ currencyCode: string; + clientId: number | null = null; + productId: number | null = null; + productDetails: any; + + loanProductsBasicDetails: LoanProductBasicDetails[] | null = null; + productType: string | null = null; + /** * Sets loans account create form. * @param {route} ActivatedRoute Activated Route. @@ -87,38 +98,60 @@ export class CreateLoansAccountComponent { * @param {ClientsService} clientService Client Service */ constructor() { - this.route.data.subscribe((data: { loansAccountTemplate: any }) => { - this.loansAccountTemplate = data.loansAccountTemplate; - }); + super(); + this.loanProductsBasicDetails = []; + this.route.data.subscribe( + (data: { loansAccountTemplate: any; loanProductsBasicDetails: LoanProductBasicDetails[] }) => { + this.loanProductsBasicDetails = data.loanProductsBasicDetails; + this.loansAccountTemplate = data.loansAccountTemplate; + } + ); + } + + ngAfterViewInit() { + this.cdr.detectChanges(); } /** * Sets loans account product template and collateral template * @param {any} $event API response */ - setTemplate($event: any) { - this.loansAccountProductTemplate = $event; + setTemplate($event: any): void { + const templateData: any = $event; + this.loansAccountProductTemplate = templateData; + if (templateData.loanData) { + this.loansAccountProductTemplate = templateData.loanData; + this.loansAccountProductTemplate.options = { + delinquencyBucketOptions: templateData.delinquencyBucketOptions, + fundOptions: templateData.fundOptions, + periodFrequencyTypeOptions: templateData.periodFrequencyTypeOptions + }; + } this.currencyCode = this.loansAccountProductTemplate.currency.code; - const clientId = this.loansAccountTemplate.clientId; - if (!!clientId) { - this.clientService.getCollateralTemplate(clientId).subscribe((response: any) => { - this.collateralOptions = response; - }); - } else { - // Fineract API doesn't have "Group Collateral Management" endpoint; from the obsolete - // community app it appears getCollateralTemplate(clientId) is called as well, but it's not clear how - // the clientId is selected from the clientIds that belong to the group. - console.error('No collateral data requested from Fineract, collateral might misbehave'); + this.productId = this.loansAccountProductTemplate.product.id; + this.productDetails = this.loansAccountProductTemplate.product; + + if (this.loanProductService.isLoanProduct) { + const clientId = this.loansAccountTemplate.clientId; + if (!!clientId) { + this.clientService.getCollateralTemplate(clientId).subscribe((response: any) => { + this.collateralOptions = response; + }); + } else { + // Fineract API doesn't have "Group Collateral Management" endpoint; from the obsolete + // community app it appears getCollateralTemplate(clientId) is called as well, but it's not clear how + // the clientId is selected from the clientIds that belong to the group. + console.error('No collateral data requested from Fineract, collateral might misbehave'); + } + this.multiDisburseLoan = this.loansAccountProductTemplate.multiDisburseLoan; + this.setDatatables(); } - const entityId = this.loansAccountTemplate.clientId - ? this.loansAccountTemplate.clientId - : this.loansAccountTemplate.group.id; - const isGroup = this.loansAccountTemplate.clientId ? false : true; - const productId = this.loansAccountProductTemplate.loanProductId; - this.loansService.getLoansAccountTemplateResource(entityId, isGroup, productId).subscribe((response: any) => { - this.multiDisburseLoan = response.multiDisburseLoan; - }); - this.setDatatables(); + this.cdr.detectChanges(); + } + + setProductType($event: any): void { + this.productType = $event; + this.loanProductService.initialize(this.productType); } setDatatables(): void { @@ -133,43 +166,60 @@ export class CreateLoansAccountComponent { /** Get Loans Account Details Form Data */ get loansAccountDetailsForm() { - return this.loansAccountDetailsStep.loansAccountDetailsForm; + return this.loansAccountDetailsStep?.loansAccountDetailsForm; } /** Get Loans Account Terms Form Data */ get loansAccountTermsForm() { - return this.loansAccountTermsStep.loansAccountTermsForm; + return this.loansAccountTermsStep?.loansAccountTermsForm; } /** Checks wheter all the forms in different steps are valid or not */ get loansAccountFormValid() { - return this.loansAccountDetailsForm.valid && this.loansAccountTermsForm.valid; + return this.loansAccountDetailsForm?.valid && this.loansAccountTermsForm?.valid; } get loansSavingsAccountLinked() { - return this.loansAccountDetailsStep.loansAccountDetailsForm.get('linkAccountId').value; + if (this.loanProductService.isLoanProduct) { + return this.loansAccountDetailsStep?.loansAccountDetailsForm.get('linkAccountId').value; + } + return null; } /** Gets principal Amount */ get loanPrincipal() { - return this.loansAccountTermsStep.loansAccountTermsForm.value.principal; + return this.loansAccountTermsStep?.loansAccountTermsForm.value.principal; } /** Retrieves Data of all forms except Currency to submit the data */ get loansAccount() { - return { - ...this.loansAccountDetailsStep.loansAccountDetails, - ...this.loansAccountTermsStep.loansAccountTerms, - ...this.loansAccountChargesStep.loansAccountCharges, - ...this.loansAccountTermsStep.loanCollateral, - ...this.loansAccountTermsStep.disbursementData - }; + if (this.loanProductService.isLoanProduct) { + return { + ...this.loansAccountDetailsStep.loansAccountDetails, + ...this.loansAccountTermsStep?.loansAccountTerms, + ...this.loansAccountChargesStep?.loansAccountCharges, + ...this.loansAccountTermsStep?.loanCollateral, + ...this.loansAccountTermsStep?.disbursementData + }; + } else if (this.loanProductService.isWorkingCapital) { + return { + ...this.loansAccountDetailsStep.loansAccountDetails, + ...this.loansAccountTermsStep?.loansAccountTerms + }; + } + console.warn('Unexpected product type in loansAccount getter'); + return {}; } - /** - * Submits Data to create loan account - */ - submit() { + submit(): void { + if (this.loanProductService.isLoanProduct) { + this.submitLoanProduct(); + } else if (this.loanProductService.isWorkingCapital) { + this.submitWorkingCapitalProduct(); + } + } + + submitLoanProduct() { const locale = this.settingsService.language.code; const dateFormat = this.settingsService.dateFormat; const payload = this.loansService.buildLoanRequestPayload( @@ -188,15 +238,74 @@ export class CreateLoansAccountComponent { payload['datatables'] = datatables; } - this.loansService.createLoansAccount(payload).subscribe((response: any) => { - this.router.navigate( - [ - '../', - response.resourceId, - 'general' - ], - { relativeTo: this.route } - ); - }); + this.loansService + .createLoansAccount(this.loanProductService.loanAccountPath, payload) + .subscribe((response: any) => { + this.router.navigate( + [ + '../', + response.resourceId, + 'general' + ], + { + queryParams: { + productType: this.loanProductService.productType.value + }, + relativeTo: this.route + } + ); + }); + } + + submitWorkingCapitalProduct() { + const locale = this.settingsService.language.code; + const dateFormat = this.settingsService.dateFormat; + const payload = { + ...this.loansAccount, + clientId: this.loansAccountProductTemplate.client.id, + submittedOnDate: this.dateUtils.formatDate(this.loansAccount.submittedOnDate, dateFormat), + expectedDisbursementDate: this.dateUtils.formatDate(this.loansAccount.expectedDisbursementDate, dateFormat), + locale, + dateFormat + }; + + if (this.productDetails.allowAttributeOverrides) { + if ( + !Object.hasOwn(this.productDetails.allowAttributeOverrides, 'periodPaymentFrequency') || + this.productDetails.allowAttributeOverrides.periodPaymentFrequency === false + ) { + delete payload['repaymentEvery']; + } + if ( + !Object.hasOwn(this.productDetails.allowAttributeOverrides, 'periodPaymentFrequencyType') || + this.productDetails.allowAttributeOverrides.periodPaymentFrequencyType === false + ) { + delete payload['repaymentFrequencyType']; + } + if ( + !Object.hasOwn(this.productDetails.allowAttributeOverrides, 'discountDefault') || + this.productDetails.allowAttributeOverrides.discountDefault === false + ) { + delete payload['discount']; + } + } + + this.loansService + .createLoansAccount(this.loanProductService.loanAccountPath, payload) + .subscribe((response: any) => { + this.router.navigate( + [ + '../', + response.resourceId, + 'general' + ], + { + queryParams: { + productType: this.loanProductService.productType.value + }, + relativeTo: this.route + } + ); + }); } } diff --git a/src/app/loans/edit-loans-account/edit-loans-account.component.html b/src/app/loans/edit-loans-account/edit-loans-account.component.html index 4d34068360..716e3974f4 100644 --- a/src/app/loans/edit-loans-account/edit-loans-account.component.html +++ b/src/app/loans/edit-loans-account/edit-loans-account.component.html @@ -39,7 +39,9 @@ @@ -55,28 +57,30 @@ - - {{ 'labels.inputs.CHARGES' | translate }} + @if (loanProductService.isLoanProduct) { + + {{ 'labels.inputs.CHARGES' | translate }} - - - + + + - - {{ 'labels.inputs.REPAYMENT SCHEDULE' | translate }} + + {{ 'labels.inputs.REPAYMENT SCHEDULE' | translate }} - - - + + + + } @if (loansAccountFormValidAndNotPristine) { @@ -85,6 +89,7 @@ [loansAccountTemplate]="loansAccountAndTemplate" [loansAccountProductTemplate]="loansAccountProductTemplate" [loansAccount]="loansAccount" + [loanProductsBasicDetails]="loanProductsBasicDetails" (submitEvent)="submit()" > diff --git a/src/app/loans/edit-loans-account/edit-loans-account.component.ts b/src/app/loans/edit-loans-account/edit-loans-account.component.ts index 21550def52..0c3070191d 100644 --- a/src/app/loans/edit-loans-account/edit-loans-account.component.ts +++ b/src/app/loans/edit-loans-account/edit-loans-account.component.ts @@ -7,7 +7,7 @@ */ import { Component, ViewChild, inject } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; +import { ActivatedRoute } from '@angular/router'; import { LoansService } from '../loans.service'; import { LoansAccountDetailsStepComponent } from '../loans-account-stepper/loans-account-details-step/loans-account-details-step.component'; import { LoansAccountTermsStepComponent } from '../loans-account-stepper/loans-account-terms-step/loans-account-terms-step.component'; @@ -21,6 +21,8 @@ import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { LoansAccountScheduleStepComponent } from '../loans-account-stepper/loans-account-schedule-step/loans-account-schedule-step.component'; import { LoansAccountPreviewStepComponent } from '../loans-account-stepper/loans-account-preview-step/loans-account-preview-step.component'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; +import { LoanProductBasicDetails } from '../models/loan-product.model'; +import { LoanProductBaseComponent } from 'app/products/loan-products/common/loan-product-base.component'; /** * Edit Loans @@ -43,9 +45,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; LoansAccountPreviewStepComponent ] }) -export class EditLoansAccountComponent { +export class EditLoansAccountComponent extends LoanProductBaseComponent { private route = inject(ActivatedRoute); - private router = inject(Router); private dateUtils = inject(Dates); private loansService = inject(LoansService); private settingsService = inject(SettingsService); @@ -66,18 +67,23 @@ export class EditLoansAccountComponent { /** Currency Code */ currencyCode: string; - /** - * Sets loans account edit form. - * @param {route} ActivatedRoute Activated Route. - * @param {router} Router Router. - * @param {Dates} dateUtils Date Utils - * @param {loansService} LoansService Loans Service - * @param {SettingsService} settingsService Settings Service - */ + productId: number | null = null; + productDetails: any; + + loanProductsBasicDetails: LoanProductBasicDetails[] | null = null; + productType: string | null = null; + constructor() { - this.route.data.subscribe((data: { loansAccountAndTemplate: any }) => { - this.loansAccountAndTemplate = data.loansAccountAndTemplate; - }); + super(); + this.loanProductService.initialize(LoanProductBaseComponent.resolveProductTypeDefault(this.route, 'loan')); + + this.route.data.subscribe( + (data: { loansAccountAndTemplate: any; loanProductsBasicDetails: LoanProductBasicDetails[] }) => { + this.loansAccountAndTemplate = data.loansAccountAndTemplate; + this.loansAccountProductTemplate = data.loansAccountAndTemplate; + this.loanProductsBasicDetails = data.loanProductsBasicDetails; + } + ); this.loanId = this.route.snapshot.params['loanId']; } @@ -86,7 +92,8 @@ export class EditLoansAccountComponent { * @param {any} $event API response */ setTemplate($event: any) { - this.loansAccountProductTemplate = $event; + const templateData: any = $event; + this.loansAccountProductTemplate = templateData.loanData ? templateData.loanData : templateData; this.currencyCode = this.loansAccountProductTemplate.currency.code; if (this.loansAccountProductTemplate.loanProductId) { this.loansService @@ -97,6 +104,11 @@ export class EditLoansAccountComponent { } } + setProductType($event: any): void { + this.productType = $event; + this.loanProductService.initialize(this.productType); + } + /** Get Loans Account Details Form Data */ get loansAccountDetailsForm() { return this.loansAccountDetailsStep.loansAccountDetailsForm; @@ -109,31 +121,52 @@ export class EditLoansAccountComponent { /** Checks wheter all the forms in different steps are valid and not pristine */ get loansAccountFormValidAndNotPristine() { - return ( - this.loansAccountDetailsForm.valid && - this.loansAccountTermsForm.valid && - (!this.loansAccountDetailsForm.pristine || - !this.loansAccountTermsForm.pristine || - !this.loansAccountTermsStep.pristine || - !this.loansAccountChargesStep.pristine) - ); + if (this.loanProductService.isLoanProduct) { + return ( + this.loansAccountDetailsForm.valid && + this.loansAccountTermsForm.valid && + (!this.loansAccountDetailsForm.pristine || + !this.loansAccountTermsForm.pristine || + !this.loansAccountTermsStep.pristine || + !this.loansAccountChargesStep?.pristine) + ); + } else if (this.loanProductService.isWorkingCapital) { + return false; + } } /** Retrieves Data of all forms except Currency to submit the data */ get loansAccount() { - return { - ...this.loansAccountDetailsStep.loansAccountDetails, - ...this.loansAccountTermsStep.loansAccountTerms, - ...this.loansAccountChargesStep.loansAccountCharges, - ...this.loansAccountTermsStep.loanCollateral, - ...this.loansAccountTermsStep.disbursementData - }; + if (this.loanProductService.isLoanProduct) { + return { + ...this.loansAccountDetailsStep.loansAccountDetails, + ...this.loansAccountTermsStep.loansAccountTerms, + ...this.loansAccountChargesStep?.loansAccountCharges, + ...this.loansAccountTermsStep.loanCollateral, + ...this.loansAccountTermsStep.disbursementData + }; + } else if (this.loanProductService.isWorkingCapital) { + return { + ...this.loansAccountDetailsStep.loansAccountDetails, + ...this.loansAccountTermsStep.loansAccountTerms + }; + } + console.warn('Unexpected product type in loansAccount getter'); + return {}; + } + + submit(): void { + if (this.loanProductService.isLoanProduct) { + this.submitLoanProduct(); + } else if (this.loanProductService.isWorkingCapital) { + this.submitWorkingCapitalProduct(); + } } /** * Submits Data to create loan account */ - submit() { + submitLoanProduct() { const locale = this.settingsService.language.code; const dateFormat = this.settingsService.dateFormat; const loanType = 'individual'; @@ -209,7 +242,14 @@ export class EditLoansAccountComponent { delete loansAccountData.allowPartialPeriodInterestCalculation; this.loansService.updateLoansAccount(this.loanId, loansAccountData).subscribe((response: any) => { - this.router.navigate(['../'], { relativeTo: this.route }); + this.router.navigate(['../'], { + queryParams: { + productType: this.loanProductService.productType.value + }, + relativeTo: this.route + }); }); } + + submitWorkingCapitalProduct(): void {} } diff --git a/src/app/loans/loans-account-stepper/loans-account-details-step/loans-account-details-step.component.html b/src/app/loans/loans-account-stepper/loans-account-details-step/loans-account-details-step.component.html index 8d89046f19..6a14459cdb 100644 --- a/src/app/loans/loans-account-stepper/loans-account-details-step/loans-account-details-step.component.html +++ b/src/app/loans/loans-account-stepper/loans-account-details-step/loans-account-details-step.component.html @@ -11,10 +11,19 @@ {{ 'labels.inputs.Product Name' | translate }} + + @if (productSelected) { + + {{ getLoanProductType(productSelected.productType) | translate }} : {{ productSelected.name }} + + } + @for (product of productData | async; track product) { - - {{ product.name }} + + + } @@ -45,7 +59,7 @@ matTooltip="{{ 'tooltips.Provides an external id' | translate }}" /> - @if (loanProductSelected) { + @if (loanProductService.isLoanProduct) { {{ 'labels.inputs.Loan officer' | translate }} + + {{ 'labels.inputs.Loan Purpose' | translate }} + + @for (loanPurpose of loanPurposeOptions; track loanPurpose) { + + {{ loanPurpose.name }} + + } + + } - - {{ 'labels.inputs.Loan Purpose' | translate }} - - @for (loanPurpose of loanPurposeOptions; track loanPurpose) { - - {{ loanPurpose.name }} - - } - - {{ 'labels.inputs.Fund' | translate }} @@ -120,21 +134,23 @@ } - -

{{ 'labels.heading.Savings Linkage' | translate }}

- - {{ 'labels.inputs.Link savings' | translate }} - - @for (savingaccount of accountLinkingOptions; track savingaccount) { - - ({{ savingaccount.accountNo }}) {{ savingaccount.productName }} - - } - - - -

{{ 'labels.inputs.Create standing instructions at disbursement' | translate }}

-
+ @if (loanProductService.isLoanProduct) { + +

{{ 'labels.heading.Savings Linkage' | translate }}

+ + {{ 'labels.inputs.Link savings' | translate }} + + @for (savingaccount of accountLinkingOptions; track savingaccount) { + + ({{ savingaccount.accountNo }}) {{ savingaccount.productName }} + + } + + + +

{{ 'labels.inputs.Create standing instructions at disbursement' | translate }}

+
+ } } @@ -162,3 +178,25 @@

{{ 'labels.heading.Savings Linkage' | translate }}< } + + +
+
+ {{ product.name }} +
+
+
+ {{ 'labels.inputs.Product Type' | translate }} + {{ getLoanProductType(product.productType) | translate }} +
+
+ {{ 'labels.inputs.Short Name' | translate }} + {{ product.shortName }} +
+
+ {{ 'labels.inputs.Currency' | translate }} + {{ product.currency?.code }} +
+
+
+
diff --git a/src/app/loans/loans-account-stepper/loans-account-details-step/loans-account-details-step.component.scss b/src/app/loans/loans-account-stepper/loans-account-details-step/loans-account-details-step.component.scss index c95283bdc2..e28af687e7 100644 --- a/src/app/loans/loans-account-stepper/loans-account-details-step/loans-account-details-step.component.scss +++ b/src/app/loans/loans-account-stepper/loans-account-details-step/loans-account-details-step.component.scss @@ -30,3 +30,60 @@ mat-divider { .margin-t { margin-top: 1em; } + +.mdc-list-item__primary-text { + width: 100%; +} + +.product-option-row { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 4px; + width: 100%; + padding: 4px 0; +} + +.product-option-name { + font-size: 0.85rem; + white-space: normal; + line-height: 1.3; + color: var(--md-sys-color-primary, #1074b9); +} + +.product-option-meta { + display: flex; + gap: 12px; +} + +.meta-item { + display: flex; + flex-direction: column; + gap: 4px; +} + +.meta-label { + font-size: 0.7rem; + text-transform: uppercase; + letter-spacing: 0.04em; + opacity: 0.6; + line-height: 1; +} + +.meta-value { + font-size: 0.85rem; + font-weight: 500; +} + +::ng-deep .loan-product-select-panel { + min-width: max(600px, 100%) !important; + + .mat-mdc-option { + height: auto !important; + padding: 10px 16px !important; + } + + .mdc-list-item__primary-text { + width: 100%; + } +} diff --git a/src/app/loans/loans-account-stepper/loans-account-details-step/loans-account-details-step.component.ts b/src/app/loans/loans-account-stepper/loans-account-details-step/loans-account-details-step.component.ts index 8d649088c8..5253ef6096 100644 --- a/src/app/loans/loans-account-stepper/loans-account-details-step/loans-account-details-step.component.ts +++ b/src/app/loans/loans-account-stepper/loans-account-details-step/loans-account-details-step.component.ts @@ -8,14 +8,8 @@ /** Angular Imports */ import { Component, OnInit, Input, Output, EventEmitter, OnDestroy, inject } from '@angular/core'; -import { - UntypedFormGroup, - UntypedFormBuilder, - Validators, - UntypedFormControl, - ReactiveFormsModule -} from '@angular/forms'; -import { ActivatedRoute, RouterLink } from '@angular/router'; +import { UntypedFormGroup, UntypedFormBuilder, Validators, UntypedFormControl } from '@angular/forms'; +import { ActivatedRoute } from '@angular/router'; import { SettingsService } from 'app/settings/settings.service'; import { TranslateService } from '@ngx-translate/core'; @@ -32,6 +26,10 @@ import { MatCheckbox } from '@angular/material/checkbox'; import { MatStepperPrevious, MatStepperNext } from '@angular/material/stepper'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; +import { LoanProductBasicDetails } from 'app/loans/models/loan-product.model'; +import { LoanProductService } from 'app/products/loan-products/services/loan-product.service'; +import { MatSelectChange, MatSelectTrigger } from '@angular/material/select'; +import { LoanProductBaseComponent } from 'app/products/loan-products/common/loan-product-base.component'; /** * Loans Account Details Step @@ -49,10 +47,11 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; MatStepperPrevious, FaIconComponent, MatStepperNext, + MatSelectTrigger, AsyncPipe ] }) -export class LoansAccountDetailsStepComponent implements OnInit, OnDestroy { +export class LoansAccountDetailsStepComponent extends LoanProductBaseComponent implements OnInit, OnDestroy { private formBuilder = inject(UntypedFormBuilder); private loansService = inject(LoansService); private route = inject(ActivatedRoute); @@ -66,6 +65,8 @@ export class LoansAccountDetailsStepComponent implements OnInit, OnDestroy { /** Loans Account Template */ @Input() loansAccountTemplate: any; + /** Loan Product Basic Details lists */ + @Input() loanProductsBasicDetails: LoanProductBasicDetails[]; /** Minimum date allowed. */ minDate = new Date(2000, 0, 1); @@ -96,8 +97,11 @@ export class LoansAccountDetailsStepComponent implements OnInit, OnDestroy { /** Subject that emits when the component has been destroyed. */ protected _onDestroy = new Subject(); + productSelected: LoanProductBasicDetails | null = null; + /** Loans Account Template with product data */ @Output() loansAccountProductTemplate = new EventEmitter(); + @Output() loansProductType = new EventEmitter(); /** * Sets loans account details form. * @param {FormBuilder} formBuilder Form Builder. @@ -105,6 +109,7 @@ export class LoansAccountDetailsStepComponent implements OnInit, OnDestroy { * @param {SettingsService} settingsService SettingsService */ constructor() { + super(); this.loanId = this.route.snapshot.params['loanId']; this.createLoansAccountDetailsForm(); } @@ -113,10 +118,10 @@ export class LoansAccountDetailsStepComponent implements OnInit, OnDestroy { this.placeHolderLabel = this.translateService.instant('labels.text.Search'); this.noEntriesFoundLabel = this.translateService.instant('labels.text.No data found'); this.maxDate = this.settingsService.maxFutureDate; - this.buildDependencies(); + this.productList = this.loanProductsBasicDetails.sort(this.commons.dynamicSort('name')); if (this.loansAccountTemplate) { - this.productList = this.loansAccountTemplate.productOptions.sort(this.commons.dynamicSort('name')); if (this.loansAccountTemplate.loanProductId) { + this.addFormControlsBasedOnProductType(); this.loansAccountDetailsForm.patchValue({ productId: this.loansAccountTemplate.loanProductId, submittedOnDate: @@ -130,6 +135,17 @@ export class LoansAccountDetailsStepComponent implements OnInit, OnDestroy { new Date(this.loansAccountTemplate.timeline.expectedDisbursementDate), externalId: this.loansAccountTemplate.externalId }); + this.productSelected = this.loanProductsBasicDetails.find( + (p: LoanProductBasicDetails) => + p.productType === this.loanProductService.productType.value && + p.id === this.loansAccountTemplate.loanProductId + ); + if (this.productSelected) { + this.loansAccountDetailsForm.patchValue({ + productId: this.productSelected.shortName + }); + this.loanProductSelected = true; + } } } this.filterFormCtrl.valueChanges.pipe(takeUntil(this._onDestroy)).subscribe(() => { @@ -152,7 +168,10 @@ export class LoansAccountDetailsStepComponent implements OnInit, OnDestroy { } else { this.productData.next( this.productList.filter((option: any) => { - return option['name'].toLowerCase().indexOf(search) >= 0; + return ( + option['name'].toLowerCase().indexOf(search) >= 0 || + option['shortName'].toLowerCase().indexOf(search) >= 0 + ); }) ); } @@ -164,12 +183,7 @@ export class LoansAccountDetailsStepComponent implements OnInit, OnDestroy { */ createLoansAccountDetailsForm() { this.loansAccountDetailsForm = this.formBuilder.group({ - productId: [ - '', - Validators.required - ], - loanOfficerId: [''], - loanPurposeId: [''], + productId: [''], fundId: [''], submittedOnDate: [ this.settingsService.businessDate, @@ -179,34 +193,7 @@ export class LoansAccountDetailsStepComponent implements OnInit, OnDestroy { '', Validators.required ], - externalId: [''], - linkAccountId: [''], - createStandingInstructionAtDisbursement: [''] - }); - } - - /** - * Fetches loans account product template on productId value changes - */ - buildDependencies() { - const entityId = this.loansAccountTemplate.clientId - ? this.loansAccountTemplate.clientId - : this.loansAccountTemplate.group.id; - const isGroup = this.loansAccountTemplate.clientId ? false : true; - this.loansAccountDetailsForm.get('productId').valueChanges.subscribe((productId: string) => { - this.loansService.getLoansAccountTemplateResource(entityId, isGroup, productId).subscribe((response: any) => { - this.loansAccountProductTemplate.emit(response); - this.loanOfficerOptions = response.loanOfficerOptions; - this.loanPurposeOptions = response.loanPurposeOptions; - this.fundOptions = response.fundOptions; - this.accountLinkingOptions = response.accountLinkingOptions; - this.loanProductSelected = true; - if (response.createStandingInstructionAtDisbursement) { - this.loansAccountDetailsForm - .get('createStandingInstructionAtDisbursement') - .patchValue(response.createStandingInstructionAtDisbursement); - } - }); + externalId: [''] }); } @@ -214,6 +201,93 @@ export class LoansAccountDetailsStepComponent implements OnInit, OnDestroy { * Returns loans account details form value. */ get loansAccountDetails() { - return this.loansAccountDetailsForm.getRawValue(); + if (this.productSelected) { + const loanAccountDetails = { + ...this.loansAccountDetailsForm.getRawValue(), + productId: this.productSelected.id + }; + return loanAccountDetails; + } + return null; + } + + getLoanProductType(productType: string) { + return LoanProductService.productTypeLabel(productType); + } + + productChange(event: MatSelectChange): void { + const productShortName = event.value; + this.productSelected = this.loanProductsBasicDetails.find( + (p: LoanProductBasicDetails) => p.shortName === productShortName + ); + if (this.productSelected) { + this.loanProductService.initialize(this.productSelected.productType); + const entityId = this.loansAccountTemplate.clientId + ? this.loansAccountTemplate.clientId + : this.loansAccountTemplate.group.id; + const isGroup: boolean = this.loansAccountTemplate.clientId ? false : true; + + this.loansProductType.emit(this.productSelected.productType); + this.addFormControlsBasedOnProductType(); + if (this.loanProductService.isLoanProduct) { + this.loansService + .getLoansAccountTemplateResource(entityId, isGroup, this.productSelected.id) + .subscribe((response: any) => { + this.loansAccountProductTemplate.emit(response); + this.loanOfficerOptions = response.loanOfficerOptions; + this.loanPurposeOptions = response.loanPurposeOptions; + this.fundOptions = response.fundOptions; + this.accountLinkingOptions = response.accountLinkingOptions; + this.loanProductSelected = true; + if (response.createStandingInstructionAtDisbursement) { + this.loansAccountDetailsForm + .get('createStandingInstructionAtDisbursement') + .patchValue(response.createStandingInstructionAtDisbursement); + } + }); + } else if (this.loanProductService.isWorkingCapital) { + this.loansService + .getWorkingCapitalLoansAccountTemplate(entityId, this.productSelected.id) + .subscribe((response: any) => { + this.loansAccountProductTemplate.emit(response); + this.fundOptions = response.fundOptions; + this.loansAccountDetailsForm.patchValue({ + fundId: response.loanData.fundId + }); + this.loanProductSelected = true; + }); + } else { + console.log(this.productSelected.productType + ' not implemented'); + } + } + } + + addFormControlsBasedOnProductType(): void { + const loanOnlyControls: Record = { + loanOfficerId: new UntypedFormControl(''), + loanPurposeId: new UntypedFormControl(''), + linkAccountId: new UntypedFormControl(''), + createStandingInstructionAtDisbursement: new UntypedFormControl('') + }; + + if (this.loanProductService.isLoanProduct) { + Object.entries(loanOnlyControls).forEach( + ([ + name, + control + ]) => { + if (!this.loansAccountDetailsForm.contains(name)) { + this.loansAccountDetailsForm.addControl(name, control); + } + } + ); + return; + } + + Object.keys(loanOnlyControls).forEach((name) => { + if (this.loansAccountDetailsForm.contains(name)) { + this.loansAccountDetailsForm.removeControl(name); + } + }); } } 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 0ecf2924a5..485d7642b4 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 @@ -10,30 +10,39 @@

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

- {{ 'labels.inputs.Product' | translate }}: - - - + {{ 'labels.inputs.Client' | translate }}: + + {{ loansAccountProductTemplate.clientName || loansAccountProductTemplate.client.displayName }} + +
+ +
+ {{ 'labels.inputs.Product Type' | translate }}: + + {{ loanProductType() }} +
- @if (loansAccount.loanOfficerId) { +
+ {{ 'labels.inputs.Product' | translate }}: + + + +
+ + @if (loanProductService.isLoanProduct && loansAccount.loanOfficerId) {
- {{ 'labels.inputs.Loan officer' | translate }}: - {{ + {{ 'labels.inputs.Loan officer' | translate }}: + {{ loansAccount.loanOfficerId | find: loansAccountProductTemplate.loanOfficerOptions : 'id' : 'displayName' }}
} - @if (loansAccount.loanPurposeId) { + @if (loanProductService.isLoanProduct && loansAccount.loanPurposeId) {
- {{ 'labels.inputs.Loan purpose' | translate }}: - {{ + {{ 'labels.inputs.Loan purpose' | translate }}: + {{ loansAccount.loanPurposeId | find: loansAccountProductTemplate.loanPurposeOptions : 'id' : 'name' }}
@@ -41,352 +50,405 @@

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

@if (loansAccount.fundId) {
- {{ 'labels.inputs.Fund' | translate }}: - {{ + {{ 'labels.inputs.Fund' | translate }}: + {{ loansAccount.fundId | find: loansAccountProductTemplate.fundOptions : 'id' : 'name' }}
}
- {{ 'labels.inputs.Submitted on' | translate }}: - {{ loansAccount.submittedOnDate | dateFormat }} + {{ 'labels.inputs.Submitted on' | translate }}: + {{ loansAccount.submittedOnDate | dateFormat }}
- {{ 'labels.inputs.Disbursement on' | translate }}: - {{ loansAccount.expectedDisbursementDate | dateFormat }} + {{ 'labels.inputs.Disbursement on' | translate }}: + {{ loansAccount.expectedDisbursementDate | dateFormat }}
@if (loansAccount.externalId) {
- {{ 'labels.inputs.External id' | translate }}: - + {{ 'labels.inputs.External id' | translate }}: +
} - @if (activeClientMembers) { -

{{ 'labels.heading.Client Members' | translate }}

+ @if (loanProductService.isWorkingCapital) { +

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

+ -
- - - - - - - - - - - - - - - - - - - - - - - -
{{ 'labels.inputs.Client ID' | translate }}{{ element.id }}{{ 'labels.inputs.Client Name' | translate }}{{ element.displayName }}{{ 'labels.inputs.Loan Purpose' | translate }}{{ element.purpose }}{{ 'labels.inputs.Original Loan' | translate }} - {{ element.principal | currency: loansAccountProductTemplate.currency.code : 'symbol-narrow' : '1.2-2' }} -
+
+ {{ 'labels.inputs.Principal' | translate }}: + + {{ + loansAccount.principalAmount | currency: loansAccountProductTemplate.currency.code : 'symbol-narrow' : '1.2-2' + }} + {{ loansAccountProductTemplate.currency.code }} + +
+
+ {{ 'labels.inputs.Total Payment' | translate }}: + + {{ + loansAccount.totalPayment | currency: loansAccountProductTemplate.currency.code : 'symbol-narrow' : '1.2-2' + }} + {{ loansAccountProductTemplate.currency.code }} +
- } - -

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

- - -
- {{ 'labels.inputs.Principal' | translate }}: - - {{ - loansAccount.principalAmount | currency: loansAccountProductTemplate.currency.code : 'symbol-narrow' : '1.2-2' - }} - {{ loansAccountProductTemplate.currency.code }} - -
- -
- {{ 'labels.inputs.Loan Term' | translate }}: - {{ loansAccount.loanTermFrequency }} - {{ - loansAccount.loanTermFrequencyType | find: loansAccountProductTemplate.termFrequencyTypeOptions : 'id' : 'name' - }} -
- -
- {{ 'labels.inputs.Number of repayments' | translate }}: - {{ loansAccount.numberOfRepayments }} -
-
- {{ 'labels.inputs.Repaid every' | translate }}: - {{ loansAccount.repaymentEvery }} - {{ - loansAccount.repaymentFrequencyType | find: loansAccountProductTemplate.termFrequencyTypeOptions : 'id' : 'name' - }} - {{ - loansAccount.repaymentFrequencyNthDayType - | find: loansAccountProductTemplate.repaymentFrequencyNthDayTypeOptions : 'id' : 'name' - }} - {{ - loansAccount.repaymentFrequencyDayOfWeekType - | find: loansAccountProductTemplate.repaymentFrequencyDaysOfWeekTypeOptions : 'id' : 'name' - }} -
+ @if (loansAccount.discount) { +
+ {{ 'labels.inputs.Discount' | translate }}: + + {{ loansAccount.discount | currency: loansAccountProductTemplate.currency.code : 'symbol-narrow' : '1.2-2' }} + {{ loansAccountProductTemplate.currency.code }} + +
+ } - @if (productEnableDownPayment) {
- {{ 'labels.inputs.Enable Down Payments' | translate }}: - {{ loansAccount.enableDownPayment | yesNo }} + {{ 'labels.inputs.Period Payment Rate' | translate }}: + {{ loansAccount.periodPaymentRate | formatNumber }} %
- } - @if (loansAccount.repaymentsStartingFromDate) {
- {{ 'labels.inputs.First repayment on' | translate }}: - {{ loansAccount.repaymentsStartingFromDate | dateFormat }} + {{ 'labels.inputs.Period Payment Frequency' | translate }}: + {{ loansAccount.repaymentEvery }} + {{ camalize(loansAccount.repaymentFrequencyType) | translateKey: 'catalogs' }}
} - @if (loansAccount.interestChargedFromDate) { + @if (loanProductService.isLoanProduct) { + @if (activeClientMembers) { +

{{ 'labels.heading.Client Members' | translate }}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
{{ 'labels.inputs.Client ID' | translate }}{{ element.id }}{{ 'labels.inputs.Client Name' | translate }}{{ element.displayName }}{{ 'labels.inputs.Loan Purpose' | translate }}{{ element.purpose }}{{ 'labels.inputs.Original Loan' | translate }} + {{ element.principal | currency: loansAccountProductTemplate.currency.code : 'symbol-narrow' : '1.2-2' }} +
+
+ } + +

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

+ +
- {{ 'labels.inputs.Interest charged from' | translate }}: - {{ loansAccount.interestChargedFromDate | dateFormat }} + {{ 'labels.inputs.Principal' | translate }}: + + {{ + loansAccount.principalAmount | currency: loansAccountProductTemplate.currency.code : 'symbol-narrow' : '1.2-2' + }} + {{ loansAccountProductTemplate.currency.code }} +
- } - @if (loansAccount.interestRatePerPeriod) {
- {{ 'labels.inputs.Nominal interest rate' | translate }}: + {{ 'labels.inputs.Loan Term' | translate }}: {{ loansAccount.interestRatePerPeriod }}  {{ - loansAccountProductTemplate.interestRateFrequencyType.value + >{{ loansAccount.loanTermFrequency }} + {{ + loansAccount.loanTermFrequencyType + | find: loansAccountProductTemplate.termFrequencyTypeOptions : 'id' : 'name' }}
- } - - @if (loansAccount.interestType) { -
- {{ 'labels.inputs.Interest method' | translate }}: - {{ loansAccount.interestType }} -
- } - @if (loansAccount.isEqualAmortization) {
- {{ 'labels.inputs.Is Equal Amortization' | translate }}: - {{ loansAccount.isEqualAmortization }} + {{ 'labels.inputs.Number of repayments' | translate }}: + {{ loansAccount.numberOfRepayments }}
- } - -
- {{ 'labels.inputs.Amortization' | translate }} - {{ - loansAccount.amortizationType - | find: loansAccountProductTemplate.amortizationTypeOptions : 'id' : 'value' - | translateKey: 'catalogs' - }} -
-
- {{ 'labels.inputs.Interest calculation period' | translate }}: - {{ - loansAccount.interestCalculationPeriodType - | find: loansAccountProductTemplate.interestCalculationPeriodTypeOptions : 'id' : 'value' - | translateKey: 'catalogs' - }} -
- - @if (loansAccount.allowPartialPeriodInterestCalculation) {
- {{ 'labels.inputs.Calculate interest for exact days in partial period' | translate }}:{{ 'labels.inputs.Repaid every' | translate }}: + {{ loansAccount.repaymentEvery }} + {{ + loansAccount.repaymentFrequencyType + | find: loansAccountProductTemplate.termFrequencyTypeOptions : 'id' : 'name' + }} + {{ + loansAccount.repaymentFrequencyNthDayType + | find: loansAccountProductTemplate.repaymentFrequencyNthDayTypeOptions : 'id' : 'name' + }} + {{ + loansAccount.repaymentFrequencyDayOfWeekType + | find: loansAccountProductTemplate.repaymentFrequencyDaysOfWeekTypeOptions : 'id' : 'name' + }} - {{ loansAccount.allowPartialPeriodInterestCalculation }}
- } - @if (loansAccount.inArrearsTolerance) { + @if (productEnableDownPayment) { +
+ {{ 'labels.inputs.Enable Down Payments' | translate }}: + {{ loansAccount.enableDownPayment | yesNo }} +
+ } + + @if (loansAccount.repaymentsStartingFromDate) { +
+ {{ 'labels.inputs.First repayment on' | translate }}: + {{ loansAccount.repaymentsStartingFromDate | dateFormat }} +
+ } + + @if (loansAccount.interestChargedFromDate) { +
+ {{ 'labels.inputs.Interest charged from' | translate }}: + {{ loansAccount.interestChargedFromDate | dateFormat }} +
+ } + + @if (loansAccount.interestRatePerPeriod) { +
+ {{ 'labels.inputs.Nominal interest rate' | translate }}: + {{ loansAccount.interestRatePerPeriod }}  {{ + loansAccountProductTemplate.interestRateFrequencyType.value + }} +
+ } + + @if (loansAccount.interestType) { +
+ {{ 'labels.inputs.Interest method' | translate }}: + {{ loansAccount.interestType }} +
+ } + + @if (loansAccount.isEqualAmortization) { +
+ {{ 'labels.inputs.Is Equal Amortization' | translate }}: + {{ loansAccount.isEqualAmortization }} +
+ } +
- {{ 'labels.inputs.Arrears tolerance' | translate }}: - {{ loansAccount.inArrearsTolerance }} + {{ 'labels.inputs.Amortization' | translate }} + {{ + loansAccount.amortizationType + | find: loansAccountProductTemplate.amortizationTypeOptions : 'id' : 'value' + | translateKey: 'catalogs' + }}
- } - @if (loansAccount.graceOnInterestCharged) {
- {{ 'labels.inputs.Interest free period' | translate }}: - {{ loansAccount.graceOnInterestCharged }} + {{ 'labels.inputs.Interest calculation period' | translate }}: + {{ + loansAccount.interestCalculationPeriodType + | find: loansAccountProductTemplate.interestCalculationPeriodTypeOptions : 'id' : 'value' + | translateKey: 'catalogs' + }}
- } - -
- {{ 'labels.inputs.Repayment strategy' | translate }}: - {{ - loansAccount.transactionProcessingStrategyCode - | find: loansAccountProductTemplate.transactionProcessingStrategyOptions : 'code' : 'name' - | translateKey: 'catalogs' - }} -
- -
- {{ 'labels.inputs.Installment Amount' | translate }} - {{ loansAccount.fixedEmiAmount | formatNumber }} -
- -
- {{ 'labels.inputs.Balloon Repayment Amount' | translate }} - {{ loansAccount.balloonRepaymentAmount | formatNumber }} -
-

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

+ @if (loansAccount.allowPartialPeriodInterestCalculation) { +
+ {{ 'labels.inputs.Calculate interest for exact days in partial period' | translate }}: + {{ loansAccount.allowPartialPeriodInterestCalculation }} +
+ } + + @if (loansAccount.inArrearsTolerance) { +
+ {{ 'labels.inputs.Arrears tolerance' | translate }}: + {{ loansAccount.inArrearsTolerance }} +
+ } + + @if (loansAccount.graceOnInterestCharged) { +
+ {{ 'labels.inputs.Interest free period' | translate }}: + {{ loansAccount.graceOnInterestCharged }} +
+ } - - @if (loansAccount.graceOnPrincipalPayment) {
- {{ 'labels.inputs.On principal payment' | translate }}: - {{ loansAccount.graceOnPrincipalPayment }} + {{ 'labels.inputs.Repayment strategy' | translate }}: + {{ + loansAccount.transactionProcessingStrategyCode + | find: loansAccountProductTemplate.transactionProcessingStrategyOptions : 'code' : 'name' + | translateKey: 'catalogs' + }}
- } - @if (loansAccount.graceOnInterestPayment) {
- {{ 'labels.inputs.On interest payment' | translate }}: - {{ loansAccount.graceOnInterestPayment }} + {{ 'labels.inputs.Installment Amount' | translate }} + {{ loansAccount.fixedEmiAmount | formatNumber }}
- } - @if (loansAccount.graceOnArrearsAgeing) {
- {{ 'labels.inputs.On Arrears Aging' | translate }}: - {{ loansAccount.graceOnArrearsAgeing }} + {{ 'labels.inputs.Balloon Repayment Amount' | translate }} + {{ loansAccount.balloonRepaymentAmount | formatNumber }}
- } -
- {{ 'labels.inputs.Enable installment level Delinquency' | translate }} - {{ loansAccount.enableInstallmentLevelDelinquency | yesNo }} -
+

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

+ + + @if (loansAccount.graceOnPrincipalPayment) { +
+ {{ 'labels.inputs.On principal payment' | translate }}: + {{ loansAccount.graceOnPrincipalPayment }} +
+ } + + @if (loansAccount.graceOnInterestPayment) { +
+ {{ 'labels.inputs.On interest payment' | translate }}: + {{ loansAccount.graceOnInterestPayment }} +
+ } + + @if (loansAccount.graceOnArrearsAgeing) { +
+ {{ 'labels.inputs.On Arrears Aging' | translate }}: + {{ loansAccount.graceOnArrearsAgeing }} +
+ } - @if (loansAccount.isTopup) {
- {{ 'labels.inputs.Is Topup Loan' | translate }}? - {{ loansAccount.isTopup }} + {{ 'labels.inputs.Enable installment level Delinquency' | translate }} + {{ loansAccount.enableInstallmentLevelDelinquency | yesNo }}
- } -
- {{ 'labels.inputs.Recalculate Interest' | translate }}: - {{ loansAccountProductTemplate?.isInterestRecalculationEnabled | yesNo }} -
+ @if (loansAccount.isTopup) { +
+ {{ 'labels.inputs.Is Topup Loan' | translate }}? + {{ loansAccount.isTopup }} +
+ } - @if (loansAccountProductTemplate?.daysInMonthType) {
- {{ 'labels.inputs.Days in month' | translate }}: - {{ loansAccountProductTemplate?.daysInMonthType.value | translateKey: 'catalogs' }} -
- } - - @if (loansAccount.charges.length) { -
-

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

- - - - - - - - - - - - - - - - - - - - - - - - -
{{ 'labels.inputs.name' | translate }} - {{ charge.name + ', ' + (charge.currency?.displaySymbol || '') }} - {{ 'labels.inputs.Type' | translate }} - {{ charge.chargeCalculationType.value }} - {{ 'labels.inputs.Amount' | translate }} - {{ charge.amount }} - {{ 'labels.inputs.Collected On' | translate }} - {{ charge.chargeTimeType.value }} - {{ 'labels.inputs.Date' | translate }} - @if (charge.chargeTimeType.value === 'Specified due date' || charge.chargeTimeType.value === 'Weekly Fee') { - - {{ (charge.dueDate | dateFormat) || 'Unassigned' }} - - } - @if (charge.chargeTimeType.value === 'Monthly Fee' || charge.chargeTimeType.value === 'Annual Fee') { - - {{ (charge.feeOnMonthDay | dateFormat) || 'Unassigned' }} - - } - @if ( - !( - charge.chargeTimeType.value === 'Monthly Fee' || - charge.chargeTimeType.value === 'Annual Fee' || - charge.chargeTimeType.value === 'Specified due date' || - charge.chargeTimeType.value === 'Weekly Fee' - ) - ) { - - {{ 'labels.inputs.N/A' | translate }} - - } -
+ {{ 'labels.inputs.Recalculate Interest' | translate }}: + {{ loansAccountProductTemplate?.isInterestRecalculationEnabled | yesNo }}
- } - @if (loansAccountProductTemplate.overdueCharges.length) { -
-

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

- - - - - - - - - - - - - - - - - - - - -
{{ 'labels.inputs.name' | translate }}{{ charge.name + ', ' + (charge.currency?.displaySymbol || '') }}{{ 'labels.inputs.Type' | translate }}{{ charge.chargeCalculationType.value }}{{ 'labels.inputs.Amount' | translate }}{{ charge.amount | formatNumber }}{{ 'labels.inputs.Collected On' | translate }}{{ charge.chargeTimeType.value }}
-
+ @if (loansAccountProductTemplate?.daysInMonthType) { +
+ {{ 'labels.inputs.Days in month' | translate }}: + {{ loansAccountProductTemplate?.daysInMonthType.value | translateKey: 'catalogs' }} +
+ } + + @if (loansAccount.charges && loansAccount.charges.length) { +
+

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

+ + + + + + + + + + + + + + + + + + + + + + + + +
{{ 'labels.inputs.name' | translate }} + {{ charge.name + ', ' + (charge.currency?.displaySymbol || '') }} + {{ 'labels.inputs.Type' | translate }} + {{ charge.chargeCalculationType.value }} + {{ 'labels.inputs.Amount' | translate }} + {{ charge.amount }} + {{ 'labels.inputs.Collected On' | translate }} + {{ charge.chargeTimeType.value }} + {{ 'labels.inputs.Date' | translate }} + @if ( + charge.chargeTimeType.value === 'Specified due date' || charge.chargeTimeType.value === 'Weekly Fee' + ) { + + {{ (charge.dueDate | dateFormat) || 'Unassigned' }} + + } + @if (charge.chargeTimeType.value === 'Monthly Fee' || charge.chargeTimeType.value === 'Annual Fee') { + + {{ (charge.feeOnMonthDay | dateFormat) || 'Unassigned' }} + + } + @if ( + !( + charge.chargeTimeType.value === 'Monthly Fee' || + charge.chargeTimeType.value === 'Annual Fee' || + charge.chargeTimeType.value === 'Specified due date' || + charge.chargeTimeType.value === 'Weekly Fee' + ) + ) { + + {{ 'labels.inputs.N/A' | translate }} + + } +
+
+ } + + @if (loansAccountProductTemplate.overdueCharges?.length) { +
+

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

+ + + + + + + + + + + + + + + + + + + + +
{{ 'labels.inputs.name' | translate }}{{ charge.name + ', ' + (charge.currency?.displaySymbol || '') }}{{ 'labels.inputs.Type' | translate }}{{ charge.chargeCalculationType.value }}{{ 'labels.inputs.Amount' | translate }}{{ charge.amount | formatNumber }}{{ 'labels.inputs.Collected On' | translate }}{{ charge.chargeTimeType.value }}
+
+ } }
diff --git a/src/app/loans/loans-account-stepper/loans-account-preview-step/loans-account-preview-step.component.ts b/src/app/loans/loans-account-stepper/loans-account-preview-step/loans-account-preview-step.component.ts index 80c8f31a41..0cd13787f6 100644 --- a/src/app/loans/loans-account-stepper/loans-account-preview-step/loans-account-preview-step.component.ts +++ b/src/app/loans/loans-account-stepper/loans-account-preview-step/loans-account-preview-step.component.ts @@ -21,7 +21,6 @@ import { MatRowDef, MatRow } from '@angular/material/table'; -import { LongTextComponent } from '../../../shared/long-text/long-text.component'; import { CurrencyPipe } from '@angular/common'; import { ExternalIdentifierComponent } from '../../../shared/external-identifier/external-identifier.component'; import { MatDivider } from '@angular/material/divider'; @@ -33,6 +32,9 @@ import { FormatNumberPipe } from '../../../pipes/format-number.pipe'; import { YesnoPipe } from '../../../pipes/yesno.pipe'; import { TranslatePipe } from '../../../pipes/translate.pipe'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; +import { LoanProductBaseComponent } from 'app/products/loan-products/common/loan-product-base.component'; +import { LoanProductBasicDetails } from 'app/loans/models/loan-product.model'; +import { LongTextComponent } from 'app/shared/long-text/long-text.component'; /** * Create Loans Account Preview Step @@ -43,7 +45,6 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; styleUrls: ['./loans-account-preview-step.component.scss'], imports: [ ...STANDALONE_SHARED_IMPORTS, - LongTextComponent, ExternalIdentifierComponent, MatDivider, MatTable, @@ -63,18 +64,20 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; DateFormatPipe, FormatNumberPipe, YesnoPipe, - TranslatePipe + TranslatePipe, + LongTextComponent ] }) -export class LoansAccountPreviewStepComponent implements OnChanges { +export class LoansAccountPreviewStepComponent extends LoanProductBaseComponent implements OnChanges { /** Loans Account Template */ - @Input() loansAccountTemplate: any = []; + @Input() loansAccountTemplate: any; /** Loans Account Product Template */ @Input() loansAccountProductTemplate: any; /** Loans Account Data */ @Input() loansAccount: any; /** active Client Members in case of GLIM Account */ @Input() activeClientMembers?: any; + @Input() loanProductsBasicDetails: LoanProductBasicDetails[]; /** Submit Loans Account */ @Output() submitEvent = new EventEmitter(); @@ -109,7 +112,9 @@ export class LoansAccountPreviewStepComponent implements OnChanges { dataSource: any; productEnableDownPayment = false; - constructor() {} + constructor() { + super(); + } ngOnChanges(changes: SimpleChanges): void { this.productEnableDownPayment = this.loansAccountProductTemplate.product.enableDownPayment; @@ -128,4 +133,18 @@ export class LoansAccountPreviewStepComponent implements OnChanges { .reduce((acc: number, member: any) => acc + (member.principal ?? 0), 0); } } + + loanProductName(id: number): string { + const productType: string = this.loanProductService.productType.value; + const product = this.loanProductsBasicDetails.find((p) => p.productType === productType && p.id === id); + return product?.name ?? ''; + } + + loanProductType(): string { + return this.loanProductService.loanProductTypeLabel; + } + + camalize(word: string) { + return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(); + } } 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 31477090f2..edf76a35b6 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 @@ -24,246 +24,251 @@

- - {{ 'labels.inputs.Loan Term' | translate }} - - @if (loansAccountTermsForm.controls.loanTermFrequency.hasError('required')) { - - {{ 'labels.inputs.Loan Term' | translate }} {{ 'labels.commons.is' | translate }} - {{ 'labels.commons.required' | translate }} - - } - - - - {{ 'labels.inputs.Frequency' | translate }} - - @for (type of termFrequencyTypeData; track type) { - - {{ type.value | translateKey: 'catalogs' }} - - } - - @if (loansAccountTermsForm.controls.loanTermFrequencyType.hasError('required')) { - - {{ 'labels.inputs.Frequency' | translate }} {{ 'labels.commons.is' | translate }} - {{ 'labels.commons.required' | translate }} - - } - - - @if (hasFixedLength()) { - - {{ 'labels.inputs.Fixed Length' | translate }} - + @if (loanProductService.isWorkingCapital) { + + {{ 'labels.inputs.Total Payment' | translate }} + - } - @if (hasFixedLength()) { - {{ - loansAccountTermsForm.value.loanTermFrequencyType | find: termFrequencyTypeData : 'id' : 'value' - }} - } -

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

- - - {{ 'labels.inputs.Number of repayments' | translate }} - - @if (loansAccountTermsForm.controls.numberOfRepayments.hasError('required')) { - - {{ 'labels.inputs.Number of repayments' | translate }} {{ 'labels.commons.is' | translate }} - {{ 'labels.commons.required' | translate }} - - } - - - @if (loansAccountTermsData?.canDefineInstallmentAmount) { - - {{ 'labels.inputs.Installment Amount' | translate }} - + + {{ 'labels.inputs.Discount' | translate }} + - } - - - {{ 'labels.inputs.First repayment on' | translate }} - - - - - - - {{ 'labels.inputs.Interest charged from' | translate }} - - - - -

- {{ 'labels.heading.Repaid Every' | translate }} - -

+ + {{ 'labels.inputs.Period Payment Rate' | translate }} + + - - {{ 'labels.inputs.Repaid every' | translate }} - - @if (loansAccountTermsForm.controls.repaymentEvery.hasError('required')) { - - {{ 'labels.inputs.Repaid every' | translate }} {{ 'labels.commons.is' | translate }} - {{ 'labels.commons.required' | translate }} - - } - - - - {{ 'labels.inputs.Frequency' | translate }} - - @for (repaymentFrequencyType of termFrequencyTypeData; track repaymentFrequencyType) { - - {{ repaymentFrequencyType.value | translateKey: 'catalogs' }} - + + {{ 'labels.inputs.Period Payment Frequency' | translate }} + + @if (loansAccountTermsForm.controls.repaymentEvery.hasError('required')) { + + {{ 'labels.inputs.Repaid every' | translate }} {{ 'labels.commons.is' | translate }} + {{ 'labels.commons.required' | translate }} + } - - - - @if (loansAccountTermsForm.controls.repaymentFrequencyType.value === 2) { - - {{ 'labels.inputs.Select On' | translate }} - - @for (repaymentFrequencyNthDayType of repaymentFrequencyNthDayTypeData; track repaymentFrequencyNthDayType) { - - {{ repaymentFrequencyNthDayType.value | translateKey: 'catalogs' }} - - } - - } - @if (loansAccountTermsForm.controls.repaymentFrequencyType.value === 2) { - - {{ 'labels.inputs.Select Day' | translate }} - - @for ( - repaymentFrequencyDayOfWeekType of repaymentFrequencyDaysOfWeekTypeData; - track repaymentFrequencyDayOfWeekType - ) { - - {{ repaymentFrequencyDayOfWeekType.value | translateKey: 'catalogs' }} + + {{ 'labels.inputs.Period Payment Frequency Type' | translate }} + + @for (repaymentFrequencyType of termFrequencyTypeData; track repaymentFrequencyType) { + + {{ repaymentFrequencyType.value | translateKey: 'catalogs' }} } } - @if (productEnableDownPayment) { - - {{ 'labels.inputs.Enable Down Payment' | translate }} - - } - -

{{ 'labels.inputs.Nominal interest rate' | translate }}

- - @if (!loansAccountTermsData?.isLoanProductLinkedToFloatingRate) { + @if (loanProductService.isLoanProduct) { - {{ 'labels.inputs.Nominal interest rate' | translate }} % - + {{ 'labels.inputs.Loan Term' | translate }} + + @if (loansAccountTermsForm.controls.loanTermFrequency.hasError('required')) { + + {{ 'labels.inputs.Loan Term' | translate }} {{ 'labels.commons.is' | translate }} + {{ 'labels.commons.required' | translate }} + + } + {{ 'labels.inputs.Frequency' | translate }} - - @for (interestRateFrequencyType of interestRateFrequencyTypeData; track interestRateFrequencyType) { - - {{ interestRateFrequencyType.value | translateKey: 'catalogs' }} + + @for (type of termFrequencyTypeData; track type) { + + {{ type.value | translateKey: 'catalogs' }} } - - {{ 'labels.inputs.Nominal interest rate frequency' | translate }} {{ 'labels.commons.is' | translate }} - {{ 'labels.commons.required' | translate }} - + @if (loansAccountTermsForm.controls.loanTermFrequencyType.hasError('required')) { + + {{ 'labels.inputs.Frequency' | translate }} {{ 'labels.commons.is' | translate }} + {{ 'labels.commons.required' | translate }} + + } + + @if (hasFixedLength()) { + + {{ 'labels.inputs.Fixed Length' | translate }} + + + } + @if (hasFixedLength()) { + {{ + loansAccountTermsForm.value.loanTermFrequencyType | find: termFrequencyTypeData : 'id' : 'value' + }} + } + +

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

+ - {{ 'labels.inputs.Interest method' | translate }} - - @for (interestType of interestTypeData; track interestType) { - - {{ interestType.value | translateKey: 'catalogs' }} - - } - + {{ 'labels.inputs.Number of repayments' | translate }} + + @if (loansAccountTermsForm.controls.numberOfRepayments.hasError('required')) { + + {{ 'labels.inputs.Number of repayments' | translate }} {{ 'labels.commons.is' | translate }} + {{ 'labels.commons.required' | translate }} + + } + + + @if (loansAccountTermsData?.canDefineInstallmentAmount) { + + {{ 'labels.inputs.Installment Amount' | translate }} + + + } + + + {{ 'labels.inputs.First repayment on' | translate }} + + + + + + + {{ 'labels.inputs.Interest charged from' | translate }} + + + + +

+ {{ 'labels.heading.Repaid Every' | translate }} + +

+ - {{ 'labels.inputs.Amortization' | translate }} - {{ 'labels.inputs.Repaid every' | translate }} + - @for (amortizationType of amortizationTypeData; track amortizationType) { - - {{ amortizationType.value | translateKey: 'catalogs' }} - - } - - @if (loansAccountTermsForm.controls.amortizationType.hasError('required')) { + formControlName="repaymentEvery" + matTooltip="{{ 'tooltips.Fields are input to calculating the repayment schedule' | translate }}" + /> + @if (loansAccountTermsForm.controls.repaymentEvery.hasError('required')) { - {{ 'labels.inputs.Amortization Type' | translate }} {{ 'labels.commons.is' | translate }} + {{ 'labels.inputs.Repaid every' | translate }} {{ 'labels.commons.is' | translate }} {{ 'labels.commons.required' | translate }} } - @if (isEqualPrincipalPayments()) { - - {{ 'labels.inputs.Principal Percentage Per Installment' | translate }} - + + + {{ 'labels.inputs.Frequency' | translate }} + + @for (repaymentFrequencyType of termFrequencyTypeData; track repaymentFrequencyType) { + + {{ repaymentFrequencyType.value | translateKey: 'catalogs' }} + + } + + + + @if (loansAccountTermsForm.controls.repaymentFrequencyType.value === 2) { + + {{ 'labels.inputs.Select On' | translate }} + + @for ( + repaymentFrequencyNthDayType of repaymentFrequencyNthDayTypeData; + track repaymentFrequencyNthDayType + ) { + + {{ repaymentFrequencyNthDayType.value | translateKey: 'catalogs' }} + + } + + + } + + @if (loansAccountTermsForm.controls.repaymentFrequencyType.value === 2) { + + {{ 'labels.inputs.Select Day' | translate }} + + @for ( + repaymentFrequencyDayOfWeekType of repaymentFrequencyDaysOfWeekTypeData; + track repaymentFrequencyDayOfWeekType + ) { + + {{ repaymentFrequencyDayOfWeekType.value | translateKey: 'catalogs' }} + + } + } - -

{{ 'labels.inputs.Is Equal Amortization' | translate }}

-
- } - @if (loansAccountTermsData?.isLoanProductLinkedToFloatingRate) { -
- - {{ 'labels.inputs.Interest Method' | translate }} - + @if (productEnableDownPayment) { + + {{ 'labels.inputs.Enable Down Payment' | translate }} + + } + +

{{ 'labels.inputs.Nominal interest rate' | translate }}

+ + @if (!loansAccountTermsData?.isLoanProductLinkedToFloatingRate) { + + {{ 'labels.inputs.Nominal interest rate' | translate }} % + + + + {{ 'labels.inputs.Frequency' | translate }} + + @for (interestRateFrequencyType of interestRateFrequencyTypeData; track interestRateFrequencyType) { + + {{ interestRateFrequencyType.value | translateKey: 'catalogs' }} + + } + + + {{ 'labels.inputs.Nominal interest rate frequency' | translate }} {{ 'labels.commons.is' | translate }} + {{ 'labels.commons.required' | translate }} + + + + {{ 'labels.inputs.Interest method' | translate }} + @for (interestType of interestTypeData; track interestType) { {{ interestType.value | translateKey: 'catalogs' }} @@ -271,7 +276,7 @@

{{ 'labels.inputs.Nominal interest rate' | translate } - + {{ 'labels.inputs.Amortization' | translate }} {{ 'labels.inputs.Nominal interest rate' | translate } - -

{{ 'labels.inputs.Is Floating Rate' | translate }}?

+ @if (isEqualPrincipalPayments()) { + + {{ 'labels.inputs.Principal Percentage Per Installment' | translate }} + + + } + +

{{ 'labels.inputs.Is Equal Amortization' | translate }}

-

- } + } + + @if (loansAccountTermsData?.isLoanProductLinkedToFloatingRate) { +
+ + {{ 'labels.inputs.Interest Method' | translate }} + + @for (interestType of interestTypeData; track interestType) { + + {{ interestType.value | translateKey: 'catalogs' }} + + } + + + + {{ 'labels.inputs.Amortization' | translate }} + + @for (amortizationType of amortizationTypeData; track amortizationType) { + + {{ amortizationType.value | translateKey: 'catalogs' }} + + } + + @if (loansAccountTermsForm.controls.amortizationType.hasError('required')) { + + {{ 'labels.inputs.Amortization Type' | translate }} {{ 'labels.commons.is' | translate }} + {{ 'labels.commons.required' | translate }} + + } + + +

{{ 'labels.inputs.Is Floating Rate' | translate }}?

+
+
+ } -

{{ 'labels.inputs.Loan Schedule' | translate }}

+

{{ 'labels.inputs.Loan Schedule' | translate }}

- @if (loanScheduleType) { -
-
-

{{ 'labels.inputs.Loan Schedule Type' | translate }}

-

{{ loanScheduleType.value | translateKey: 'catalogs' }}

+ @if (loanScheduleType) { +
+
+

{{ 'labels.inputs.Loan Schedule Type' | translate }}

+

{{ loanScheduleType.value | translateKey: 'catalogs' }}

+
-
- } + } - - {{ 'labels.inputs.Repayment Strategy' | translate }} - - @for ( - transactionProcessingStrategy of transactionProcessingStrategyOptions; - track transactionProcessingStrategy - ) { - - {{ transactionProcessingStrategy.name | translateKey: 'catalogs' }} - + + {{ 'labels.inputs.Repayment Strategy' | translate }} + + @for ( + transactionProcessingStrategy of transactionProcessingStrategyOptions; + track transactionProcessingStrategy + ) { + + {{ transactionProcessingStrategy.name | translateKey: 'catalogs' }} + + } + + @if (loansAccountTermsForm.controls.transactionProcessingStrategyCode.hasError('required')) { + + {{ 'labels.inputs.Repayment Strategy' | translate }} {{ 'labels.commons.is' | translate }} + {{ 'labels.commons.required' | translate }} + } - - @if (loansAccountTermsForm.controls.transactionProcessingStrategyCode.hasError('required')) { - - {{ 'labels.inputs.Repayment Strategy' | translate }} {{ 'labels.commons.is' | translate }} - {{ 'labels.commons.required' | translate }} - - } - + -

{{ 'labels.heading.Interest Calculations' | translate }}

+

{{ 'labels.heading.Interest Calculations' | translate }}

- - {{ 'labels.inputs.Interest calculation period' | translate }} - - @for (interestCalculationPeriodType of interestCalculationPeriodTypeData; track interestCalculationPeriodType) { - - {{ interestCalculationPeriodType.value | translateKey: 'catalogs' }} - - } - - - - -

{{ 'labels.inputs.Calculate interest for exact days in partial period' | translate }}

-
- - @if (isProgressive) { - - -

{{ 'labels.inputs.Is interest recognition on disbursement date?' | translate }}

-
-
- } + + {{ 'labels.inputs.Interest calculation period' | translate }} + + @for ( + interestCalculationPeriodType of interestCalculationPeriodTypeData; + track interestCalculationPeriodType + ) { + + {{ interestCalculationPeriodType.value | translateKey: 'catalogs' }} + + } + + - - {{ 'labels.inputs.Arrears tolerance' | translate }} - - - - - {{ 'labels.inputs.Interest free period' | translate }} - - + +

{{ 'labels.inputs.Calculate interest for exact days in partial period' | translate }}

+
-

- {{ 'labels.heading.Moratorium' | translate }} - -

+ @if (isProgressive) { + + +

{{ 'labels.inputs.Is interest recognition on disbursement date?' | translate }}

+
+
+ } - - {{ 'labels.inputs.Grace on principal payment' | translate }} - - - - - {{ 'labels.inputs.Grace on interest payment' | translate }} - - - - - {{ 'labels.inputs.On arrears ageing' | translate }} - - - - @if (isDelinquencyEnabled()) { -
-

- {{ 'labels.inputs.Delinquency Bucket' | translate }} - {{ loanProduct?.delinquencyBucket.name }} -

-
- } + + {{ 'labels.inputs.Arrears tolerance' | translate }} + + - @if (loanProductService.isLoanProduct && isDelinquencyEnabled()) { -
- -

{{ 'labels.inputs.Enable installment level Delinquency' | translate }}

-
-
- } + + {{ 'labels.inputs.Interest free period' | translate }} + + - @if (loansAccountTermsData?.isTopup) { - - -

{{ 'labels.inputs.Is Topup Loan' | translate }}?

-
- @if (loansAccountTermsForm.controls.isTopup.value) { - - {{ 'labels.inputs.Loan closed with Topup' | translate }} - - @for (clientActiveLoan of clientActiveLoanData; track clientActiveLoan) { - - {{ clientActiveLoan.accountNo }} - - } - - - } -
- } +

+ {{ 'labels.heading.Moratorium' | translate }} + +

- + + {{ 'labels.inputs.Grace on principal payment' | translate }} + + -
- {{ 'labels.inputs.Recalculate Interest' | translate }} - {{ loansAccountTermsData?.isInterestRecalculationEnabled | yesNo }} -
+ + {{ 'labels.inputs.Grace on interest payment' | translate }} + + - @if (loansAccountTermsData?.isInterestRecalculationEnabled) { -
- {{ 'labels.inputs.Days in year' | translate }} - {{ loansAccountTermsData.daysInYearType.value | translateKey: 'catalogs' }} -
- } - @if (loansAccountTermsData?.isInterestRecalculationEnabled) { -
- {{ 'labels.inputs.Days in month' | translate }} - {{ loansAccountTermsData.daysInMonthType.value | translateKey: 'catalogs' }} -
- } - @if (loansAccountTermsData?.isInterestRecalculationEnabled) { -
- {{ 'labels.inputs.Advance payments adjustment type' | translate }} - {{ loansAccountTermsData.interestRecalculationData.rescheduleStrategyType.value }} -
- } + + {{ 'labels.inputs.On arrears ageing' | translate }} + + - @if (loansAccountTermsData?.isInterestRecalculationEnabled) { -
- {{ 'labels.inputs.Interest recalculation compounding on' | translate }} - {{ - loansAccountTermsData.interestRecalculationData.interestRecalculationCompoundingType.value - | translateKey: 'catalogs' - }} -
-
- {{ 'labels.inputs.Frequency Interval for recalculation' | translate }} - - {{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyType.value }} - @if ( - loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyType.id === 3 && - loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyWeekday - ) { - - on {{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyWeekday.value }} - } - @if ( - loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyType.id === 4 && - loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyOnDay - ) { - on day {{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyOnDay }} - } - @if ( - loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyType.id === 4 && - !loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyOnDay && - loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyNthDay - ) { - on - {{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyNthDay.value }} - {{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyWeekday.value }} +

+ {{ 'labels.inputs.Delinquency Bucket' | translate }} + {{ loanProduct?.delinquencyBucket.name }} +

+
+ +
+ +

{{ 'labels.inputs.Enable installment level Delinquency' | translate }}

+
+
+ } + + @if (loansAccountTermsData?.isTopup) { + + +

{{ 'labels.inputs.Is Topup Loan' | translate }}?

+
+ @if (loansAccountTermsForm.controls.isTopup.value) { + + {{ 'labels.inputs.Loan closed with Topup' | translate }} + + @for (clientActiveLoan of clientActiveLoanData; track clientActiveLoan) { + + {{ clientActiveLoan.accountNo }} + + } + + } - -
- } + + } + + - @if ( - loansAccountTermsData?.isInterestRecalculationEnabled && - loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyType.id !== 1 - ) {
- {{ 'labels.inputs.Frequency Interval for recalculation' | translate }} - {{ - loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyInterval - }} + {{ 'labels.inputs.Recalculate Interest' | translate }} + {{ loansAccountTermsData?.isInterestRecalculationEnabled | yesNo }}
- } -
- {{ 'labels.inputs.Enable income capitalization' | translate }} - {{ enableIncomeCapitalization | yesNo }} -
+ @if (loansAccountTermsData?.isInterestRecalculationEnabled) { +
+ {{ 'labels.inputs.Days in year' | translate }} + {{ loansAccountTermsData.daysInYearType.value | translateKey: 'catalogs' }} +
+ } + @if (loansAccountTermsData?.isInterestRecalculationEnabled) { +
+ {{ 'labels.inputs.Days in month' | translate }} + {{ loansAccountTermsData.daysInMonthType.value | translateKey: 'catalogs' }} +
+ } + @if (loansAccountTermsData?.isInterestRecalculationEnabled) { +
+ {{ 'labels.inputs.Advance payments adjustment type' | translate }} + {{ + loansAccountTermsData.interestRecalculationData.rescheduleStrategyType.value + }} +
+ } -
- {{ 'labels.inputs.Enable Buy down fee' | translate }} - {{ enableBuyDownFee | yesNo }} -
+ @if (loansAccountTermsData?.isInterestRecalculationEnabled) { +
+ {{ 'labels.inputs.Interest recalculation compounding on' | translate }} + {{ + loansAccountTermsData.interestRecalculationData.interestRecalculationCompoundingType.value + | translateKey: 'catalogs' + }} +
+
+ {{ 'labels.inputs.Frequency Interval for recalculation' | translate }} + + {{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyType.value }} + @if ( + loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyType.id === 3 && + loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyWeekday + ) { + + on {{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyWeekday.value }} + } + @if ( + loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyType.id === 4 && + loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyOnDay + ) { + on day {{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyOnDay }} + } + @if ( + loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyType.id === 4 && + !loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyOnDay && + loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyNthDay + ) { + on + {{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyNthDay.value }} + {{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyWeekday.value }} + } + +
+ } - @if (multiDisburseLoan) { - - @if (allowAddDisbursementDetails()) { + @if ( + loansAccountTermsData?.isInterestRecalculationEnabled && + loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyType.id !== 1 + ) {
-

{{ 'labels.heading.Loan Tranche Details' | translate }}

+ {{ 'labels.inputs.Frequency Interval for recalculation' | translate }} + {{ + loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyInterval + }}
} - @if (isFullTermTrancheEditable()) { - + {{ 'labels.inputs.Enable income capitalization' | translate }} - {{ 'labels.inputs.Allow full term for each tranche' | translate }} - - } + {{ enableIncomeCapitalization | yesNo }} + +
- - {{ 'labels.inputs.Maximum allowed outstanding balance' | translate }} - - @if (loansAccountTermsForm.controls.maxOutstandingLoanBalance.hasError('required')) { - - {{ 'labels.inputs.Maximum allowed outstanding balance' | translate }} - {{ 'labels.commons.is' | translate }} - {{ 'labels.commons.required' | translate }} - - } - - - - + {{ 'labels.inputs.Enable Buy down fee' | translate }} + {{ enableBuyDownFee | yesNo }}
- @if (!allowAddDisbursementDetails()) { + + @if (multiDisburseLoan) { + + @if (allowAddDisbursementDetails()) { +
+

{{ 'labels.heading.Loan Tranche Details' | translate }}

+
+ } + @if (isFullTermTrancheEditable()) { + + {{ 'labels.inputs.Allow full term for each tranche' | translate }} + + }
-

- {{ 'labels.heading.Loan Tranche Details are not allowed for this Loan Product' | translate }} -

-
- } - - - - - - - - - - - - - - - -
{{ 'labels.inputs.Expected Disbursement Date' | translate }} - {{ row.expectedDisbursementDate | dateFormat }} - {{ 'labels.inputs.Principal' | translate }} - {{ row.principal }} - {{ 'labels.inputs.Actions' | translate }} + + {{ 'labels.inputs.Maximum allowed outstanding balance' | translate }} + + @if (loansAccountTermsForm.controls.maxOutstandingLoanBalance.hasError('required')) { + + {{ 'labels.inputs.Maximum allowed outstanding balance' | translate }} + {{ 'labels.commons.is' | translate }} + {{ 'labels.commons.required' | translate }} + + } + + -
- } + + + @if (!allowAddDisbursementDetails()) { +
+

+ {{ 'labels.heading.Loan Tranche Details are not allowed for this Loan Product' | translate }} +

+
+ } + + + + + + + + + + + + + + + +
{{ 'labels.inputs.Expected Disbursement Date' | translate }} + {{ row.expectedDisbursementDate | dateFormat }} + {{ 'labels.inputs.Principal' | translate }} + {{ row.principal }} + {{ 'labels.inputs.Actions' | translate }} + +
+ } - @if ( - loansAccountTermsData?.isInterestRecalculationEnabled && - loansAccountTermsData.interestRecalculationData.interestRecalculationCompoundingType.id !== 0 - ) { -
- {{ 'labels.inputs.Frequency for compounding' | translate }} - {{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyType.value }} - @if ( - loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyType.id === 3 && - loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyWeekday - ) { - - on {{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyWeekday.value }} - - } - @if ( - loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyType.id === 4 && - loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyOnDay - ) { - on day - {{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyOnDay }} - - } - @if ( - loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyType.id === 4 && - !loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyOnDay && - loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyNthDay - ) { - on - {{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyNthDay.value }} - {{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyWeekday.value }} - - } - -
- } + @if ( + loansAccountTermsData?.isInterestRecalculationEnabled && + loansAccountTermsData.interestRecalculationData.interestRecalculationCompoundingType.id !== 0 + ) { +
+ {{ 'labels.inputs.Frequency for compounding' | translate }} + {{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyType.value }} + @if ( + loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyType.id === 3 && + loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyWeekday + ) { + + on {{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyWeekday.value }} + + } + @if ( + loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyType.id === 4 && + loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyOnDay + ) { + on day + {{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyOnDay }} + + } + @if ( + loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyType.id === 4 && + !loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyOnDay && + loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyNthDay + ) { + on + {{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyNthDay.value }} + {{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyWeekday.value }} + + } + +
+ } - @if ( - loansAccountTermsData?.isInterestRecalculationEnabled && - loansAccountTermsData.interestRecalculationData.interestRecalculationCompoundingType.id !== 0 && - loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyType.id !== 1 - ) { -
- {{ 'labels.inputs.Frequency Interval for compounding' | translate }} - {{ - loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyInterval - }} -
- } + @if ( + loansAccountTermsData?.isInterestRecalculationEnabled && + loansAccountTermsData.interestRecalculationData.interestRecalculationCompoundingType.id !== 0 && + loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyType.id !== 1 + ) { +
+ {{ 'labels.inputs.Frequency Interval for compounding' | translate }} + {{ + loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyInterval + }} +
+ } - + -
-
-

{{ 'labels.heading.Collaterals Data' | translate }}

-
+
+
+

{{ 'labels.heading.Collaterals Data' | translate }}

+
-
-
- +
+
+ +
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{{ 'labels.inputs.name' | translate }}{{ ele.type.name }}{{ 'labels.inputs.Quantity' | translate }}{{ ele.value }}{{ 'labels.inputs.Total Value' | translate }}{{ ele.type.basePrice * ele.value }}{{ 'labels.inputs.Total Collateral Value' | translate }}{{ (ele.type.pctToBase * ele.type.basePrice * ele.value) / 100 }}{{ 'labels.inputs.Actions' | translate }} - -
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{{ 'labels.inputs.name' | translate }}{{ ele.type.name }}{{ 'labels.inputs.Quantity' | translate }}{{ ele.value }}{{ 'labels.inputs.Total Value' | translate }}{{ ele.type.basePrice * ele.value }}{{ 'labels.inputs.Total Collateral Value' | translate }}{{ (ele.type.pctToBase * ele.type.basePrice * ele.value) / 100 }}{{ 'labels.inputs.Actions' | 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 5c3985394a..72d4675d6b 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 @@ -171,15 +171,12 @@ export class LoansAccountTermsStepComponent extends LoanProductBaseComponent imp enableBuyDownFee = false; isProgressive = false; - /** - * Create Loans Account Terms Form - * @param formBuilder FormBuilder - * @param {SettingsService} settingsService SettingsService - */ + allowAttributeOverrides: any | null = null; + constructor() { super(); - this.loanId = this.route.snapshot.params['loanId']; this.createloansAccountTermsForm(); + this.loanId = this.route.snapshot.params['loanId']; } /** * Executes on change of input values @@ -317,11 +314,33 @@ export class LoansAccountTermsStepComponent extends LoanProductBaseComponent imp ); } } + } else if (this.loanProductService.isWorkingCapital && this.loansAccountProductTemplate) { + this.loansAccountTermsData = this.loansAccountProductTemplate; + this.currency = this.loansAccountTermsData.currency; + this.termFrequencyTypeData = this.loansAccountTermsData.options.periodFrequencyTypeOptions; + this.loansAccountTermsForm.patchValue({ + principalAmount: this.loansAccountTermsData.product.principal + }); + this.allowAttributeOverrides = this.loansAccountProductTemplate.product.allowAttributeOverrides; + if ( + !this.allowAttributeOverrides.periodPaymentFrequency || + this.allowAttributeOverrides.periodPaymentFrequency === false + ) { + this.loansAccountTermsForm.controls.repaymentEvery.disable(); + } + if ( + !this.allowAttributeOverrides.periodPaymentFrequencyType || + this.allowAttributeOverrides.periodPaymentFrequencyType === false + ) { + this.loansAccountTermsForm.controls.repaymentFrequencyType.disable(); + } + if (!this.allowAttributeOverrides.discountDefault || this.allowAttributeOverrides.discountDefault === false) { + this.loansAccountTermsForm.controls.discount.disable(); + } } } ngOnInit() { - this.createloansAccountTermsForm(); this.maxDate = this.settingsService.maxFutureDate; this.loansAccountTermsData = this.loansAccountProductTemplate; if (this.loanProductService.isLoanProduct) { @@ -340,6 +359,15 @@ export class LoansAccountTermsStepComponent extends LoanProductBaseComponent imp repaymentsStartingFromDate: this.loansAccountTermsData.expectedFirstRepaymentOnDate && formattedDate }); } + if (this.isDelinquencyEnabled()) { + this.loansAccountTermsForm.addControl( + 'enableInstallmentLevelDelinquency', + new UntypedFormControl( + this.loansAccountTermsData.enableInstallmentLevelDelinquency || + this.loanProduct.enableInstallmentLevelDelinquency + ) + ); + } this.loansAccountTermsForm.patchValue({ principalAmount: this.loansAccountTermsData.principal, loanTermFrequency: this.loansAccountTermsData.termFrequency, @@ -368,12 +396,15 @@ export class LoansAccountTermsStepComponent extends LoanProductBaseComponent imp interestRecognitionOnDisbursementDate: this.loansAccountTermsData.interestRecognitionOnDisbursementDate || false }); + + if (this.loansAccountTermsData.loanScheduleType.code == LoanProducts.LOAN_SCHEDULE_TYPE_CUMULATIVE) { + this.loansAccountTermsForm.removeControl('interestRecognitionOnDisbursementDate'); + } } this.setAdvancedPaymentStrategyControls(); - // this.setCustomValidators(); + this.setCustomValidators(); this.setLoanTermListener(); - this.loansAccountTermsForm.removeControl('maxOutstandingLoanBalance'); if (this.allowAddDisbursementDetails()) { this.loansAccountTermsForm.removeControl('maxOutstandingLoanBalance'); this.loansAccountTermsForm.addControl( @@ -386,6 +417,15 @@ export class LoansAccountTermsStepComponent extends LoanProductBaseComponent imp new UntypedFormControl(this.loansAccountTermsData?.maxOutstandingLoanBalance ?? null) ); } + } else if (this.loanProductService.isWorkingCapital) { + if (this.loansAccountTermsData) { + this.loansAccountTermsForm.patchValue({ + principalAmount: this.loansAccountTermsData.principal || this.loansAccountTermsData.product.principal, + periodPaymentRate: this.loansAccountTermsData.periodPaymentRate, + repaymentEvery: this.loansAccountTermsData.repaymentEvery, + repaymentFrequencyType: this.loansAccountTermsData.repaymentFrequencyType.id + }); + } } } @@ -406,16 +446,13 @@ export class LoansAccountTermsStepComponent extends LoanProductBaseComponent imp const repaymentFrequencyDayOfWeekType = this.loansAccountTermsForm.get('repaymentFrequencyDayOfWeekType'); this.loansAccountTermsForm.get('repaymentFrequencyType').valueChanges.subscribe((repaymentFrequencyType) => { - if (repaymentFrequencyType === 2) { - repaymentFrequencyNthDayType.setValidators([Validators.required]); - repaymentFrequencyDayOfWeekType.setValidators([Validators.required]); - } else { - repaymentFrequencyNthDayType.setValidators(null); - repaymentFrequencyDayOfWeekType.setValidators(null); - } + repaymentFrequencyNthDayType.setValidators(null); + repaymentFrequencyDayOfWeekType.setValidators(null); - repaymentFrequencyNthDayType.updateValueAndValidity(); - repaymentFrequencyDayOfWeekType.updateValueAndValidity(); + setTimeout(() => { + repaymentFrequencyNthDayType.updateValueAndValidity(); + repaymentFrequencyDayOfWeekType.updateValueAndValidity(); + }); }); } @@ -482,65 +519,97 @@ export class LoansAccountTermsStepComponent extends LoanProductBaseComponent imp /** Create Loans Account Terms Form */ createloansAccountTermsForm() { - this.loansAccountTermsForm = this.formBuilder.group({ - principalAmount: [ - '', - Validators.required - ], - loanTermFrequency: [ - { value: '', disabled: true }, - Validators.required - ], - loanTermFrequencyType: [ - '', - Validators.required - ], - numberOfRepayments: [ - '', - Validators.required - ], - repaymentEvery: [ - '', - Validators.required - ], - repaymentFrequencyType: [ - { value: '', disabled: true }, - Validators.required - ], - repaymentFrequencyNthDayType: [''], - repaymentFrequencyDayOfWeekType: [''], - repaymentsStartingFromDate: [''], - interestChargedFromDate: [''], - interestRatePerPeriod: [''], - interestType: [''], - isFloatingInterestRate: [null], - isEqualAmortization: [''], - amortizationType: [ - '', - Validators.required - ], - interestCalculationPeriodType: [''], - allowPartialPeriodInterestCalculation: [''], - inArrearsTolerance: [''], - graceOnInterestCharged: [''], - graceOnPrincipalPayment: [''], - graceOnInterestPayment: [''], - graceOnArrearsAgeing: [''], - loanIdToClose: [''], - fixedEmiAmount: [''], - isTopup: [''], - maxOutstandingLoanBalance: [''], - interestRateDifferential: [''], - transactionProcessingStrategyCode: [ - '', - Validators.required - ], - multiDisburseLoan: [false], - interestRateFrequencyType: [''], - balloonRepaymentAmount: [''], - interestRecognitionOnDisbursementDate: [false], - allowFullTermForTranche: [false] - }); + if (this.loanProductService.isLoanProduct) { + this.loansAccountTermsForm = this.formBuilder.group({ + principalAmount: [ + '', + Validators.required + ], + loanTermFrequency: [ + { value: '', disabled: true }, + Validators.required + ], + loanTermFrequencyType: [ + '', + Validators.required + ], + numberOfRepayments: [ + '', + Validators.required + ], + repaymentEvery: [ + '', + Validators.required + ], + repaymentFrequencyType: [ + { value: '', disabled: true }, + Validators.required + ], + repaymentFrequencyNthDayType: [''], + repaymentFrequencyDayOfWeekType: [''], + repaymentsStartingFromDate: [''], + interestChargedFromDate: [''], + interestRatePerPeriod: [''], + interestType: [''], + isFloatingInterestRate: [null], + isEqualAmortization: [''], + amortizationType: [ + '', + Validators.required + ], + interestCalculationPeriodType: [''], + allowPartialPeriodInterestCalculation: [''], + inArrearsTolerance: [''], + graceOnInterestCharged: [''], + graceOnPrincipalPayment: [''], + graceOnInterestPayment: [''], + graceOnArrearsAgeing: [''], + loanIdToClose: [''], + fixedEmiAmount: [''], + isTopup: [''], + maxOutstandingLoanBalance: [''], + interestRateDifferential: [''], + transactionProcessingStrategyCode: [ + '', + Validators.required + ], + multiDisburseLoan: [false], + interestRateFrequencyType: [''], + balloonRepaymentAmount: [''], + interestRecognitionOnDisbursementDate: [false], + allowFullTermForTranche: [false] + }); + } else if (this.loanProductService.isWorkingCapital) { + this.loansAccountTermsForm = this.formBuilder.group({ + principalAmount: [ + '', + Validators.required + ], + totalPayment: [ + '', + Validators.required + ], + discount: [''], + periodPaymentRate: [ + '', + [ + Validators.required, + Validators.min(1) + ] + ], + repaymentEvery: [ + '', + [ + Validators.required, + Validators.min(1) + ] + ], + repaymentFrequencyType: [ + '', + Validators.required + ] + }); + } } calculateLoanTerm(numberOfRepayments: number, repaymentEvery: number): void { diff --git a/src/app/loans/loans-routing.module.ts b/src/app/loans/loans-routing.module.ts index 23dc4b0071..c6270046ba 100644 --- a/src/app/loans/loans-routing.module.ts +++ b/src/app/loans/loans-routing.module.ts @@ -77,6 +77,7 @@ import { LoanDeferredIncomeDataResolver } from './common-resolvers/loan-deferred import { LoanBuyDownFeesDataResolver } from './common-resolvers/loan-buy-down-fees-data.resolver'; import { LoanOriginatorsTabComponent } from './loans-view/loan-originators-tab/loan-originators-tab.component'; import { LoanOriginatorsResolver } from './common-resolvers/loan-originators.resolver'; +import { LoanProductsResolver } from './common-resolvers/loan-products.resolver'; /** Loans Route. */ const routes: Routes = [ @@ -89,7 +90,8 @@ const routes: Routes = [ data: { title: 'Create Loans Account', breadcrumb: 'Create Loans Account' }, component: CreateLoansAccountComponent, resolve: { - loansAccountTemplate: LoansAccountTemplateResolver + loansAccountTemplate: LoansAccountTemplateResolver, + loanProductsBasicDetails: LoanProductsResolver } }, { @@ -205,7 +207,6 @@ const routes: Routes = [ component: LoanTermVariationsTabComponent, data: { title: 'Loan Term Variations', breadcrumb: 'Loan Term Variations', routeParamBreadcrumb: false }, resolve: { - loanDetailsData: LoanDetailsResolver, interestPausesData: LoanTermVariationsResolver } }, @@ -337,6 +338,7 @@ const routes: Routes = [ data: { title: 'Modify Loans Account', breadcrumb: 'Modify Loans Account', routeParamBreadcrumb: 'Edit' }, component: EditLoansAccountComponent, resolve: { + loanProductsBasicDetails: LoanProductsResolver, loansAccountAndTemplate: LoansAccountAndTemplateResolver } }, @@ -444,7 +446,8 @@ const routes: Routes = [ LoanDelinquencyDataResolver, LoanTermVariationsResolver, LoanDeferredIncomeDataResolver, - LoanBuyDownFeesDataResolver + LoanBuyDownFeesDataResolver, + LoanProductsResolver ] }) export class LoansRoutingModule {} diff --git a/src/app/loans/loans-view/account-details/account-details.component.html b/src/app/loans/loans-view/account-details/account-details.component.html index 5989ad61af..b83bd49e6b 100644 --- a/src/app/loans/loans-view/account-details/account-details.component.html +++ b/src/app/loans/loans-view/account-details/account-details.component.html @@ -10,169 +10,200 @@

{{ 'labels.heading.Loan Details' | translate }}

-
- {{ 'labels.inputs.Repayment Strategy' | translate }} - {{ loanDetails.transactionProcessingStrategyName | translateKey: 'catalogs' }} -
- -
- {{ 'labels.inputs.Repayments' | translate }} - {{ loanDetails.numberOfRepayments }} {{ 'labels.commons.every' | translate }} - {{ loanDetails.repaymentEvery }} {{ loanDetails.repaymentFrequencyType.value | translateKey: 'catalogs' }} - @if ( - loanDetails.repaymentFrequencyType?.id === 2 && - loanDetails.repaymentFrequencyNthDayType?.id !== 0 && - loanDetails.repaymentFrequencyDayOfWeekType?.id !== 0 - ) { - - @if (loanDetails.repaymentFrequencyDayOfWeekType) { - - {{ 'labels.commons.on' | translate }}{{ loanDetails.repaymentFrequencyNthDayType?.value }} - {{ - loanDetails.repaymentFrequencyDayOfWeekType?.value | translateKey: 'catalogs' - }} - - } - - } - -
- - @if (loanDetails.fixedLength) { + @if (loanDetails.transactionProcessingStrategyName) {
- {{ 'labels.inputs.Fixed Length' | translate }} - - {{ loanDetails.fixedLength }} {{ loanDetails.repaymentFrequencyType.value | translateKey: 'catalogs' }} + {{ 'labels.inputs.Repayment Strategy' | translate }} + {{ loanDetails.transactionProcessingStrategyName | translateKey: 'catalogs' }}
} -
- {{ 'labels.inputs.Amortization' | translate }} - {{ loanDetails.amortizationType.value | translateKey: 'catalogs' }} -
- - @if (loanDetails.fixedPrincipalPercentagePerInstallment) { + @if (loanProductService.isWorkingCapital) {
- {{ 'labels.inputs.Principal Percentage Per Installment' | translate }} - {{ loanDetails.fixedPrincipalPercentagePerInstallment | formatNumber }} % + {{ 'labels.inputs.Period Payment Frequency' | translate }} + + {{ loanDetails.repaymentEvery }} + {{ camalize(loanDetails.repaymentFrequencyType.value) | translateKey: 'catalogs' }} +
- } -
- {{ 'labels.inputs.Equal Amortization' | translate }} - {{ loanDetails.isEqualAmortization | yesNo }} -
+ @if (loanDetails.periodPaymentRate) { +
+ {{ 'labels.inputs.Period Payment Rate' | translate }} + {{ loanDetails.periodPaymentRate | formatNumber }} % +
+ } -
- {{ 'labels.inputs.Interest' | translate }} - - {{ loanDetails.annualInterestRate | formatNumber }} % {{ 'labels.text.per annum' | translate }} ({{ - loanDetails.interestRatePerPeriod - }} - %  {{ loanDetails.interestRateFrequencyType.value | translateKey: 'catalogs' }}) - -
+ @if (loanDetails.discount) { +
+ {{ 'labels.inputs.Discount' | translate }} + {{ loanDetails.discount | formatNumber }} +
+ } + } -
- {{ 'labels.inputs.Interest Type' | translate }} - {{ 'labels.text.' + loanDetails.interestType.value | translate }} -
+ @if (loanProductService.isLoanProduct) { +
+ {{ 'labels.inputs.Repayments' | translate }} + {{ loanDetails.numberOfRepayments }} {{ 'labels.commons.every' | translate }} + {{ loanDetails.repaymentEvery }} {{ + loanDetails.repaymentFrequencyType.value | translateKey: 'catalogs' + }} + @if ( + loanDetails.repaymentFrequencyType?.id === 2 && + loanDetails.repaymentFrequencyNthDayType?.id !== 0 && + loanDetails.repaymentFrequencyDayOfWeekType?.id !== 0 + ) { + + @if (loanDetails.repaymentFrequencyDayOfWeekType) { + + {{ 'labels.commons.on' | translate }}{{ loanDetails.repaymentFrequencyNthDayType?.value }} + {{ + loanDetails.repaymentFrequencyDayOfWeekType?.value | translateKey: 'catalogs' + }} + + } + + } + +
-
- {{ 'labels.inputs.Enable Down Payments' | translate }}: - {{ loanDetails.enableDownPayment | yesNo }} -
+ @if (loanDetails.fixedLength) { +
+ {{ 'labels.inputs.Fixed Length' | translate }} + + {{ loanDetails.fixedLength }} + {{ loanDetails.repaymentFrequencyType.value | translateKey: 'catalogs' }} +
+ } -
- {{ 'labels.inputs.Loan Charge-off behaviour' | translate }}: - {{ loanDetails.chargeOffBehaviour.value | translateKey: 'catalogs' }} -
+
+ {{ 'labels.inputs.Amortization' | translate }} + {{ loanDetails.amortizationType.value | translateKey: 'catalogs' }} +
-
- {{ 'labels.inputs.Enable income capitalization' | translate }} - {{ loanDetails.enableIncomeCapitalization | yesNo }} -
+ @if (loanDetails.fixedPrincipalPercentagePerInstallment) { +
+ {{ 'labels.inputs.Principal Percentage Per Installment' | translate }} + {{ loanDetails.fixedPrincipalPercentagePerInstallment | formatNumber }} % +
+ } - @if (loanDetails.enableIncomeCapitalization) {
- {{ 'labels.inputs.Income capitalization calculation type' | translate }} + {{ 'labels.inputs.Equal Amortization' | translate }} + {{ loanDetails.isEqualAmortization | yesNo }} +
+ +
+ {{ 'labels.inputs.Interest' | translate }} - {{ loanDetails.capitalizedIncomeCalculationType?.value | translateKey: 'catalogs' }} + {{ loanDetails.annualInterestRate | formatNumber }} % {{ 'labels.text.per annum' | translate }} ({{ + loanDetails.interestRatePerPeriod + }} + %  {{ loanDetails.interestRateFrequencyType.value | translateKey: 'catalogs' }})
- } - @if (loanDetails.enableIncomeCapitalization) {
- {{ 'labels.inputs.Income capitalization strategy' | translate }} - {{ loanDetails.capitalizedIncomeStrategy?.value | translateKey: 'catalogs' }} + {{ 'labels.inputs.Interest Type' | translate }} + {{ 'labels.text.' + loanDetails.interestType.value | translate }}
- } - @if (loanDetails.enableIncomeCapitalization) {
- {{ 'labels.inputs.Income capitalization type' | translate }} - {{ loanDetails.capitalizedIncomeType?.value | translateKey: 'catalogs' }} + {{ 'labels.inputs.Enable Down Payments' | translate }}: + {{ loanDetails.enableDownPayment | yesNo }}
- } - -
- {{ 'labels.inputs.Enable Buy down fee' | translate }} - {{ loanDetails.enableBuyDownFee | yesNo }} -
- @if (loanDetails.enableBuyDownFee) {
- {{ 'labels.inputs.Buy down fee calculation type' | translate }} - - {{ loanDetails.buyDownFeeCalculationType?.value | translateKey: 'catalogs' }} - + {{ 'labels.inputs.Loan Charge-off behaviour' | translate }}: + {{ loanDetails.chargeOffBehaviour.value | translateKey: 'catalogs' }}
- } - @if (loanDetails.enableBuyDownFee) {
- {{ 'labels.inputs.Buy down fee strategy' | translate }} - {{ loanDetails.buyDownFeeStrategy?.value | translateKey: 'catalogs' }} + {{ 'labels.inputs.Enable income capitalization' | translate }} + {{ loanDetails.enableIncomeCapitalization | yesNo }}
- } - @if (loanDetails.enableBuyDownFee) { + @if (loanDetails.enableIncomeCapitalization) { +
+ {{ 'labels.inputs.Income capitalization calculation type' | translate }} + + {{ loanDetails.capitalizedIncomeCalculationType?.value | translateKey: 'catalogs' }} + +
+ } + + @if (loanDetails.enableIncomeCapitalization) { +
+ {{ 'labels.inputs.Income capitalization strategy' | translate }} + {{ loanDetails.capitalizedIncomeStrategy?.value | translateKey: 'catalogs' }} +
+ } + + @if (loanDetails.enableIncomeCapitalization) { +
+ {{ 'labels.inputs.Income capitalization type' | translate }} + {{ loanDetails.capitalizedIncomeType?.value | translateKey: 'catalogs' }} +
+ } +
- {{ 'labels.inputs.Buy down fee income type' | translate }} - {{ loanDetails.buyDownFeeIncomeType?.value | translateKey: 'catalogs' }} + {{ 'labels.inputs.Enable Buy down fee' | translate }} + {{ loanDetails.enableBuyDownFee | yesNo }}
- } - @if (loanDetails.enableBuyDownFee) { + @if (loanDetails.enableBuyDownFee) { +
+ {{ 'labels.inputs.Buy down fee calculation type' | translate }} + + {{ loanDetails.buyDownFeeCalculationType?.value | translateKey: 'catalogs' }} + +
+ } + + @if (loanDetails.enableBuyDownFee) { +
+ {{ 'labels.inputs.Buy down fee strategy' | translate }} + {{ loanDetails.buyDownFeeStrategy?.value | translateKey: 'catalogs' }} +
+ } + + @if (loanDetails.enableBuyDownFee) { +
+ {{ 'labels.inputs.Buy down fee income type' | translate }} + {{ loanDetails.buyDownFeeIncomeType?.value | translateKey: 'catalogs' }} +
+ } + + @if (loanDetails.enableBuyDownFee) { +
+ {{ 'labels.inputs.Merchant Buy down fee' | translate }} + {{ loanDetails.merchantBuyDownFee | yesNo }} +
+ } +
- {{ 'labels.inputs.Merchant Buy down fee' | translate }} - {{ loanDetails.merchantBuyDownFee | yesNo }} + {{ 'labels.inputs.Grace: On Principal Payment' | translate }} + {{ loanDetails.graceOnPrincipalPayment }}
- } - -
- {{ 'labels.inputs.Grace: On Principal Payment' | translate }} - {{ loanDetails.graceOnPrincipalPayment }} -
-
- {{ 'labels.inputs.Grace: On Interest Payment' | translate }} - {{ loanDetails.graceOnInterestPayment }} -
+
+ {{ 'labels.inputs.Grace: On Interest Payment' | translate }} + {{ loanDetails.graceOnInterestPayment }} +
-
- {{ 'labels.inputs.Grace on Arrears Ageing' | translate }} - {{ loanDetails.graceOnArrearsAgeing }} -
+
+ {{ 'labels.inputs.Grace on Arrears Ageing' | translate }} + {{ loanDetails.graceOnArrearsAgeing }} +
-
- {{ 'labels.inputs.Enable installment level Delinquency' | translate }} - {{ loanDetails.enableInstallmentLevelDelinquency | yesNo }} -
+
+ {{ 'labels.inputs.Enable installment level Delinquency' | translate }} + {{ loanDetails.enableInstallmentLevelDelinquency | yesNo }} +
+ }
{{ 'labels.inputs.Fund Source' | translate }} @@ -184,27 +215,29 @@

{{ 'labels.heading.Loan Details' | translate }}

}
-
- {{ 'labels.inputs.Interest Free Period' | translate }} - {{ loanDetails.graceOnInterestCharged }} -
+ @if (loanProductService.isLoanProduct) { +
+ {{ 'labels.inputs.Interest Free Period' | translate }} + {{ loanDetails.graceOnInterestCharged }} +
-
- {{ 'labels.inputs.Interest Calculation Period' | translate }} - {{ loanDetails.interestCalculationPeriodType.value | translateKey: 'catalogs' }} -
+
+ {{ 'labels.inputs.Interest Calculation Period' | translate }} + {{ loanDetails.interestCalculationPeriodType.value | translateKey: 'catalogs' }} +
-
- - {{ 'labels.inputs.Allow Partial Interest Calculation with same as repayment' | translate }} - {{ loanDetails.allowPartialPeriodInterestCalculation | yesNo }} -
+
+ + {{ 'labels.inputs.Allow Partial Interest Calculation with same as repayment' | translate }} + {{ loanDetails.allowPartialPeriodInterestCalculation | yesNo }} +
-
- {{ 'labels.inputs.Is interest recognition on disbursement date?' | translate }}: - {{ loanDetails.interestRecognitionOnDisbursementDate | yesNo }} -
+
+ {{ 'labels.inputs.Is interest recognition on disbursement date?' | translate }}: + {{ loanDetails.interestRecognitionOnDisbursementDate | yesNo }} +
+ }
{{ 'labels.inputs.Submitted on' | translate }} @@ -226,104 +259,111 @@

{{ 'labels.heading.Loan Details' | translate }}

{{ loanDetails.timeline.expectedMaturityDate | dateFormat }}
- @if (loanDetails.canDefineInstallmentAmount) { -
- {{ 'labels.inputs.Fixed EMI amount' | translate }} - {{ loanDetails.fixedEmiAmount | formatNumber }} -
- } - - @if (loanDetails.isTopup) { -
- {{ 'labels.inputs.Is Topup Loan' | translate }}? - {{ loanDetails.isTopup | yesNo }} -
- } - - @if (loanDetails.isTopup) { -
- {{ 'labels.inputs.Loan closed with Topup' | translate }} - - {{ loanDetails.closureLoanAccountNo }} - -
- } - - @if (loanDetails.isTopup) { -
- {{ 'labels.inputs.Topup closure amount' | translate }} - {{ loanDetails.topupAmount | formatNumber }} -
- } + @if (loanProductService.isLoanProduct) { + @if (loanDetails.canDefineInstallmentAmount) { +
+ {{ 'labels.inputs.Fixed EMI amount' | translate }} + {{ loanDetails.fixedEmiAmount | formatNumber }} +
+ } -
- {{ 'labels.inputs.Recalculate Interest based on new terms' | translate }} - {{ loanDetails.isInterestRecalculationEnabled | yesNo }} -
+ @if (loanDetails.isTopup) { +
+ {{ 'labels.inputs.Is Topup Loan' | translate }}? + {{ loanDetails.isTopup | yesNo }} +
+ } -
- {{ 'labels.inputs.Days in year' | translate }} - {{ loanDetails.daysInYearType.value | translateKey: 'catalogs' }} -
+ @if (loanDetails.isTopup) { +
+ {{ 'labels.inputs.Loan closed with Topup' | translate }} + + {{ loanDetails.closureLoanAccountNo }} + +
+ } -
- {{ 'labels.inputs.Days in month' | translate }} - {{ loanDetails.daysInMonthType.value | translateKey: 'catalogs' }} -
+ @if (loanDetails.isTopup) { +
+ {{ 'labels.inputs.Topup closure amount' | translate }} + {{ loanDetails.topupAmount | formatNumber }} +
+ } - @if (loanDetails.isInterestRecalculationEnabled) {
- {{ 'labels.inputs.Interest recalculation compounding on' | translate }} - - {{ - loanDetails.interestRecalculationData.interestRecalculationCompoundingType.value | translateKey: 'catalogs' - }} - + {{ 'labels.inputs.Recalculate Interest based on new terms' | translate }} + {{ loanDetails.isInterestRecalculationEnabled | yesNo }}
- } - @if (loanDetails.isInterestRecalculationEnabled) {
- {{ 'labels.inputs.Advance payments adjustment type' | translate }} - - {{ loanDetails.interestRecalculationData.rescheduleStrategyType.value | translateKey: 'catalogs' }} - + {{ 'labels.inputs.Days in year' | translate }} + {{ loanDetails.daysInYearType.value | translateKey: 'catalogs' }}
- } - @if (loanDetails.isInterestRecalculationEnabled) {
- {{ 'labels.inputs.Frequency for recalculate Outstanding Principal' | translate }} - {{ loanDetails.interestRecalculationData.calendarData.humanReadable }} + {{ 'labels.inputs.Days in month' | translate }} + {{ loanDetails.daysInMonthType.value | translateKey: 'catalogs' }}
- } - @if ( - loanDetails.isInterestRecalculationEnabled && - loanDetails.interestRecalculationData.interestRecalculationCompoundingType.id !== 0 - ) { -
- {{ 'labels.inputs.Frequency for compounding' | translate }} - {{ loanDetails.interestRecalculationData.compoundingCalendarData.humanReadable }} -
- } + @if (loanDetails.isInterestRecalculationEnabled) { +
+ {{ 'labels.inputs.Interest recalculation compounding on' | translate }} + + {{ + loanDetails.interestRecalculationData.interestRecalculationCompoundingType.value + | translateKey: 'catalogs' + }} + +
+ } - @if (loanDetails.isVariableInstallmentsAllowed) { -
- {{ 'labels.inputs.Variable Installments Allowed' | translate }} - {{ loanDetails.isVariableInstallmentsAllowed | yesNo }} -
- } + @if (loanDetails.isInterestRecalculationEnabled) { +
+ {{ 'labels.inputs.Advance payments adjustment type' | translate }} + + {{ loanDetails.interestRecalculationData.rescheduleStrategyType.value | translateKey: 'catalogs' }} + +
+ } - @if (loanDetails.isVariableInstallmentsAllowed) { -
- {{ 'labels.inputs.Gap between Installments' | translate }} - - {{ loanDetails.minimumGap | formatNumber }} {{ 'labels.text.Days' | translate }} , Max:{{ - loanDetails.maximumGap | formatNumber - }} {{ 'labels.text.Days' | translate }} - -
+ @if (loanDetails.isInterestRecalculationEnabled) { +
+ + {{ 'labels.inputs.Frequency for recalculate Outstanding Principal' | translate }} + {{ loanDetails.interestRecalculationData.calendarData.humanReadable }} +
+ } + + @if ( + loanDetails.isInterestRecalculationEnabled && + loanDetails.interestRecalculationData.interestRecalculationCompoundingType.id !== 0 + ) { +
+ {{ 'labels.inputs.Frequency for compounding' | translate }} + + {{ loanDetails.interestRecalculationData.compoundingCalendarData.humanReadable }} + +
+ } + + @if (loanDetails.isVariableInstallmentsAllowed) { +
+ {{ 'labels.inputs.Variable Installments Allowed' | translate }} + {{ loanDetails.isVariableInstallmentsAllowed | yesNo }} +
+ } + + @if (loanDetails.isVariableInstallmentsAllowed) { +
+ {{ 'labels.inputs.Gap between Installments' | translate }} + + {{ loanDetails.minimumGap | formatNumber }} {{ 'labels.text.Days' | translate }} , Max:{{ + loanDetails.maximumGap | formatNumber + }} {{ 'labels.text.Days' | translate }} + +
+ } } @if ( diff --git a/src/app/loans/loans-view/account-details/account-details.component.ts b/src/app/loans/loans-view/account-details/account-details.component.ts index ca3bf59535..ba440f8356 100644 --- a/src/app/loans/loans-view/account-details/account-details.component.ts +++ b/src/app/loans/loans-view/account-details/account-details.component.ts @@ -12,6 +12,7 @@ import { DateFormatPipe } from '../../../pipes/date-format.pipe'; import { FormatNumberPipe } from '../../../pipes/format-number.pipe'; import { YesnoPipe } from '../../../pipes/yesno.pipe'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; +import { LoanProductBaseComponent } from 'app/products/loan-products/common/loan-product-base.component'; @Component({ selector: 'mifosx-account-details', @@ -24,7 +25,7 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; YesnoPipe ] }) -export class AccountDetailsComponent { +export class AccountDetailsComponent extends LoanProductBaseComponent { private route = inject(ActivatedRoute); loanDetails: any; @@ -34,8 +35,14 @@ export class AccountDetailsComponent { }[]; constructor() { + super(); + this.loanProductService.initialize(LoanProductBaseComponent.resolveProductTypeDefault(this.route, 'loan')); this.route.parent.data.subscribe((data: { loanDetailsData: any }) => { this.loanDetails = data.loanDetailsData; }); } + + camalize(word: string) { + return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(); + } } diff --git a/src/app/loans/loans-view/charges-tab/charges-tab.component.ts b/src/app/loans/loans-view/charges-tab/charges-tab.component.ts index 871822c85e..c6ca989ce0 100644 --- a/src/app/loans/loans-view/charges-tab/charges-tab.component.ts +++ b/src/app/loans/loans-view/charges-tab/charges-tab.component.ts @@ -8,7 +8,7 @@ /** Angular Imports */ import { Component, OnInit, ViewChild, inject } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; +import { ActivatedRoute } from '@angular/router'; import { MatDialog } from '@angular/material/dialog'; import { MatPaginator } from '@angular/material/paginator'; import { MatSort, MatSortHeader } from '@angular/material/sort'; @@ -49,6 +49,7 @@ import { DateFormatPipe } from '../../../pipes/date-format.pipe'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; import { LoanCharge } from 'app/loans/models/loan-charge.model'; import { FormatNumberPipe } from '@pipes/format-number.pipe'; +import { LoanAccountTabBaseComponent } from '../loan-account-tab-base.component'; @Component({ selector: 'mifosx-charges-tab', @@ -75,11 +76,10 @@ import { FormatNumberPipe } from '@pipes/format-number.pipe'; FormatNumberPipe ] }) -export class ChargesTabComponent implements OnInit { +export class ChargesTabComponent extends LoanAccountTabBaseComponent implements OnInit { private loansService = inject(LoansService); private route = inject(ActivatedRoute); private dateUtils = inject(Dates); - private router = inject(Router); private translateService = inject(TranslateService); private dialog = inject(MatDialog); private settingsService = inject(SettingsService); @@ -120,6 +120,7 @@ export class ChargesTabComponent implements OnInit { * @param {SettingsService} settingsService Settings Service */ constructor() { + super(); this.route.parent.data.subscribe((data: { loanDetailsData: any }) => { this.loanDetails = data.loanDetailsData; }); @@ -159,7 +160,12 @@ export class ChargesTabComponent implements OnInit { * @param {any} chargeId Charge Id */ adjustCharge(chargeId: string) { - this.router.navigate([`${chargeId}/adjustment`], { relativeTo: this.route }); + this.router.navigate([`${chargeId}/adjustment`], { + queryParams: { + productType: this.loanProductService.productType.value + }, + relativeTo: this.route + }); } /** @@ -287,18 +293,6 @@ export class ChargesTabComponent implements OnInit { $event.stopPropagation(); } - /** - * Refetches data fot the component - * TODO: Replace by a custom reload component instead of hard-coded back-routing. - */ - private reload() { - const clientId = this.loanDetails.clientId; - const url: string = this.router.url; - this.router - .navigateByUrl(`/clients/${clientId}/loans-accounts`, { skipLocationChange: true }) - .then(() => this.router.navigate([url])); - } - isPercentageCharge(loanCharge: LoanCharge): boolean { return loanCharge.chargeCalculationType.code.includes('.percent.'); } diff --git a/src/app/loans/loans-view/external-asset-owner-tab/external-asset-owner-tab.component.ts b/src/app/loans/loans-view/external-asset-owner-tab/external-asset-owner-tab.component.ts index 94a8493fe7..81b334f398 100644 --- a/src/app/loans/loans-view/external-asset-owner-tab/external-asset-owner-tab.component.ts +++ b/src/app/loans/loans-view/external-asset-owner-tab/external-asset-owner-tab.component.ts @@ -8,7 +8,7 @@ import { Component, OnInit, inject } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; -import { ActivatedRoute, Router, RouterLink } from '@angular/router'; +import { ActivatedRoute } from '@angular/router'; import { ExternalAssetOwner } from 'app/loans/services/external-asset-owner'; import { ExternalAssetOwnerService } from 'app/loans/services/external-asset-owner.service'; import { CancelDialogComponent } from 'app/shared/cancel-dialog/cancel-dialog.component'; @@ -31,6 +31,7 @@ import { MatTooltip } from '@angular/material/tooltip'; import { DateFormatPipe } from '../../../pipes/date-format.pipe'; import { FormatNumberPipe } from '../../../pipes/format-number.pipe'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; +import { LoanAccountTabBaseComponent } from '../loan-account-tab-base.component'; @Component({ selector: 'mifosx-external-asset-owner-tab', @@ -57,9 +58,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; FormatNumberPipe ] }) -export class ExternalAssetOwnerTabComponent implements OnInit { +export class ExternalAssetOwnerTabComponent extends LoanAccountTabBaseComponent implements OnInit { private route = inject(ActivatedRoute); - private router = inject(Router); private dialog = inject(MatDialog); private externalAssetOwner = inject(ExternalAssetOwner); private externalAssetOwnerService = inject(ExternalAssetOwnerService); @@ -81,6 +81,7 @@ export class ExternalAssetOwnerTabComponent implements OnInit { existActiveTransfer = false; constructor() { + super(); this.route.data.subscribe((data: { loanTransfersData: any; activeTransferData: any }) => { this.loanTransfersData = data.loanTransfersData.empty ? [] : data.loanTransfersData.content; this.activeTransferData = data.activeTransferData || null; @@ -128,7 +129,12 @@ export class ExternalAssetOwnerTabComponent implements OnInit { } saleLoan(): void { - this.router.navigate(['../actions/Sell Loan'], { relativeTo: this.route }); + this.router.navigate(['../actions/Sell Loan'], { + queryParams: { + productType: this.loanProductService.productType.value + }, + relativeTo: this.route + }); } cancelSaleLoan(): void { @@ -150,15 +156,15 @@ export class ExternalAssetOwnerTabComponent implements OnInit { } buyBackLoan(): void { - this.router.navigate(['../actions/Buy Back Loan'], { relativeTo: this.route }); + this.router.navigate(['../actions/Buy Back Loan'], { + queryParams: { + productType: this.loanProductService.productType.value + }, + relativeTo: this.route + }); } routeJournalEntry(ev: MouseEvent): void { ev.stopPropagation(); } - - reload() { - const url: string = this.router.url; - this.router.navigateByUrl(`/`, { skipLocationChange: true }).then(() => this.router.navigate([url])); - } } diff --git a/src/app/loans/loans-view/general-tab/general-tab.component.html b/src/app/loans/loans-view/general-tab/general-tab.component.html index 672ac9fc19..955d2348cc 100644 --- a/src/app/loans/loans-view/general-tab/general-tab.component.html +++ b/src/app/loans/loans-view/general-tab/general-tab.component.html @@ -87,9 +87,7 @@

{{ 'labels.heading.Loan Summary' | translate }}

- } - @if (loanDetails.summary) {

{{ 'labels.heading.Loan Details' | translate }}

@@ -156,7 +154,20 @@

{{ 'labels.heading.Loan Details' | translate }}

} } @if (ele.key === 'Proposed Amount' || ele.key === 'Approved Amount' || ele.key === 'Disburse Amount') { - {{ ele.value }} + {{ ele.value | currency: currencyCode : 'symbol-narrow' : '1.2-2' }} + } + @if (ele.key === 'Product Type') { + {{ loanProductType() | translate }} + } + @if (ele.key === 'Product Name') { + {{ + loanDetails.loanProductName || loanDetails.product.name || ('labels.inputs.Not Available' | translate) + }} + + } + @if (ele.key === 'Status') { + {{ 'labels.status.' + loanDetails.status.value | translate }} } @@ -215,37 +226,55 @@

{{ 'labels.heading.Loan Details' | translate }}

{{ 'labels.inputs.Not Available' | translate }} } } + @if (ele.key === 'Product Type') { + {{ loanProductType() | translate }} + } + @if (ele.key === 'Product Name') { + {{ + loanDetails.loanProductName || loanDetails.product.name || ('labels.inputs.Not Available' | translate) + }} + + } + @if (ele.key === 'Status') { + {{ 'labels.status.' + loanDetails.status.value | translate }} + } + @if (ele.key === 'Loan Purpose') { + @if (!loanDetails.loanPurposeName) { + {{ 'labels.inputs.Not Provided' | translate }} + } + @if (loanDetails.loanPurposeName) { + + {{ loanDetails.loanPurposeName }} + + } + }
- } - @if (!loanDetails.summary) {
-

{{ 'labels.heading.Loan Purpose' | translate }}

+

{{ 'labels.heading.Loan Amounts' | translate }}

-
- {{ 'labels.inputs.Loan Purpose' | translate }}: - @if (loanDetails.loanPurposeName) { - - {{ loanDetails.loanPurposeName }} - - } - @if (!loanDetails.loanPurposeName) { - - {{ 'labels.inputs.Not Provided' | translate }} - - } -
{{ 'labels.inputs.Proposed Amount' | translate }}: {{ loanDetails.proposedPrincipal | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
+ @if (loanDetails.balance) { +
+ {{ 'labels.inputs.Total Payment' | translate }} {{ 'labels.inputs.Amount' | translate }}: + {{ + loanDetails.balance.totalPayment | currency: currencyCode : 'symbol-narrow' : '1.2-2' + }} +
+ } @if (showApprovedAmountBasedOnStatus()) {
{{ 'labels.inputs.Approved Amount' | translate }}: diff --git a/src/app/loans/loans-view/general-tab/general-tab.component.ts b/src/app/loans/loans-view/general-tab/general-tab.component.ts index 173d5dc83d..ffb177b4b1 100644 --- a/src/app/loans/loans-view/general-tab/general-tab.component.ts +++ b/src/app/loans/loans-view/general-tab/general-tab.component.ts @@ -26,6 +26,8 @@ import { ExternalIdentifierComponent } from '../../../shared/external-identifier import { DateFormatPipe } from '../../../pipes/date-format.pipe'; import { FormatNumberPipe } from '../../../pipes/format-number.pipe'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; +import { LoanProductService } from 'app/products/loan-products/services/loan-product.service'; +import { LoanProductBaseComponent } from 'app/products/loan-products/common/loan-product-base.component'; @Component({ selector: 'mifosx-general-tab', @@ -49,7 +51,7 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; FormatNumberPipe ] }) -export class GeneralTabComponent implements OnInit { +export class GeneralTabComponent extends LoanProductBaseComponent implements OnInit { private route = inject(ActivatedRoute); /** Currency Code */ @@ -89,6 +91,11 @@ export class GeneralTabComponent implements OnInit { detailsDataSource: MatTableDataSource; constructor() { + super(); + const productType = this.route.snapshot.queryParamMap.get('productType') || null; + if (productType) { + this.loanProductService.initialize(productType); + } this.route.parent.data.subscribe((data: { loanDetailsData: any }) => { this.loanDetails = data.loanDetailsData; this.currencyCode = this.loanDetails.currency.code; @@ -181,13 +188,16 @@ export class GeneralTabComponent implements OnInit { setloanDetailsTableData() { this.loanDetailsTableData = [ { - key: 'Disbursement Date' + key: 'Product Type' }, { - key: 'Loan Purpose' + key: 'Product Name' }, { - key: 'Loan Officer' + key: 'Status' + }, + { + key: 'Disbursement Date' }, { key: 'Currency' @@ -214,24 +224,43 @@ export class GeneralTabComponent implements OnInit { value: this.loanDetails.writeOffReason }); } + if (this.loanProductService.isLoanProduct) { + this.loanDetailsTableData.push({ + key: 'Loan Officer' + }); + } this.detailsDataSource = new MatTableDataSource(this.loanDetailsTableData); } setloanNonDetailsTableData() { this.loanDetailsTableData = [ { - key: 'Disbursement Date' + key: 'Product Type' }, { - key: 'Currency' + key: 'Product Name' }, { - key: 'Loan Officer' + key: 'Status' + }, + { + key: 'Disbursement Date' + }, + { + key: 'Currency' }, { key: 'External Id' } ]; + if (this.loanProductService.isLoanProduct) { + this.loanDetailsTableData.push({ + key: 'Loan Officer' + }); + this.loanDetailsTableData.push({ + key: 'Loan Purpose' + }); + } this.detailsDataSource = new MatTableDataSource(this.loanDetailsTableData); } @@ -257,4 +286,10 @@ export class GeneralTabComponent implements OnInit { } return true; }; + + loanProductType(): string { + return this.loanDetails.loanType + ? LoanProductService.productTypeLabel('loan') + : LoanProductService.productTypeLabel('working-capital'); + } } diff --git a/src/app/loans/loans-view/loan-account-actions/add-collateral/add-collateral.component.html b/src/app/loans/loans-view/loan-account-actions/add-collateral/add-collateral.component.html index 10a10702f6..c0c9ceb873 100644 --- a/src/app/loans/loans-view/loan-account-actions/add-collateral/add-collateral.component.html +++ b/src/app/loans/loans-view/loan-account-actions/add-collateral/add-collateral.component.html @@ -44,7 +44,7 @@
-
-
-
-
-
- diff --git a/src/app/loans/loans-view/loan-account-actions/edit-repayment-schedule/edit-repayment-schedule.component.ts b/src/app/loans/loans-view/loan-account-actions/edit-repayment-schedule/edit-repayment-schedule.component.ts index b172b44d8f..1d50d0d3ff 100644 --- a/src/app/loans/loans-view/loan-account-actions/edit-repayment-schedule/edit-repayment-schedule.component.ts +++ b/src/app/loans/loans-view/loan-account-actions/edit-repayment-schedule/edit-repayment-schedule.component.ts @@ -8,12 +8,9 @@ import { Component, OnInit, inject } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; -import { ActivatedRoute, Router, RouterLink } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { Dates } from 'app/core/utils/dates'; -import { LoansService } from 'app/loans/loans.service'; import { EditableRepaymentSchedule, EditablePeriod, ScheduleChangeRecord } from 'app/loans/models/loan-account.model'; -import { SettingsService } from 'app/settings/settings.service'; import { ConfirmationDialogComponent } from 'app/shared/confirmation-dialog/confirmation-dialog.component'; import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component'; import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base'; @@ -21,6 +18,7 @@ import { InputBase } from 'app/shared/form-dialog/formfield/model/input-base'; import { SelectBase } from 'app/shared/form-dialog/formfield/model/select-base'; import { RepaymentScheduleTabComponent } from '../../repayment-schedule-tab/repayment-schedule-tab.component'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; +import { LoanAccountActionsBaseComponent } from '../loan-account-actions-base.component'; @Component({ selector: 'mifosx-edit-repayment-schedule', @@ -31,17 +29,11 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; RepaymentScheduleTabComponent ] }) -export class EditRepaymentScheduleComponent implements OnInit { - private loansService = inject(LoansService); - private router = inject(Router); - private route = inject(ActivatedRoute); +export class EditRepaymentScheduleComponent extends LoanAccountActionsBaseComponent implements OnInit { private dialog = inject(MatDialog); private dateUtils = inject(Dates); private translateService = inject(TranslateService); - private settingsService = inject(SettingsService); - /** Loan ID. */ - loanId: string; /** Indicates If the Schedule has been changed */ wasChanged = false; /** Indicates If the Schedule has been validated */ @@ -51,16 +43,8 @@ export class EditRepaymentScheduleComponent implements OnInit { /** Stores the Installments changed */ repaymentScheduleChanges: Record = {}; - /** - * @param {LoansService} systemService Loan Service. - * @param {Router} router Router for navigation. - * @param {ActivatedRoute} route Activated Route. - * @param {MatDialog} dialog Confirmation Dialogs. - * @param {Dates} dateUtils Dates Utils. - * @param {SettingsService} settingsService Settings Service - */ constructor() { - this.loanId = this.route.snapshot.params['loanId']; + super(); this.getRepaymentSchedule(); } @@ -69,7 +53,7 @@ export class EditRepaymentScheduleComponent implements OnInit { } getRepaymentSchedule(): void { - this.loansService.getLoanAccountResource(this.loanId, 'repaymentSchedule').subscribe({ + this.loanService.getLoanAccountResource(this.loanId, 'repaymentSchedule').subscribe({ next: (response: { repaymentSchedule: EditableRepaymentSchedule }) => { this.repaymentScheduleDetails = response.repaymentSchedule; }, @@ -157,7 +141,7 @@ export class EditRepaymentScheduleComponent implements OnInit { }); recoverScheduleDialogRef.afterClosed().subscribe((responseConfirmation: { confirm?: boolean }) => { if (responseConfirmation.confirm) { - this.loansService.applyCommandLoanScheduleVariations(this.loanId, 'deleteVariations', {}).subscribe({ + this.loanService.applyCommandLoanScheduleVariations(this.loanId, 'deleteVariations', {}).subscribe({ next: () => { this.getRepaymentSchedule(); this.wasChanged = false; @@ -176,7 +160,7 @@ export class EditRepaymentScheduleComponent implements OnInit { return; } - this.loansService + this.loanService .applyCommandLoanScheduleVariations(this.loanId, 'calculateLoanSchedule', this.getPayload()) .subscribe({ next: (response: EditableRepaymentSchedule) => { @@ -196,9 +180,9 @@ export class EditRepaymentScheduleComponent implements OnInit { } submit(): void { - this.loansService.applyCommandLoanScheduleVariations(this.loanId, 'addVariations', this.getPayload()).subscribe({ + this.loanService.applyCommandLoanScheduleVariations(this.loanId, 'addVariations', this.getPayload()).subscribe({ next: () => { - this.router.navigate(['../../repayment-schedule'], { relativeTo: this.route }); + this.gotoLoanView('repayment-schedule'); }, error: (err) => { console.error('Failed to add schedule variations:', err); diff --git a/src/app/loans/loans-view/loan-account-actions/foreclosure/foreclosure.component.html b/src/app/loans/loans-view/loan-account-actions/foreclosure/foreclosure.component.html index 5e5a615695..24b7cc8d8f 100644 --- a/src/app/loans/loans-view/loan-account-actions/foreclosure/foreclosure.component.html +++ b/src/app/loans/loans-view/loan-account-actions/foreclosure/foreclosure.component.html @@ -63,7 +63,7 @@ -

{{ 'labels.heading.Account Overview' | translate }} {{ 'labels.inputs.Account Details' | translate }} - @if (loanDetailsData.originalSchedule) { + @if (loanProductService.isLoanProduct && loanDetailsData.originalSchedule) { - {{ 'labels.inputs.Original Schedule' | translate }} + {{ 'labels.inputs.General' | translate }} } {{ 'labels.heading.Account Overview' | translate }} {{ 'labels.inputs.Transactions' | translate }} } - @if (loanDetailsData.enableIncomeCapitalization) { + @if (loanProductService.isLoanProduct && loanDetailsData.enableIncomeCapitalization) { - {{ 'labels.inputs.Deferred income' | translate }} + {{ 'labels.inputs.Account Details' | translate }} } - @if (loanDetailsData.enableBuyDownFee) { + @if (loanProductService.isLoanProduct && loanDetailsData.enableBuyDownFee) { {{ 'labels.heading.Account Overview' | translate }} {{ 'labels.heading.Account Overview' | translate }} {{ 'labels.inputs.Originators' | translate }} - @if (loanDetailsData.collateral) { + @if (loanProductService.isLoanProduct && loanDetailsData.collateral) { {{ 'labels.heading.Account Overview' | translate }} {{ 'labels.inputs.Loan Collateral Details' | translate }} } - @if (loanDetailsData.multiDisburseLoan) { + @if (loanProductService.isLoanProduct && loanDetailsData.multiDisburseLoan) { {{ 'labels.heading.Account Overview' | translate }} {{ 'labels.inputs.Loan Tranche Details' | translate }} } - @if (loanDetailsData.loanTermVariations) { + @if (loanProductService.isLoanProduct && loanDetailsData.loanTermVariations) { {{ 'labels.heading.Account Overview' | translate }} {{ 'labels.inputs.Term Variations' | translate }} } - @if (loanDetailsData.overdueCharges.length > 0) { + @if (loanProductService.isLoanProduct && loanDetailsData.overdueCharges.length > 0) { {{ 'labels.heading.Account Overview' | translate }} {{ 'labels.inputs.Overdue Charges' | translate }} } - @if (loanDetailsData.isLoanProductLinkedToFloatingRate) { + @if (loanProductService.isLoanProduct && loanDetailsData.isLoanProductLinkedToFloatingRate) { {{ 'labels.heading.Account Overview' | translate }} {{ 'labels.inputs.Floating Interest Rates' | translate }} } - @if (loanDetailsData.charges) { + @if (loanProductService.isLoanProduct && loanDetailsData.charges) { {{ 'labels.heading.Account Overview' | translate }} {{ 'labels.inputs.Charges' | translate }} } - @if (loanDetailsData.status.active || loanDetailsData.status.closed || loanDetailsData.status.overpaid) { + @if ( + loanProductService.isLoanProduct && + (loanDetailsData.status.active || loanDetailsData.status.closed || loanDetailsData.status.overpaid) + ) { {{ 'labels.heading.Account Overview' | translate }} {{ 'labels.heading.Account Overview' | translate }} mat-tab-link *mifosxHasPermission="'READ_LOANNOTE'" [routerLink]="['./notes']" + [queryParams]="{ + productType: loanProductService.productType.value + }" routerLinkActive #notes="routerLinkActive" [active]="notes.isActive" > {{ 'labels.inputs.Notes' | translate }} - @if (loanDetailsData.clientId) { + @if (loanProductService.isLoanProduct && loanDetailsData.clientId) { {{ 'labels.heading.Account Overview' | translate }} {{ 'labels.inputs.Standing Instruction' | translate }} } - @if (loanDetailsData.status.active) { + @if (loanProductService.isLoanProduct && loanDetailsData.status.active) { {{ 'labels.heading.Account Overview' | translate }} {{ 'labels.inputs.External Asset Owner' | translate }} } - @if (datatablesReady) { + @if (loanProductService.isLoanProduct && datatablesReady) { @for (loanDatatable of loanDatatables; track loanDatatable) { { this.loanDetailsData = data.loanDetailsData; - this.loanDatatables = data.loanDatatables; - this.loanDisplayArrearsDelinquency = data.loanArrearsDelinquencyConfig?.value || 0; - if (this.loanDetailsData) { - this.loanStatus = this.loanDetailsData.status; + if (!this.loanDetailsData.loanProductName) { + this.loanDetailsData.loanProductName = this.loanDetailsData.product.name; + } + this.loanDatatables = this.loanProductService.isLoanProduct ? data.loanDatatables : []; + this.loanStatus = this.loanDetailsData.status; + this.currency = this.loanDetailsData.currency; + if (this.loanProductService.isLoanProduct) { + this.loanDisplayArrearsDelinquency = data.loanArrearsDelinquencyConfig.value || 0; this.loanSubStatus = this.loanDetailsData.subStatus === undefined ? null : this.loanDetailsData.subStatus; - this.currency = this.loanDetailsData.currency; loansService.saveLoanDisbursementDetailsData(this.loanDetailsData.disbursementDetails); - if (this.loanStatus?.active) { - this.loanDetailsData.transactions?.forEach((lt: LoanTransaction) => { + if (this.loanStatus.active) { + this.loanDetailsData.transactions.forEach((lt: LoanTransaction) => { if (!lt.manuallyReversed) { if (lt.type.reAge) { this.loanReAged = true; @@ -136,11 +141,10 @@ export class LoansViewComponent implements OnInit { } }); } - this.clientId = this.loanDetailsData.clientId; - this.setConditionalButtons(); // Filter datatables based on entity datatable checks this.filterDatatablesByProduct(); } + this.setConditionalButtons(); } ); this.loanId = this.route.snapshot.params['loanId']; @@ -406,7 +410,10 @@ export class LoansViewComponent implements OnInit { this.deleteLoanAccount(); break; case 'Modify Application': - this.router.navigate(['edit-loans-account'], { relativeTo: this.route }); + this.router.navigate(['edit-loans-account'], { + queryParams: { productType: this.loanProductService.productType.value }, + relativeTo: this.route + }); break; case 'Transfer Funds': const queryParams: any = { loanId: this.loanId, accountType: 'fromloans' }; @@ -422,6 +429,9 @@ export class LoansViewComponent implements OnInit { break; default: const navigationExtras: NavigationExtras = { + queryParams: { + productType: this.loanProductService.productType.value + }, relativeTo: this.route, state: { data: this.loanDetailsData @@ -555,18 +565,6 @@ export class LoansViewComponent implements OnInit { }); } - /** - * Refetches data for the component - * TODO: Replace by a custom reload component instead of hard-coded back-routing. - */ - private reload() { - const clientId = this.clientId; - const url: string = this.router.url; - this.router - .navigateByUrl(`/clients/${clientId}/loans-accounts`, { skipLocationChange: true }) - .then(() => this.router.navigate([url])); - } - private isContractTermination(substatus: OptionData): boolean { if (substatus == null) { return false; diff --git a/src/app/loans/loans-view/reschedule-loan-tab/reschedule-loan-tab.component.ts b/src/app/loans/loans-view/reschedule-loan-tab/reschedule-loan-tab.component.ts index 3e85a48bb5..1f0625279e 100644 --- a/src/app/loans/loans-view/reschedule-loan-tab/reschedule-loan-tab.component.ts +++ b/src/app/loans/loans-view/reschedule-loan-tab/reschedule-loan-tab.component.ts @@ -8,7 +8,7 @@ import { Component, Input, inject } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; -import { ActivatedRoute, Router, RouterLink } from '@angular/router'; +import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { Dates } from 'app/core/utils/dates'; import { LoansService } from 'app/loans/loans.service'; @@ -33,6 +33,7 @@ import { MatTooltip } from '@angular/material/tooltip'; import { StatusLookupPipe } from '../../../pipes/status-lookup.pipe'; import { DateFormatPipe } from '../../../pipes/date-format.pipe'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; +import { LoanAccountTabBaseComponent } from '../loan-account-tab-base.component'; @Component({ selector: 'mifosx-reschedule-loan-tab', @@ -57,9 +58,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; DateFormatPipe ] }) -export class RescheduleLoanTabComponent { +export class RescheduleLoanTabComponent extends LoanAccountTabBaseComponent { private route = inject(ActivatedRoute); - private router = inject(Router); private loansServices = inject(LoansService); private settingsService = inject(SettingsService); private dateUtils = inject(Dates); @@ -79,6 +79,7 @@ export class RescheduleLoanTabComponent { clientId: any; constructor() { + super(); this.clientId = this.route.parent.parent.snapshot.paramMap.get('clientId'); this.route.parent.data.subscribe((data: { loanRescheduleData: any }) => { this.loanRescheduleData = data.loanRescheduleData; @@ -122,14 +123,4 @@ export class RescheduleLoanTabComponent { } }); } - - /** - * Refetches data fot the component - */ - private reload() { - const url: string = this.router.url; - this.router - .navigateByUrl(`/clients/${this.clientId}/loans-accounts`, { skipLocationChange: true }) - .then(() => this.router.navigate([url])); - } } diff --git a/src/app/loans/loans-view/transactions-tab/transactions-tab.component.ts b/src/app/loans/loans-view/transactions-tab/transactions-tab.component.ts index 9a653de204..93cc53548f 100644 --- a/src/app/loans/loans-view/transactions-tab/transactions-tab.component.ts +++ b/src/app/loans/loans-view/transactions-tab/transactions-tab.component.ts @@ -7,7 +7,7 @@ */ import { Component, OnInit, ViewChild, inject } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; +import { ActivatedRoute } from '@angular/router'; import { UntypedFormControl, Validators } from '@angular/forms'; import { MatPaginator } from '@angular/material/paginator'; import { MatSort } from '@angular/material/sort'; @@ -47,6 +47,7 @@ import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { DateFormatPipe } from '../../../pipes/date-format.pipe'; import { FormatNumberPipe } from '../../../pipes/format-number.pipe'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; +import { LoanProductBaseComponent } from 'app/products/loan-products/common/loan-product-base.component'; @Component({ selector: 'mifosx-transactions-tab', @@ -79,10 +80,9 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; FormatNumberPipe ] }) -export class TransactionsTabComponent implements OnInit { +export class TransactionsTabComponent extends LoanProductBaseComponent implements OnInit { private route = inject(ActivatedRoute); private dateUtils = inject(Dates); - private router = inject(Router); private dialog = inject(MatDialog); private loansService = inject(LoansService); private translateService = inject(TranslateService); @@ -145,6 +145,7 @@ export class TransactionsTabComponent implements OnInit { * @param {ActivatedRoute} route Activated Route. */ constructor() { + super(); this.route.parent.parent.data.subscribe((data: { loanDetailsData: any }) => { this.loanDetailsData = data.loanDetailsData; this.status = data.loanDetailsData.status.value; @@ -219,7 +220,12 @@ export class TransactionsTabComponent implements OnInit { */ showTransactions(transactionsData: LoanTransaction) { if (this.showTransaction(transactionsData)) { - this.router.navigate([transactionsData.id], { relativeTo: this.route }); + this.router.navigate([transactionsData.id], { + queryParams: { + productType: this.loanProductService.productType.value + }, + relativeTo: this.route + }); } } @@ -559,12 +565,6 @@ export class TransactionsTabComponent implements OnInit { }); } - private reload() { - const clientId = this.route.parent.parent.snapshot.params['clientId']; - const url: string = this.router.url; - this.router.navigateByUrl(`/clients`, { skipLocationChange: true }).then(() => this.router.navigate([url])); - } - displaySubMenu(transaction: LoanTransaction): boolean { if (this.isReAgoeOrReAmortize(transaction.type) && transaction.manuallyReversed) { return false; diff --git a/src/app/loans/loans-view/transactions/edit-transaction/edit-transaction.component.ts b/src/app/loans/loans-view/transactions/edit-transaction/edit-transaction.component.ts index bddc949fd2..f46f8617b7 100644 --- a/src/app/loans/loans-view/transactions/edit-transaction/edit-transaction.component.ts +++ b/src/app/loans/loans-view/transactions/edit-transaction/edit-transaction.component.ts @@ -8,23 +8,16 @@ /** Angular Imports */ import { Component, OnInit, inject } from '@angular/core'; -import { - UntypedFormGroup, - UntypedFormBuilder, - Validators, - UntypedFormControl, - ReactiveFormsModule -} from '@angular/forms'; -import { Router, ActivatedRoute, RouterLink } from '@angular/router'; +import { UntypedFormGroup, UntypedFormBuilder, Validators, UntypedFormControl } from '@angular/forms'; import { Dates } from 'app/core/utils/dates'; /** Custom Services */ import { LoansService } from 'app/loans/loans.service'; -import { SettingsService } from 'app/settings/settings.service'; import { Currency } from 'app/shared/models/general.model'; import { InputAmountComponent } from '../../../../shared/input-amount/input-amount.component'; import { MatSlideToggle } from '@angular/material/slide-toggle'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; +import { LoanAccountActionsBaseComponent } from '../../loan-account-actions/loan-account-actions-base.component'; /** * Edit Transaction component. @@ -39,13 +32,10 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; MatSlideToggle ] }) -export class EditTransactionComponent implements OnInit { +export class EditTransactionComponent extends LoanAccountActionsBaseComponent implements OnInit { private formBuilder = inject(UntypedFormBuilder); - private route = inject(ActivatedRoute); - private router = inject(Router); private dateUtils = inject(Dates); private loansService = inject(LoansService); - private settingsService = inject(SettingsService); /** Minimum Due Date allowed. */ minDate = new Date(2000, 0, 1); @@ -79,6 +69,7 @@ export class EditTransactionComponent implements OnInit { * @param {SettingsService} settingsService Settings Service */ constructor() { + super(); this.route.data.subscribe((data: { loansAccountTransactionTemplate: any }) => { this.transactionTemplateData = data.loansAccountTransactionTemplate; if (data.loansAccountTransactionTemplate.currency) { @@ -161,7 +152,12 @@ export class EditTransactionComponent implements OnInit { this.loansService .executeLoansAccountTransactionsCommand(this.loanAccountId, 'modify', data, this.transactionTemplateData.id) .subscribe((res: any) => { - this.router.navigate(['../'], { relativeTo: this.route }); + this.router.navigate(['../'], { + queryParams: { + productType: this.loanProductService.productType.value + }, + relativeTo: this.route + }); }); } } diff --git a/src/app/loans/loans-view/transactions/view-transaction/view-transaction.component.ts b/src/app/loans/loans-view/transactions/view-transaction/view-transaction.component.ts index 13032a3415..d56e8a2b59 100644 --- a/src/app/loans/loans-view/transactions/view-transaction/view-transaction.component.ts +++ b/src/app/loans/loans-view/transactions/view-transaction/view-transaction.component.ts @@ -8,13 +8,11 @@ /** Angular Imports */ import { Component, OnInit, inject } from '@angular/core'; -import { ActivatedRoute, Router, RouterLink } from '@angular/router'; import { MatDialog } from '@angular/material/dialog'; /** Custom Services */ import { LoansService } from 'app/loans/loans.service'; import { ConfirmationDialogComponent } from 'app/shared/confirmation-dialog/confirmation-dialog.component'; -import { SettingsService } from 'app/settings/settings.service'; import { Dates } from 'app/core/utils/dates'; import { OrganizationService } from 'app/organization/organization.service'; import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base'; @@ -45,6 +43,7 @@ import { MatTooltip } from '@angular/material/tooltip'; import { TransactionPaymentDetailComponent } from '../../../../shared/transaction-payment-detail/transaction-payment-detail.component'; import { DateFormatPipe } from '../../../../pipes/date-format.pipe'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; +import { LoanAccountActionsBaseComponent } from '../../loan-account-actions/loan-account-actions-base.component'; /** Custom Dialogs */ @@ -78,14 +77,11 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; DateFormatPipe ] }) -export class ViewTransactionComponent implements OnInit { +export class ViewTransactionComponent extends LoanAccountActionsBaseComponent implements OnInit { private loansService = inject(LoansService); - private route = inject(ActivatedRoute); private dateUtils = inject(Dates); - private router = inject(Router); dialog = inject(MatDialog); private translateService = inject(TranslateService); - private settingsService = inject(SettingsService); private organizationService = inject(OrganizationService); private alertService = inject(AlertService); @@ -112,7 +108,6 @@ export class ViewTransactionComponent implements OnInit { amountRelationsAllowed = 0; clientId: number; - loanId: number; /** * Retrieves the Transaction data from `resolve`. @@ -125,6 +120,7 @@ export class ViewTransactionComponent implements OnInit { * @param {AlertService} alertService Alert Service */ constructor() { + super(); this.route.data.subscribe((data: { loansAccountTransaction: any }) => { this.transactionData = data.loansAccountTransaction; this.transactionType = this.transactionData.type; @@ -252,7 +248,12 @@ export class ViewTransactionComponent implements OnInit { }; this.loansService.loanActionButtons(accountId, 'undoContractTermination', payload).subscribe(() => { - this.router.navigate(['../'], { relativeTo: this.route }); + this.router.navigate(['../'], { + queryParams: { + productType: this.loanProductService.productType.value + }, + relativeTo: this.route + }); }); } }); @@ -283,7 +284,12 @@ export class ViewTransactionComponent implements OnInit { this.loansService .executeLoansAccountTransactionsCommand(accountId, command, data, transactionId) .subscribe(() => { - this.router.navigate(['../'], { relativeTo: this.route }); + this.router.navigate(['../'], { + queryParams: { + productType: this.loanProductService.productType.value + }, + relativeTo: this.route + }); }); } }); @@ -329,7 +335,12 @@ export class ViewTransactionComponent implements OnInit { this.loansService .executeLoansAccountTransactionsCommand(accountId, 'chargeback', payload, this.transactionData.id) .subscribe(() => { - this.router.navigate(['../'], { relativeTo: this.route }); + this.router.navigate(['../'], { + queryParams: { + productType: this.loanProductService.productType.value + }, + relativeTo: this.route + }); }); } else { this.alertService.alert({ diff --git a/src/app/loans/loans-view/view-charge/view-charge.component.ts b/src/app/loans/loans-view/view-charge/view-charge.component.ts index aef61c0787..cd88fd6e36 100644 --- a/src/app/loans/loans-view/view-charge/view-charge.component.ts +++ b/src/app/loans/loans-view/view-charge/view-charge.component.ts @@ -8,7 +8,7 @@ /** Angular Imports */ import { Component, inject } from '@angular/core'; -import { ActivatedRoute, Router, RouterLink } from '@angular/router'; +import { ActivatedRoute } from '@angular/router'; import { MatDialog } from '@angular/material/dialog'; /** Custom Services */ @@ -31,6 +31,7 @@ import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { DateFormatPipe } from '../../../pipes/date-format.pipe'; import { FormatNumberPipe } from '../../../pipes/format-number.pipe'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; +import { LoanAccountTabBaseComponent } from '../loan-account-tab-base.component'; /** * View Charge Component. @@ -47,11 +48,10 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; FormatNumberPipe ] }) -export class ViewChargeComponent { +export class ViewChargeComponent extends LoanAccountTabBaseComponent { private loansService = inject(LoansService); private route = inject(ActivatedRoute); private dateUtils = inject(Dates); - private router = inject(Router); private translateService = inject(TranslateService); dialog = inject(MatDialog); private settingsService = inject(SettingsService); @@ -73,6 +73,7 @@ export class ViewChargeComponent { * @param {SettingsService} settingsService Settings Service */ constructor() { + super(); this.route.data.subscribe((data: { loansAccountCharge: any; loanDetailsData: any }) => { this.chargeData = data.loansAccountCharge; this.allowPayCharge = this.chargeData.chargePayable && !this.chargeData.paid; @@ -212,18 +213,11 @@ export class ViewChargeComponent { } adjustmentCharge(): void { - this.router.navigate(['adjustment'], { relativeTo: this.route }); - } - - /** - * Refetches data fot the component - * TODO: Replace by a custom reload component instead of hard-coded back-routing. - */ - private reload() { - const clientId = this.loansAccountData.clientId; - const url: string = this.router.url; - this.router - .navigateByUrl(`/clients/${clientId}/loans-accounts`, { skipLocationChange: true }) - .then(() => this.router.navigate([url])); + this.router.navigate(['adjustment'], { + queryParams: { + productType: this.loanProductService.productType.value + }, + relativeTo: this.route + }); } } diff --git a/src/app/loans/loans.service.ts b/src/app/loans/loans.service.ts index 178647a30f..ee824753c9 100644 --- a/src/app/loans/loans.service.ts +++ b/src/app/loans/loans.service.ts @@ -203,6 +203,11 @@ export class LoansService { return this.http.get(`/loans/${loanId}`, { params: httpParams }); } + getWorkingCapitalLoannDetails(loanId: string) { + const httpParams = new HttpParams().set('associations', 'all'); + return this.http.get(`/working-capital-loans/${loanId}`, { params: httpParams }); + } + getApproveAssociationsDetails(loanId: any) { const httpParams = new HttpParams().set('associations', 'multiDisburseDetails'); return this.http.get(`/loans/${loanId}`, { params: httpParams }); @@ -357,6 +362,11 @@ export class LoansService { return this.http.post(`/loans/${loanId}`, data, { params: httpParams }); } + applyWorkingCapitalLoanAccountCommand(loanId: any, command: any, data?: any): Observable { + const httpParams = new HttpParams().set('command', command); + return this.http.post(`/working-capital-loans/${loanId}`, data, { params: httpParams }); + } + addInterestPauseToLoan(loanId: any, data?: any): Observable { return this.http.post(`/loans/${loanId}/interest-pauses`, data); } @@ -449,6 +459,12 @@ export class LoansService { return this.http.get('/loans/template', { params: httpParams }); } + getWorkingCapitalLoansAccountTemplate(clientId: number, productId?: number): Observable { + let httpParams = new HttpParams().set('clientId', clientId); + httpParams = productId ? httpParams.set('productId', productId) : httpParams; + return this.http.get('/working-capital-loans/template', { params: httpParams }); + } + getLoansAccountAndTemplateResource(loanId: any): Observable { const httpParams = new HttpParams() .set('associations', 'charges,collateral,meeting,multiDisburseDetails') @@ -473,8 +489,8 @@ export class LoansService { * Creates Loans Account * @param {any} loanAccount Loan Account */ - createLoansAccount(loanAccount: any): Observable { - return this.http.post('/loans', loanAccount); + createLoansAccount(productType: string, loanAccount: any): Observable { + return this.http.post(`/${productType}`, loanAccount); } getLoanDocuments(loanId: any): Observable { @@ -539,6 +555,11 @@ export class LoansService { return this.http.get(`/loans/${loanId}/template`, { params: httpParams }); } + getWorkingCapitalLoanActionTemplate(loanId: string, actionName: string): Observable { + const httpParams = new HttpParams().set('templateType', actionName); + return this.http.get(`/working-capital-loans/${loanId}/template`, { params: httpParams }); + } + guarantorAccountResource(loanId: string, clientId: any): Observable { const httpParams = new HttpParams().set('clientId', clientId); return this.http.get(`/loans/${loanId}/guarantors/accounts/template`, { params: httpParams }); diff --git a/src/app/loans/loans-view/loan-account-actions/loan-account-actions.component.scss b/src/app/loans/models/loan-product.model.ts similarity index 52% rename from src/app/loans/loans-view/loan-account-actions/loan-account-actions.component.scss rename to src/app/loans/models/loan-product.model.ts index af9f4c0753..6b5ab8a0b1 100644 --- a/src/app/loans/loans-view/loan-account-actions/loan-account-actions.component.scss +++ b/src/app/loans/models/loan-product.model.ts @@ -5,3 +5,14 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import { Currency } from 'app/shared/models/general.model'; + +export interface LoanProductBasicDetails { + productType: string; + id: number; + name: string; + shortName: string; + description: string; + currency: Currency; +} diff --git a/src/app/products/loan-products/common/loan-product-base.component.ts b/src/app/products/loan-products/common/loan-product-base.component.ts index 6e1b712e23..d98debe2c8 100644 --- a/src/app/products/loan-products/common/loan-product-base.component.ts +++ b/src/app/products/loan-products/common/loan-product-base.component.ts @@ -8,10 +8,14 @@ import { inject } from '@angular/core'; import { LoanProductService } from '../services/loan-product.service'; +import { ActivatedRoute, Router } from '@angular/router'; export abstract class LoanProductBaseComponent { + protected router = inject(Router); protected loanProductService = inject(LoanProductService); + static PRODUCT_TYPE_PARAM: string = 'productType'; + constructor() {} getProductTypeLabel(upperCase: boolean): string { @@ -19,4 +23,21 @@ export abstract class LoanProductBaseComponent { ? this.loanProductService.loanProductTypeLabel.toUpperCase() : this.loanProductService.loanProductTypeLabel; } + + static resolveProductType(route: ActivatedRoute): string { + return route.snapshot.queryParamMap.get(this.PRODUCT_TYPE_PARAM) || null; + } + + static resolveProductTypeDefault(route: ActivatedRoute, defaultType: string): string { + return route.snapshot.queryParamMap.get(this.PRODUCT_TYPE_PARAM) || defaultType; + } + + protected reload() { + const url: string = this.router.url.split('?')[0]; + this.router + .navigateByUrl(`/clients`, { skipLocationChange: true }) + .then(() => + this.router.navigate([url], { queryParams: { productType: this.loanProductService.productType.value } }) + ); + } } diff --git a/src/app/products/loan-products/common/loan-product-summary/loan-product-summary.component.html b/src/app/products/loan-products/common/loan-product-summary/loan-product-summary.component.html index ccfe7e2c37..85c658df32 100644 --- a/src/app/products/loan-products/common/loan-product-summary/loan-product-summary.component.html +++ b/src/app/products/loan-products/common/loan-product-summary/loan-product-summary.component.html @@ -878,10 +878,6 @@

{{ 'labels.inputs.Configurable Terms and Settings' } @if (loanProductService.isWorkingCapital) {
-
- {{ 'labels.inputs.Flat Percentage Amount' | translate }}: - {{ loanProduct.allowAttributeOverrides.flatPercentageAmount | yesNo }} -
{{ 'labels.inputs.Delinquency Bucket Classification' | translate }}: {{ diff --git a/src/app/products/loan-products/create-loan-product/create-loan-product.component.ts b/src/app/products/loan-products/create-loan-product/create-loan-product.component.ts index 9103e9329a..4d99471b1d 100644 --- a/src/app/products/loan-products/create-loan-product/create-loan-product.component.ts +++ b/src/app/products/loan-products/create-loan-product/create-loan-product.component.ts @@ -8,7 +8,7 @@ /** Angular Imports */ import { AfterViewInit, ChangeDetectorRef, Component, OnInit, ViewChild, inject } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; +import { ActivatedRoute } from '@angular/router'; /** Custom Components */ import { LoanProductDetailsStepComponent } from '../loan-product-stepper/loan-product-details-step/loan-product-details-step.component'; @@ -70,7 +70,6 @@ export class CreateLoanProductComponent extends LoanProductBaseComponent impleme private route = inject(ActivatedRoute); private productsService = inject(ProductsService); private loanProducts = inject(LoanProducts); - private router = inject(Router); private accounting = inject(Accounting); private advancedPaymentStrategy = inject(AdvancedPaymentStrategy); private cdr = inject(ChangeDetectorRef); diff --git a/src/app/products/loan-products/edit-loan-product/edit-loan-product.component.ts b/src/app/products/loan-products/edit-loan-product/edit-loan-product.component.ts index 04f8571c0e..894d4b5746 100644 --- a/src/app/products/loan-products/edit-loan-product/edit-loan-product.component.ts +++ b/src/app/products/loan-products/edit-loan-product/edit-loan-product.component.ts @@ -8,7 +8,7 @@ /** Angular Imports */ import { AfterViewInit, ChangeDetectorRef, Component, OnInit, ViewChild, inject } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; +import { ActivatedRoute } from '@angular/router'; /** Custom Components */ import { LoanProductDetailsStepComponent } from '../loan-product-stepper/loan-product-details-step/loan-product-details-step.component'; @@ -73,7 +73,6 @@ export class EditLoanProductComponent extends LoanProductBaseComponent implement private route = inject(ActivatedRoute); private productsService = inject(ProductsService); private loanProducts = inject(LoanProducts); - private router = inject(Router); private accounting = inject(Accounting); private advancedPaymentStrategy = inject(AdvancedPaymentStrategy); private cdr = inject(ChangeDetectorRef); 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 3ec84bb1af..565eb203e6 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 @@ -867,9 +867,6 @@

{{ 'labels.inputs.Configurable Terms and Settings' | } @if (loanProductService.isWorkingCapital) {
- - {{ 'labels.inputs.Flat Percentage Amount' | translate }} - attribute ), allowAttributeOverrides: { - flatPercentageAmount: this.loanProductsTemplate.allowAttributeOverrides.flatPercentageAmount, delinquencyBucketClassification: this.loanProductsTemplate.allowAttributeOverrides.delinquencyBucketClassification, discountDefault: this.loanProductsTemplate.allowAttributeOverrides.discountDefault, @@ -426,7 +425,6 @@ export class LoanProductSettingsStepComponent extends LoanProductBaseComponent i ] ], allowAttributeOverrides: this.formBuilder.group({ - flatPercentageAmount: [true], delinquencyBucketClassification: [true], discountDefault: [true], periodPaymentFrequency: [true], @@ -788,7 +786,6 @@ export class LoanProductSettingsStepComponent extends LoanProductBaseComponent i .valueChanges.subscribe((allowAttributeConfiguration: any) => { if (allowAttributeConfiguration) { allowAttributeOverrides.patchValue({ - flatPercentageAmount: true, delinquencyBucketClassification: true, discountDefault: true, periodPaymentFrequency: true, @@ -796,7 +793,6 @@ export class LoanProductSettingsStepComponent extends LoanProductBaseComponent i }); } else { allowAttributeOverrides.patchValue({ - flatPercentageAmount: false, delinquencyBucketClassification: false, discountDefault: false, periodPaymentFrequency: false, diff --git a/src/app/products/loan-products/loan-products.component.ts b/src/app/products/loan-products/loan-products.component.ts index 0274b64a28..0ac5083dfd 100644 --- a/src/app/products/loan-products/loan-products.component.ts +++ b/src/app/products/loan-products/loan-products.component.ts @@ -24,7 +24,7 @@ import { MatRowDef, MatRow } from '@angular/material/table'; -import { ActivatedRoute, Router } from '@angular/router'; +import { ActivatedRoute } from '@angular/router'; /** rxjs Imports */ import { switchMap, catchError } from 'rxjs/operators'; @@ -76,7 +76,6 @@ import { LoanProductBaseComponent } from './common/loan-product-base.component'; }) export class LoanProductsComponent extends LoanProductBaseComponent implements OnInit, AfterViewInit { private route = inject(ActivatedRoute); - private router = inject(Router); private configurationWizardService = inject(ConfigurationWizardService); private popoverService = inject(PopoverService); private dialog = inject(MatDialog); diff --git a/src/app/products/loan-products/services/loan-product.service.ts b/src/app/products/loan-products/services/loan-product.service.ts index f88f8c9288..e5b7240662 100644 --- a/src/app/products/loan-products/services/loan-product.service.ts +++ b/src/app/products/loan-products/services/loan-product.service.ts @@ -22,10 +22,12 @@ export class LoanProductService { constructor() {} initialize(productType: string): void { - if (productType === 'loan') { - this.productType.next(LOAN_PRODUCT_TYPE.LOAN); - } else if (productType === 'working-capital') { - this.productType.next(LOAN_PRODUCT_TYPE.WORKING_CAPITAL); + if (productType !== null) { + if (productType === 'loan') { + this.productType.next(LOAN_PRODUCT_TYPE.LOAN); + } else if (productType === 'working-capital') { + this.productType.next(LOAN_PRODUCT_TYPE.WORKING_CAPITAL); + } } } @@ -46,4 +48,12 @@ export class LoanProductService { get loanProductPath(): string { return this.isLoanProduct ? 'loanproducts' : 'working-capital-loan-products'; } + + get loanAccountPath(): string { + return this.isLoanProduct ? 'loans' : 'working-capital-loans'; + } + + static productTypeLabel(productType: string): string { + return productType === 'loan' ? 'labels.heading.Loan Product' : 'labels.heading.Working Capital Product'; + } } diff --git a/src/app/products/products.service.ts b/src/app/products/products.service.ts index 2a8a6d0e7c..3e0fd3f4ff 100644 --- a/src/app/products/products.service.ts +++ b/src/app/products/products.service.ts @@ -33,6 +33,13 @@ export class ProductsService { return this.http.get(`/${productType}`); } + /** + * @returns {Observable} Loan Products basis details data. + */ + getLoanProductsBasicDetails(): Observable { + return this.http.get('/loanproducts/basic-details'); + } + createLoanProduct(productType: string, loanProduct: any): Observable { return this.http.post(`/${productType}`, loanProduct); } diff --git a/src/app/shared/footer/footer.component.ts b/src/app/shared/footer/footer.component.ts index 1cf52519da..6f65dce670 100644 --- a/src/app/shared/footer/footer.component.ts +++ b/src/app/shared/footer/footer.component.ts @@ -153,6 +153,8 @@ export class FooterComponent implements OnInit, OnDestroy { this.timer = setTimeout(() => { this.getConfigurations(); }, 60000); + } else { + clearTimeout(this.timer); } }); } else { diff --git a/src/app/shared/long-text/long-text.component.html b/src/app/shared/long-text/long-text.component.html index f09b9da28a..f13f6aaa10 100644 --- a/src/app/shared/long-text/long-text.component.html +++ b/src/app/shared/long-text/long-text.component.html @@ -10,8 +10,6 @@ @if (isLongValue()) { - } - @if (isLongValue()) { {{ textValue | truncateText: printChars }}... } @if (!isLongValue()) { diff --git a/src/app/shared/long-text/long-text.component.ts b/src/app/shared/long-text/long-text.component.ts index 954d9b1ed1..6969bb41c2 100644 --- a/src/app/shared/long-text/long-text.component.ts +++ b/src/app/shared/long-text/long-text.component.ts @@ -47,10 +47,10 @@ export class LongTextComponent implements OnInit { } showValue() { - if (this.printChars == 30) { + if (this.printChars < 1000) { this.printChars = 1000; } else { - this.printChars = 30; + this.printChars = this.chars; } } diff --git a/src/assets/translations/cs-CS.json b/src/assets/translations/cs-CS.json index 4df5ddffb8..3fb17997a1 100644 --- a/src/assets/translations/cs-CS.json +++ b/src/assets/translations/cs-CS.json @@ -885,7 +885,10 @@ "move to next repayment meeting day": "přesunout na další den schůzky o splácení", "move to previous working day": "přesunout na předchozí pracovní den", "move to next meeting day": "přesunout na další den schůzky", - "Working Capital": "Provozní kapitál" + "Working Capital": "Provozní kapitál", + "DAYS": "DNY", + "MONTHS": "MĚSÍCE", + "YEARS": "ROKY" }, "commons": { "50 characters long": "50 znaků dlouhé", @@ -1153,6 +1156,7 @@ "List of Users with their details": "Seznam uživatelů s jejich podrobnostmi", "Loan Account OverView": "Přehled úvěrového účtu", "Loan Accounts": "Úvěrové účty", + "Loan Amounts": "Výše úvěru", "Loan Delinquency Actions": "Akce delikvence půjčky", "Loan Delinquency Classification": "Klasifikace delikvence půjčky", "Loan Delinquency Tags": "Značky proplácení úvěrů", @@ -1791,6 +1795,7 @@ "Disbursement Date": "Datum výplaty", "Disbursement On": "Vyplácení zapnuto", "Disbursement on": "Výplata zapnuta", + "Discount": "Sleva", "Display Name": "Zobrazovaný název", "Dividend Amount": "Částka dividendy", "Dividend Period End Date": "Datum ukončení dividendového období", @@ -2382,6 +2387,7 @@ "Priority": "Přednost", "Product": "Produkt", "Product Name": "jméno výrobku", + "Product Type": "Typ produktu", "Products": "produkty", "Profession": "Profese", "Proposed Amount": "Navrhovaná částka", @@ -2641,6 +2647,7 @@ "Total Interest Earned": "Celkový získaný úrok", "Total No. of Shares": "Celkový počet akcií", "Total Number of Shares": "Celkový počet akcií", + "Total Payment": "Celková platba", "Total Records": "Celkové rekordy", "Total Savings": "Celková úspora", "Total Shares": "Celkový počet akcií", @@ -3464,6 +3471,7 @@ "NoDocuments": "Žádné dokumenty k dispozici.", "NoFileSelected": "Nevybrán žádný soubor", "NoNotesAvailable": "Žádné poznámky k dispozici", + "No Loan Product was found": "Nebyl nalezen žádný úvěrový produkt", "No loan locked available": "Žádná půjčka není k dispozici.", "No notifications": "Žádné oznámení", "No pending loan available for disbursal": "Není k dispozici žádná nevyřízená půjčka k vyplacení.", diff --git a/src/assets/translations/de-DE.json b/src/assets/translations/de-DE.json index 40ce5d30d1..b58539b3fc 100644 --- a/src/assets/translations/de-DE.json +++ b/src/assets/translations/de-DE.json @@ -886,7 +886,10 @@ "move to next repayment meeting day": "zum nächsten Rückzahlungstermin verschieben", "move to previous working day": "zum vorherigen Arbeitstag verschieben", "move to next meeting day": "zum nächsten Termin verschieben", - "Working Capital": "Betriebskapital" + "Working Capital": "Betriebskapital", + "DAYS": "TAGE", + "MONTHS": "MONATE", + "YEARS": "JAHRE" }, "commons": { "50 characters long": "50 Zeichen lang", @@ -1155,6 +1158,7 @@ "List of Users with their details": "Liste der Benutzer mit ihren Details", "Loan Account OverView": "Kreditkontoübersicht", "Loan Accounts": "Kreditkonten", + "Loan Amounts": "Darlehensbeträge", "Loan Delinquency Actions": "Darlehenskriminalitätsmaßnahmen", "Loan Delinquency Classification": "Kreditkriminalitätsklassifizierung", "Loan Delinquency Tags": "Tags für Kreditausfälle", @@ -1794,6 +1798,7 @@ "Disbursement Date": "Auszahlungsdatum", "Disbursement On": "Auszahlung erfolgt", "Disbursement on": "Auszahlung am", + "Discount": "Rabatt", "Display Name": "Anzeigename", "Dividend Amount": "Dividendenbetrag", "Dividend Period End Date": "Enddatum des Dividendenzeitraums", @@ -2384,6 +2389,7 @@ "Priority": "Priorität", "Product": "Produkt", "Product Name": "Produktname", + "Product Type": "Produkttyp", "Products": "Produkte", "Profession": "Beruf", "Proposed Amount": "Vorgeschlagener Betrag", @@ -2643,6 +2649,7 @@ "Total Interest Earned": "Insgesamt verdiente Zinsen", "Total No. of Shares": "Gesamtzahl der Anteile", "Total Number of Shares": "Gesamtzahl der Aktien", + "Total Payment": "Gesamtbetrag", "Total Records": "Gesamtaufzeichnungen", "Total Savings": "Gesamtersparnis", "Total Shares": "Gesamtanteile", @@ -3465,6 +3472,7 @@ "NoDocuments": "Keine Dokumente verfügbar.", "NoFileSelected": "Keine Datei ausgewählt", "NoNotesAvailable": "Keine Notizen verfügbar", + "No Loan Product was found": "Es wurde kein Kreditprodukt gefunden", "No loan locked available": "Kein gesperrter Kredit verfügbar.", "No notifications": "Keine benachrichtigungen", "No pending loan available for disbursal": "Kein ausstehendes Darlehen zur Auszahlung verfügbar.", diff --git a/src/assets/translations/en-US.json b/src/assets/translations/en-US.json index e00f760272..f363796ac5 100644 --- a/src/assets/translations/en-US.json +++ b/src/assets/translations/en-US.json @@ -889,7 +889,10 @@ "move to next repayment meeting day": "move to next repayment meeting day", "move to previous working day": "move to previous working day", "move to next meeting day": "move to next meeting day", - "Working Capital": "Working Capital" + "Working Capital": "Working Capital", + "DAYS": "DAYS", + "MONTHS": "MONTHS", + "YEARS": "YEARS" }, "commons": { "50 characters long": "50 characters long", @@ -1169,6 +1172,7 @@ "List of Users with their details": "List of Users with their details", "Loan Account OverView": "Loan Account OverView", "Loan Accounts": "Loan Accounts", + "Loan Amounts": "Loan Amounts", "Loan Delinquency Actions": "Loan Delinquency Actions", "Loan Delinquency Classification": "Loan Delinquency Classification", "Loan Delinquency Tags": "Loan Delinquency Tags", @@ -1801,6 +1805,7 @@ "Disbursement Date": "Disbursement Date", "Disbursement On": "Disbursement On", "Disbursement on": "Disbursement on", + "Discount": "Discount", "Display Name": "Display Name", "Dividend Amount": "Dividend Amount", "Dividend Period End Date": "Dividend Period End Date", @@ -2403,6 +2408,7 @@ "Priority": "Priority", "Product": "Product", "Product Name": "Product Name", + "Product Type": "Product Type", "Products": "Products", "Profession": "Profession", "Proposed Amount": "Proposed Amount", @@ -2664,6 +2670,7 @@ "Total Interest Earned": "Total Interest Earned", "Total No. of Shares": "Total No. of Shares", "Total Number of Shares": "Total Number of Shares", + "Total Payment": "Total Payment", "Total Records": "Total Records", "Total Savings": "Total Savings", "Total Shares": "Total Shares", @@ -3584,6 +3591,7 @@ "NoDocuments": "No documents available.", "NoFileSelected": "No file selected", "NoNotesAvailable": "No notes available", + "No Loan Product was found": "No Loan Product was found", "No loan locked available": "No loan locked available.", "No notifications": "No notifications", "No pending loan available for disbursal": "No pending loan available for disbursal.", diff --git a/src/assets/translations/es-CL.json b/src/assets/translations/es-CL.json index 4c36fc2164..fc35087b03 100644 --- a/src/assets/translations/es-CL.json +++ b/src/assets/translations/es-CL.json @@ -885,7 +885,10 @@ "move to next repayment meeting day": "mover al siguiente día de reunión de pago", "move to previous working day": "mover al día laborable anterior", "move to next meeting day": "mover al siguiente día de reunión", - "Working Capital": "Capital de Trabajo" + "Working Capital": "Capital de Trabajo", + "DAYS": "DÍAS", + "MONTHS": "MESES", + "YEARS": "AÑOS" }, "commons": { "50 characters long": "50 caracteres de largo", @@ -1155,6 +1158,7 @@ "List of Users with their details": "Listado de Usuarios con sus datos", "Loan Account OverView": "Resumen cuenta de Crédito", "Loan Accounts": "Cuentas de Crédito", + "Loan Amounts": "Montos del Crédito", "Loan Delinquency Actions": "Acciones de Morosidad de Crédito", "Loan Delinquency Classification": "Clasificación de morosidad de créditos", "Loan Delinquency Tags": "Etiquetas de morosidad de Créditos", @@ -1794,6 +1798,7 @@ "Disbursement Date": "Fecha de curso", "Disbursement On": "Curso en", "Disbursement on": "Curso en", + "Discount": "Descuento", "Display Name": "Nombre para mostrar", "Dividend Amount": "Monto del dividendo", "Dividend Period End Date": "Fecha de finalización del período de dividendos", @@ -2385,6 +2390,7 @@ "Priority": "Prioridad", "Product": "Producto", "Product Name": "Nombre del Producto", + "Product Type": "Tipo de Producto", "Products": "Productos", "Profession": "Profesión", "Proposed Amount": "Monto propuesto", @@ -2644,6 +2650,7 @@ "Total Interest Earned": "Interés total ganado", "Total No. of Shares": "Número total de acciones", "Total Number of Shares": "Número total de acciones", + "Total Payment": "Pago total", "Total Records": "Registros totales", "Total Savings": "Ahorros totales", "Total Shares": "Acciones totales", @@ -3466,6 +3473,7 @@ "NoDocuments": "No hay documentos disponibles.", "NoFileSelected": "No se ha seleccionado ningún archivo", "NoNotesAvailable": "No hay notas disponibles", + "No Loan Product was found": "No se encontró ningún producto de crédito", "No loan locked available": "No hay Crédito bloqueado disponible.", "No notifications": "Sin notificaciones", "No pending loan available for disbursal": "No hay Crédito pendiente disponible para curso.", diff --git a/src/assets/translations/es-MX.json b/src/assets/translations/es-MX.json index 67e572ef64..80848cba68 100644 --- a/src/assets/translations/es-MX.json +++ b/src/assets/translations/es-MX.json @@ -888,7 +888,10 @@ "move to next repayment meeting day": "mover al siguiente día de reunión de pago", "move to previous working day": "mover al día laborable anterior", "move to next meeting day": "mover al siguiente día de reunión", - "Working Capital": "Capital de Trabajo" + "Working Capital": "Capital de Trabajo", + "DAYS": "DÍAS", + "MONTHS": "MESES", + "YEARS": "AÑOS" }, "commons": { "50 characters long": "50 caracteres de largo", @@ -1157,6 +1160,7 @@ "List of Users with their details": "Listado de Usuarios con sus datos", "Loan Account OverView": "Resumen cuenta de Crédito", "Loan Accounts": "Cuentas de Crédito", + "Loan Amounts": "Montos del Crédito", "Loan Delinquency Actions": "Acciones de Morosidad de Crédito", "Loan Delinquency Classification": "Clasificación de morosidad de créditos", "Loan Delinquency Tags": "Clasificación de morosidad de Créditos", @@ -1796,6 +1800,7 @@ "Disbursement Date": "Fecha de desembolso", "Disbursement On": "Desembolso en", "Disbursement on": "Desembolso en", + "Discount": "Descuento", "Display Name": "Nombre para mostrar", "Dividend Amount": "Monto del dividendo", "Dividend Period End Date": "Fecha de finalización del período de dividendos", @@ -2388,6 +2393,7 @@ "Priority": "Prioridad", "Product": "Producto", "Product Name": "Nombre del Producto", + "Product Type": "Tipo de Producto", "Products": "Productos", "Profession": "Profesión", "Proposed Amount": "Monto propuesto", @@ -2648,6 +2654,7 @@ "Total Interest Earned": "Interés total ganado", "Total No. of Shares": "Número total de acciones", "Total Number of Shares": "Número total de acciones", + "Total Payment": "Pago total", "Total Records": "Registros totales", "Total Savings": "Ahorros totales", "Total Shares": "Acciones totales", @@ -3497,6 +3504,7 @@ "NoDocuments": "No hay documentos disponibles.", "NoFileSelected": "No se ha seleccionado ningún archivo", "NoNotesAvailable": "No hay notas disponibles", + "No Loan Product was found": "No se encontró ningún producto de crédito", "No loan locked available": "No hay crédito bloqueado disponible.", "No notifications": "Sin notificaciones", "No pending loan available for disbursal": "No hay Crédito pendiente disponible para desembolso.", diff --git a/src/assets/translations/fr-FR.json b/src/assets/translations/fr-FR.json index 8020a3aee6..14033df587 100644 --- a/src/assets/translations/fr-FR.json +++ b/src/assets/translations/fr-FR.json @@ -886,7 +886,10 @@ "move to next repayment meeting day": "déplacer au jour de réunion de remboursement suivant", "move to previous working day": "déplacer au jour ouvrable précédent", "move to next meeting day": "déplacer au jour de réunion suivant", - "Working Capital": "Fonds de roulement" + "Working Capital": "Fonds de roulement", + "DAYS": "JOURS", + "MONTHS": "MOIS", + "YEARS": "ANNÉES" }, "commons": { "50 characters long": "50 caractères", @@ -1158,6 +1161,7 @@ "List of Users with their details": "Liste des utilisateurs avec leurs coordonnées", "Loan Account OverView": "Aperçu du compte de prêt", "Loan Accounts": "Comptes de prêt", + "Loan Amounts": "Montants des prêts", "Loan Delinquency Actions": "Actions de délinquance de prêt", "Loan Delinquency Classification": "Classification de délinquance de prêt", "Loan Delinquency Tags": "Étiquettes de délinquance de prêt", @@ -1797,6 +1801,7 @@ "Disbursement Date": "Date de décaissement", "Disbursement On": "Décaissement le", "Disbursement on": "Décaissement le", + "Discount": "Rabais", "Display Name": "Afficher un nom", "Dividend Amount": "Montant du dividende", "Dividend Period End Date": "Date de fin de la période de dividende", @@ -2387,6 +2392,7 @@ "Priority": "Priorité", "Product": "Produit", "Product Name": "Nom du produit", + "Product Type": "Type de produit", "Products": "Des produits", "Profession": "Profession", "Proposed Amount": "Montant proposé", @@ -2646,6 +2652,7 @@ "Total Interest Earned": "Intérêts totaux gagnés", "Total No. of Shares": "Nombre total d'actions", "Total Number of Shares": "Nombre total d'actions", + "Total Payment": "Paiement total", "Total Records": "Total des enregistrements", "Total Savings": "Économies totales", "Total Shares": "Total des actions", @@ -3467,6 +3474,7 @@ "NoDocuments": "Aucun document disponible.", "NoFileSelected": "Aucun fichier sélectionné", "NoNotesAvailable": "Aucune note disponible", + "No Loan Product was found": "Aucun produit de prêt n'a été trouvé.", "No loan locked available": "Aucun prêt bloqué disponible.", "No notifications": "Pas de notifications", "No pending loan available for disbursal": "Aucun prêt en attente disponible pour décaissement.", diff --git a/src/assets/translations/it-IT.json b/src/assets/translations/it-IT.json index 30ad07a918..566e655fe8 100644 --- a/src/assets/translations/it-IT.json +++ b/src/assets/translations/it-IT.json @@ -885,7 +885,10 @@ "move to next repayment meeting day": "spostare al giorno di riunione di rimborso successivo", "move to previous working day": "spostare al giorno lavorativo precedente", "move to next meeting day": "spostare al giorno di riunione successivo", - "Working Capital": "Capitale circolante" + "Working Capital": "Capitale circolante", + "DAYS": "GIORNI", + "MONTHS": "MESI", + "YEARS": "ANNI" }, "commons": { "50 characters long": "50 caratteri di lunghezza", @@ -1154,6 +1157,7 @@ "List of Users with their details": "Elenco degli Utenti con i loro dettagli", "Loan Account OverView": "Panoramica del conto di prestito", "Loan Accounts": "Conti di prestito", + "Loan Amounts": "Importi di prestito", "Loan Delinquency Actions": "Azioni di delinquenza del prestito", "Loan Delinquency Classification": "Classificazione della delinquenza del prestito", "Loan Delinquency Tags": "Tag di insolvenza del prestito", @@ -1793,6 +1797,7 @@ "Disbursement Date": "Data di erogazione", "Disbursement On": "Erogazione attivata", "Disbursement on": "Erogazione in corso", + "Discount": "Sconto", "Display Name": "Nome da visualizzare", "Dividend Amount": "Importo del dividendo", "Dividend Period End Date": "Data di fine del periodo di dividendo", @@ -2383,6 +2388,7 @@ "Priority": "Priorità", "Product": "Prodotto", "Product Name": "nome del prodotto", + "Product Type": "Tipo di prodotto", "Products": "Prodotti", "Profession": "Professione", "Proposed Amount": "Importo proposto", @@ -2642,6 +2648,7 @@ "Total Interest Earned": "Interessi totali guadagnati", "Total No. of Shares": "Numero totale di azioni", "Total Number of Shares": "Numero totale di azioni", + "Total Payment": "Pagamento totale", "Total Records": "Record totali", "Total Savings": "Risparmi totali", "Total Shares": "Azioni totali", @@ -3463,6 +3470,7 @@ "NoDocuments": "Nessun documento disponibile.", "NoFileSelected": "Nessun file selezionato", "NoNotesAvailable": "Nessuna nota disponibile", + "No Loan Product was found": "Nessun prodotto di prestito trovato", "No loan locked available": "Nessun prestito bloccato disponibile.", "No pending loan available for disbursal": "Nessun prestito pendente disponibile per l'erogazione.", "No notifications": "Nessuna notifica", diff --git a/src/assets/translations/ko-KO.json b/src/assets/translations/ko-KO.json index 086bca8d46..f97ed6d014 100644 --- a/src/assets/translations/ko-KO.json +++ b/src/assets/translations/ko-KO.json @@ -886,7 +886,10 @@ "move to next repayment meeting day": "다음 상환 회의일로 이동", "move to previous working day": "이전 근무일로 이동", "move to next meeting day": "다음 회의일로 이동", - "Working Capital": "운전자본" + "Working Capital": "운전자본", + "DAYS": "날", + "MONTHS": "개월", + "YEARS": "연령" }, "commons": { "50 characters long": "50자(영문 기준)", @@ -1155,6 +1158,7 @@ "List of Users with their details": "세부 정보가 포함된 사용자 목록", "Loan Account OverView": "대출계좌 개요", "Loan Accounts": "대출 계좌", + "Loan Amounts": "대출 금액", "Loan Delinquency Actions": "대출 연체 조치", "Loan Delinquency Classification": "대출 연체 분류", "Loan Delinquency Tags": "대출 연체 태그", @@ -1795,6 +1799,7 @@ "Disbursement Date": "지급일", "Disbursement On": "지불 날짜", "Disbursement on": "지불 날짜", + "Discount": "할인", "Display Name": "이름 표시하기", "Dividend Amount": "배당금액", "Dividend Period End Date": "배당기간 종료일", @@ -2385,6 +2390,7 @@ "Priority": "우선 사항", "Product": "제품", "Product Name": "상품명", + "Product Type": "제품 유형", "Products": "제품", "Profession": "직업", "Proposed Amount": "제안된 금액", @@ -2644,6 +2650,7 @@ "Total Interest Earned": "총 이자 수익", "Total No. of Shares": "총 주식수", "Total Number of Shares": "총 주식수", + "Total Payment": "총 결제 금액", "Total Records": "총 기록", "Total Savings": "총 절감액", "Total Shares": "총주식수", @@ -3464,6 +3471,7 @@ "NoDocuments": "사용 가능한 문서가 없습니다.", "NoFileSelected": "선택된 파일 없음", "NoNotesAvailable": "사용 가능한 메모 없음", + "No Loan Product was found": "대출 상품을 찾을 수 없습니다.", "No loan locked available": "잠긴 대출이 없습니다.", "No notifications": "알림 없음", "No pending loan available for disbursal": "지급 가능한 보류 중인 대출이 없습니다.", diff --git a/src/assets/translations/lt-LT.json b/src/assets/translations/lt-LT.json index 3bad07eb34..03d896c4ff 100644 --- a/src/assets/translations/lt-LT.json +++ b/src/assets/translations/lt-LT.json @@ -884,7 +884,10 @@ "move to next repayment meeting day": "perkelti į kitą grąžinimo susitikimo dieną", "move to previous working day": "perkelti į ankstesnę darbo dieną", "move to next meeting day": "perkelti į kitą susitikimo dieną", - "Working Capital": "Apyvartinis kapitalas" + "Working Capital": "Apyvartinis kapitalas", + "DAYS": "DIENOS", + "MONTHS": "MĖNESIŲ", + "YEARS": "METAI" }, "commons": { "50 characters long": "50 simbolių ilgio", @@ -1153,6 +1156,7 @@ "List of Users with their details": "Vartotojų sąrašas su jų duomenimis", "Loan Account OverView": "Paskolos sąskaitos apžvalga", "Loan Accounts": "Paskolų sąskaitos", + "Loan Amounts": "Paskolų sumos", "Loan Delinquency Actions": "Paskolos nusikalstamumo veiksmai", "Loan Delinquency Classification": "Paskolos nusikalstamumo klasifikacija", "Loan Delinquency Tags": "Paskolų vėlavimo žymos", @@ -1792,6 +1796,7 @@ "Disbursement Date": "Išmokėjimo data", "Disbursement On": "Išmokėjimas Įjungtas", "Disbursement on": "Išmokėjimas įjungtas", + "Discount": "Nuolaida", "Display Name": "Rodomas pavadinimas", "Dividend Amount": "Dividendų suma", "Dividend Period End Date": "Dividendų laikotarpio pabaigos data", @@ -2382,6 +2387,7 @@ "Priority": "Pirmenybė", "Product": "Produktas", "Product Name": "produkto pavadinimas", + "Product Type": "Produkto tipas", "Products": "Produktai", "Profession": "Profesija", "Proposed Amount": "Siūloma suma", @@ -2640,6 +2646,7 @@ "Total Interest Earned": "Iš viso uždirbtos palūkanos", "Total No. of Shares": "Bendras akcijų skaičius", "Total Number of Shares": "Bendras akcijų skaičius", + "Total Payment": "Bendra mokėjimo suma", "Total Records": "Iš viso įrašų", "Total Savings": "Iš viso sutaupyta", "Total Shares": "Iš viso akcijų", @@ -3465,6 +3472,7 @@ "NoDocuments": "Nėra dokumentų.", "NoFileSelected": "Failas nepasirinktas", "NoNotesAvailable": "Nėra prieinamų pastabų", + "No Loan Product was found": "Nerasta jokių paskolos produktų", "No loan locked available": "Nėra užblokuotos paskolos.", "No notifications": "Nėra pranešimų", "No pending loan available for disbursal": "Nėra laukiamos paskolos, kurią būtų galima išmokėti.", diff --git a/src/assets/translations/lv-LV.json b/src/assets/translations/lv-LV.json index 5b7a24feb8..9a68e01e84 100644 --- a/src/assets/translations/lv-LV.json +++ b/src/assets/translations/lv-LV.json @@ -886,7 +886,10 @@ "move to next repayment meeting day": "pārvietot uz nākamo atmaksas sanāksmes dienu", "move to previous working day": "pārvietot uz iepriekšējo darba dienu", "move to next meeting day": "pārvietot uz nākamo sanāksmes dienu", - "Working Capital": "Apgrozāmie līdzekļi" + "Working Capital": "Apgrozāmie līdzekļi", + "DAYS": "DIENAS", + "MONTHS": "MĒNEŠI", + "YEARS": "GADI" }, "commons": { "50 characters long": "50 rakstzīmes garš", @@ -1155,6 +1158,7 @@ "List of Users with their details": "Lietotāju saraksts ar viņu informāciju", "Loan Account OverView": "Aizdevuma konta pārskats", "Loan Accounts": "Aizdevuma konti", + "Loan Amounts": "Aizdevuma summas", "Loan Delinquency Actions": "Aizdevuma likumpārkāpumu darbības", "Loan Delinquency Classification": "Aizdevumu likumpārkāpumu klasifikācija", "Loan Delinquency Tags": "Aizdevuma kavējuma birkas", @@ -1794,6 +1798,7 @@ "Disbursement Date": "Izmaksas datums", "Disbursement On": "Izmaksa ieslēgta", "Disbursement on": "Izmaksa ieslēgta", + "Discount": "Atlaide", "Display Name": "Parādāmais nosaukums", "Dividend Amount": "Dividenžu summa", "Dividend Period End Date": "Dividenžu perioda beigu datums", @@ -2384,6 +2389,7 @@ "Priority": "Prioritāte", "Product": "Produkts", "Product Name": "produkta nosaukums", + "Product Type": "Produkta veids", "Products": "Produkti", "Profession": "Profesija", "Proposed Amount": "Piedāvātā summa", @@ -2643,6 +2649,7 @@ "Total Interest Earned": "Kopējie nopelnītie procenti", "Total No. of Shares": "Kopējais akciju skaits", "Total Number of Shares": "Kopējais akciju skaits", + "Total Payment": "Kopējais maksājums", "Total Records": "Kopējie ieraksti", "Total Savings": "Kopējie ietaupījumi", "Total Shares": "Kopējās akcijas", @@ -3464,6 +3471,7 @@ "NoDocuments": "Nav pieejamu dokumentu.", "NoFileSelected": "Nav izvēlēts fails", "NoNotesAvailable": "Nav pieejamas piezīmes", + "No Loan Product was found": "Nav atrasts neviens aizdevuma produkts", "No loan locked available": "Nav pieejams bloķēts aizdevums.", "No notifications": "Nav paziņojumu", "No pending loan available for disbursal": "Nav pieejams neizmaksāts aizdevums.", diff --git a/src/assets/translations/ne-NE.json b/src/assets/translations/ne-NE.json index 329cf9d958..2044e6a1f1 100644 --- a/src/assets/translations/ne-NE.json +++ b/src/assets/translations/ne-NE.json @@ -884,7 +884,10 @@ "move to next repayment meeting day": "अर्को भुक्तानी बैठक दिनमा सार्नुहोस्", "move to previous working day": "अघिल्लो काम गर्ने दिनमा सार्नुहोस्", "move to next meeting day": "अर्को बैठक दिनमा सार्नुहोस्", - "Working Capital": "कार्यशील पूँजी" + "Working Capital": "कार्यशील पूँजी", + "DAYS": "दिनहरू", + "MONTHS": "महिनाहरू", + "YEARS": "वर्षहरू" }, "commons": { "50 characters long": "५० वर्ण लामो", @@ -1153,6 +1156,7 @@ "List of Users with their details": "तिनीहरूको विवरण सहित प्रयोगकर्ताहरूको सूची", "Loan Account OverView": "ऋण खाता अवलोकन", "Loan Accounts": "ऋण खाताहरू", + "Loan Amounts": "ऋण रकम", "Loan Delinquency Actions": "Dep ण दिक्विटी कार्यहरू", "Loan Delinquency Classification": "कर्जा दुस्तुरी वर्गीकरण", "Loan Delinquency Tags": "ऋण अपराध ट्यागहरू", @@ -1791,6 +1795,7 @@ "Disbursement Date": "वितरण मिति", "Disbursement On": "वितरण सुरु", "Disbursement on": "वितरण जारी छ", + "Discount": "छुट", "Display Name": "प्रदर्शन नाम", "Dividend Amount": "लाभांश रकम", "Dividend Period End Date": "लाभांश अवधि समाप्ति मिति", @@ -2381,6 +2386,7 @@ "Priority": "प्राथमिकता", "Product": "उत्पादन", "Product Name": "उत्पादनको नाम", + "Product Type": "उत्पादन प्रकार", "Products": "उत्पादनहरू", "Profession": "पेशा", "Proposed Amount": "प्रस्तावित रकम", @@ -2640,6 +2646,7 @@ "Total Interest Earned": "कुल ब्याज कमाइयो", "Total No. of Shares": "शेयर को कुल संख्या", "Total Number of Shares": "शेयर को कुल संख्या", + "Total Payment": "कुल भुक्तानी", "Total Records": "कुल रेकर्डहरू", "Total Savings": "कुल बचत", "Total Shares": "कुल शेयर", @@ -3462,6 +3469,7 @@ "NoDocuments": "कुनै कागजात उपलब्ध छैन।", "NoFileSelected": "कुनै फाइल छानिएको छैन", "NoNotesAvailable": "कुनै नोटहरू उपलब्ध छैनन्", + "No Loan Product was found": "कुनै ऋण उत्पादन फेला परेन।", "No loan locked available": "कुनै ऋण उपलब्ध छैन।", "No notifications": "कुनै सूचना छैन", "No pending loan available for disbursal": "वितरणको लागि कुनै पेन्डिङ ऋण उपलब्ध छैन।", diff --git a/src/assets/translations/pt-PT.json b/src/assets/translations/pt-PT.json index 306e7fe983..66de6e792b 100644 --- a/src/assets/translations/pt-PT.json +++ b/src/assets/translations/pt-PT.json @@ -886,7 +886,10 @@ "move to next repayment meeting day": "mover para o próximo dia de reunião de pagamento", "move to previous working day": "mover para o dia útil anterior", "move to next meeting day": "mover para o próximo dia de reunião", - "Working Capital": "Capital de giro" + "Working Capital": "Capital de giro", + "DAYS": "DIAS", + "MONTHS": "MESES", + "YEARS": "ANOS" }, "commons": { "50 characters long": "50 caracteres", @@ -1154,6 +1157,7 @@ "List of Users with their details": "Lista de usuários com seus dados", "Loan Account OverView": "Visão geral da conta de empréstimo", "Loan Accounts": "Contas de empréstimo", + "Loan Amounts": "Valores de empréstimo", "Loan Delinquency Actions": "Ações de inadimplência de empréstimos", "Loan Delinquency Classification": "Classificação de inadimplência de empréstimos", "Loan Delinquency Tags": "Inadimplência de Empréstimo Tags", @@ -1793,6 +1797,7 @@ "Disbursement Date": "Data de Desembolso", "Disbursement On": "Desembolso ativado", "Disbursement on": "Desembolso em", + "Discount": "Desconto", "Display Name": "Nome de exibição", "Dividend Amount": "Valor do Dividendo", "Dividend Period End Date": "Data de término do período de dividendos", @@ -2383,6 +2388,7 @@ "Priority": "Prioridade", "Product": "produtos", "Product Name": "Nome do Produto", + "Product Type": "Tipo de Produto", "Products": "Produtos", "Profession": "Profissão", "Proposed Amount": "Valor proposto", @@ -2642,6 +2648,7 @@ "Total Interest Earned": "Juros totais ganhos", "Total No. of Shares": "Nº total de ações", "Total Number of Shares": "Número Total de Ações", + "Total Payment": "Pagamento total", "Total Records": "Registros totais", "Total Savings": "Economia total", "Total Shares": "Total de ações", @@ -3464,6 +3471,7 @@ "NoDocuments": "Nenhum documento disponível.", "NoFileSelected": "Nenhum arquivo selecionado", "NoNotesAvailable": "Nenhuma nota disponível", + "No Loan Product was found": "Nenhum produto de empréstimo foi encontrado.", "No loan locked available": "Nenhum empréstimo bloqueado disponível.", "No notifications": "Sem notificações", "No pending loan available for disbursal": "Nenhum empréstimo pendente disponível para desembolso.", diff --git a/src/assets/translations/sw-SW.json b/src/assets/translations/sw-SW.json index 4635e025ab..11bd28691e 100644 --- a/src/assets/translations/sw-SW.json +++ b/src/assets/translations/sw-SW.json @@ -884,7 +884,10 @@ "move to next repayment meeting day": "hamisha kwa siku ya mkutano wa malipo ijayo", "move to previous working day": "hamisha kwa siku ya kazi iliyotangulia", "move to next meeting day": "hamisha kwa siku ya mkutano ijayo", - "Working Capital": "Mtaji wa Kufanya Kazi" + "Working Capital": "Mtaji wa Kufanya Kazi", + "DAYS": "SIKU", + "MONTHS": "MIEZI", + "YEARS": "MIAKA" }, "commons": { "50 characters long": "Urefu wa herufi 50", @@ -1152,6 +1155,7 @@ "List of Users with their details": "Orodha ya Watumiaji na maelezo yao", "Loan Account OverView": "Muhtasari wa Akaunti ya Mkopo", "Loan Accounts": "Hesabu za Mikopo", + "Loan Amounts": "Kiasi za Mikopo", "Loan Delinquency Actions": "Vitendo vya upungufu wa mkopo", "Loan Delinquency Classification": "Uainishaji wa mkopo wa mkopo", "Loan Delinquency Tags": "Lebo za Uhalifu wa Mkopo", @@ -1790,6 +1794,7 @@ "Disbursement Date": "Tarehe ya Utoaji", "Disbursement On": "Utoaji Umewashwa", "Disbursement on": "Ulipaji umewashwa", + "Discount": "Punguzo", "Display Name": "Jina la Kuonyesha", "Dividend Amount": "Kiasi cha Mgao", "Dividend Period End Date": "Tarehe ya Mwisho ya Kipindi cha Gawio", @@ -2379,7 +2384,8 @@ "Principal Threshold (%) for Last Instalment": "Kiwango Kikubwa (%) cha Awamu ya Mwisho", "Priority": "Kipaumbele", "Product": "Bidhaa", - "Product Name": "Jina la bidhaa", + "Product Name": "Jina la Bidhaa", + "Product Type": "Aina ya Bidhaa", "Products": "Bidhaa", "Profession": "Taaluma", "Proposed Amount": "Kiasi Kilichopendekezwa", @@ -2639,6 +2645,7 @@ "Total Interest Earned": "Jumla ya Riba Iliyopatikana", "Total No. of Shares": "Jumla ya Nambari ya Hisa", "Total Number of Shares": "Jumla ya Idadi ya Hisa", + "Total Payment": "Jumla ya Malipo", "Total Records": "Jumla ya Rekodi", "Total Savings": "Jumla ya Akiba", "Total Shares": "Jumla ya Hisa", @@ -3460,6 +3467,7 @@ "NoDocuments": "Hakuna hati zinazopatikana.", "NoFileSelected": "Hakuna faili iliyochaguliwa", "NoNotesAvailable": "Hakuna noti zinazopatikana", + "No Loan Product was found": "Hakuna Bidhaa ya Mkopo Iliyopatikana", "No loan locked available": "Hakuna mkopo uliofungwa unaopatikana.", "No notifications": "Hakuna arifa", "No pending loan available for disbursal": "Hakuna mkopo unaosubiri kulipwa.",