From 08e3dfbf6ee1f19a159a7aefa3921c3179e5943b Mon Sep 17 00:00:00 2001 From: Felix van Hove Date: Tue, 18 Mar 2025 01:37:24 +0100 Subject: [PATCH] fix: bug preventing individual loan application, improved GLIM (#2329) This fixes a recently introduced bug preventing individual loan applications. It also simplifies dramatically the GLIM process, improving GLIM user experience and functionality. Partially addresses: WEB-9 --- .../create-glim-account.component.html | 36 +- .../create-glim-account.component.ts | 233 ++++--- .../glim-charges-step.component.html | 201 ------ .../glim-charges-step.component.scss | 3 - .../glim-charges-step.component.spec.ts | 24 - .../glim-charges-step.component.ts | 283 -------- .../glim-details-step.component.html | 107 --- .../glim-details-step.component.scss | 0 .../glim-details-step.component.spec.ts | 24 - .../glim-details-step.component.ts | 175 ----- .../glim-preview-step.component.html | 321 --------- .../glim-preview-step.component.scss | 0 .../glim-preview-step.component.spec.ts | 24 - .../glim-preview-step.component.ts | 44 -- .../glim-terms-step.component.html | 614 ------------------ .../glim-terms-step.component.scss | 3 - .../glim-terms-step.component.spec.ts | 24 - .../glim-terms-step.component.ts | 520 --------------- .../loans-account-charges-step.component.html | 54 ++ .../loans-account-charges-step.component.ts | 48 +- .../loans-account-preview-step.component.html | 4 + .../loans-account-preview-step.component.ts | 13 + .../loans-account-terms-step.component.ts | 1 + src/app/loans/loans-routing.module.ts | 1 - src/app/loans/loans.module.ts | 8 - src/app/loans/loans.service.ts | 2 +- 26 files changed, 286 insertions(+), 2481 deletions(-) delete mode 100644 src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-charges-step/glim-charges-step.component.html delete mode 100644 src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-charges-step/glim-charges-step.component.scss delete mode 100644 src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-charges-step/glim-charges-step.component.spec.ts delete mode 100644 src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-charges-step/glim-charges-step.component.ts delete mode 100644 src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-details-step/glim-details-step.component.html delete mode 100644 src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-details-step/glim-details-step.component.scss delete mode 100644 src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-details-step/glim-details-step.component.spec.ts delete mode 100644 src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-details-step/glim-details-step.component.ts delete mode 100644 src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-preview-step/glim-preview-step.component.html delete mode 100644 src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-preview-step/glim-preview-step.component.scss delete mode 100644 src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-preview-step/glim-preview-step.component.spec.ts delete mode 100644 src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-preview-step/glim-preview-step.component.ts delete mode 100644 src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-terms-step/glim-terms-step.component.html delete mode 100644 src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-terms-step/glim-terms-step.component.scss delete mode 100644 src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-terms-step/glim-terms-step.component.spec.ts delete mode 100644 src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-terms-step/glim-terms-step.component.ts diff --git a/src/app/loans/glim-account/create-glim-account/create-glim-account.component.html b/src/app/loans/glim-account/create-glim-account/create-glim-account.component.html index ac11c8cd3..18c322677 100644 --- a/src/app/loans/glim-account/create-glim-account/create-glim-account.component.html +++ b/src/app/loans/glim-account/create-glim-account/create-glim-account.component.html @@ -23,38 +23,57 @@ {{ 'labels.inputs.DETAILS' | translate }} - - + {{ 'labels.inputs.TERMS' | translate }} - - + {{ 'labels.inputs.CHARGES' | translate }} - - + + + + + {{ 'labels.inputs.REPAYMENT SCHEDULE' | translate }} + + + + + + + {{ datatable.registeredTableName }} + + @@ -64,6 +83,7 @@ [loansAccountTemplate]="loansAccountTemplate" [loansAccountProductTemplate]="loansAccountProductTemplate" [loansAccount]="loansAccount" + [activeClientMembers]="activeClientMembers" (submitEvent)="submit()" > diff --git a/src/app/loans/glim-account/create-glim-account/create-glim-account.component.ts b/src/app/loans/glim-account/create-glim-account/create-glim-account.component.ts index 24bc7b806..add87c3ff 100644 --- a/src/app/loans/glim-account/create-glim-account/create-glim-account.component.ts +++ b/src/app/loans/glim-account/create-glim-account/create-glim-account.component.ts @@ -1,15 +1,18 @@ /** Angular Imports */ -import { Component, ViewChild, /* Felix: added: */ QueryList, ViewChildren } from '@angular/core'; +import { Component, QueryList, ViewChild, ViewChildren } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; /** Custom Services */ -import { LoansService } from 'app/loans/loans.service'; +import { LoansService } from '../../loans.service'; import { SettingsService } from 'app/settings/settings.service'; +import { Dates } from 'app/core/utils/dates'; +import { ClientsService } from 'app/clients/clients.service'; /** Step Components */ -import { GlimChargesStepComponent } from './glim-account-stepper/glim-charges-step/glim-charges-step.component'; -import { GlimDetailsStepComponent } from './glim-account-stepper/glim-details-step/glim-details-step.component'; -import { GlimTermsStepComponent } from './glim-account-stepper/glim-terms-step/glim-terms-step.component'; +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'; +import { LoansAccountChargesStepComponent } from '../../loans-account-stepper/loans-account-charges-step/loans-account-charges-step.component'; +import { LoansAccountDatatableStepComponent } from '../../loans-account-stepper/loans-account-datatable-step/loans-account-datatable-step.component'; @Component({ selector: 'mifosx-create-glim-account', @@ -17,34 +20,33 @@ import { GlimTermsStepComponent } from './glim-account-stepper/glim-terms-step/g styleUrls: ['./create-glim-account.component.scss'] }) export class CreateGlimAccountComponent { - /** Imports all the step components */ - @ViewChild(GlimDetailsStepComponent, { static: true }) loansAccountDetailsStep: GlimDetailsStepComponent; - @ViewChild(GlimTermsStepComponent, { static: true }) loansAccountTermsStep: GlimTermsStepComponent; - @ViewChild(GlimChargesStepComponent, { static: true }) loansAccountChargesStep: GlimChargesStepComponent; + /** Imports all the step component */ + @ViewChild(LoansAccountDetailsStepComponent, { static: true }) + loansAccountDetailsStep: LoansAccountDetailsStepComponent; + @ViewChild(LoansAccountTermsStepComponent, { static: true }) loansAccountTermsStep: LoansAccountTermsStepComponent; + @ViewChild(LoansAccountChargesStepComponent, { static: true }) + loansAccountChargesStep: LoansAccountChargesStepComponent; + /** Get handle on dtloan tags in the template */ + @ViewChildren('dtloan') loanDatatables: QueryList; /** Loans Account Template */ loansAccountTemplate: any; /** Loans Account Product Template */ loansAccountProductTemplate: any | null = null; + /** Table Data Source */ + dataSource: any; + /** Selected Members */ + selectedMembers: any; + /** Collateral Options */ + collateralOptions: any; /** Multi Disburse Loan */ multiDisburseLoan: any; /** Principal Amount */ principal: any; + datatables: any = []; /** Currency Code */ currencyCode: string; - // accountLinkingOptions: any; - - // totalLoan: any; - - // /** Table Data Source */ - // dataSource: any; - // /** Selected Members */ - selectedMembers: any; - // /** Selected Members */ - activeClientMembers: any; - gsimData: any; - /** * Sets loans account create form. * @param {route} ActivatedRoute Activated Route. @@ -57,29 +59,53 @@ export class CreateGlimAccountComponent { private route: ActivatedRoute, private router: Router, private loansService: LoansService, - private settingsService: SettingsService + private settingsService: SettingsService, + private clientService: ClientsService, + private dateUtils: Dates ) { - this.route.data.subscribe((data: { loansAccountTemplate: any; gsimData: any; groupsData: any }) => { + this.route.data.subscribe((data: { loansAccountTemplate: any; groupsData: any }) => { this.loansAccountTemplate = data.loansAccountTemplate; - this.activeClientMembers = data.groupsData.activeClientMembers; - this.gsimData = data.gsimData; + this.dataSource = data.groupsData.activeClientMembers; }); } /** - * Sets glim account product template and collateral template + * Sets loans account product template and collateral template * @param {any} $event API response */ setTemplate($event: any) { this.loansAccountProductTemplate = $event; 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'); + } 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, true, productId).subscribe((response: any) => { + this.loansService.getLoansAccountTemplateResource(entityId, isGroup, productId).subscribe((response: any) => { this.multiDisburseLoan = response.multiDisburseLoan; }); + this.setDatatables(); + } + + setDatatables(): void { + this.datatables = []; + + if (this.loansAccountProductTemplate.datatables) { + this.loansAccountProductTemplate.datatables.forEach((datatable: any) => { + this.datatables.push(datatable); + }); + } } /** Get Loans Account Details Form Data */ @@ -92,6 +118,13 @@ export class CreateGlimAccountComponent { return this.loansAccountTermsStep.loansAccountTermsForm; } + /** + * Retrieves savings account terms form. + */ + get activeClientMembers() { + return this.dataSource; + } + /** Checks whether all the forms in different steps are valid or not */ get loansAccountFormValid() { return ( @@ -101,93 +134,105 @@ export class CreateGlimAccountComponent { /** Gets principal Amount */ get loanPrincipal() { - return this.loansAccountChargesStep.selectedClientMembers.selectedMembers.reduce( - (acc: number, member: any) => acc + member.principal, - 0 - ); + return this.loansAccountTermsStep.loansAccountTermsForm.value.principal; } /** Retrieves Data of all forms except Currency to submit the data */ get loansAccount() { + this.selectedMembers = this.loansAccountChargesStep.selectedClientMembers; return { ...this.loansAccountDetailsStep.loansAccountDetails, ...this.loansAccountTermsStep.loansAccountTerms, ...this.loansAccountChargesStep.loansAccountCharges, + ...this.loansAccountTermsStep.loanCollateral, ...this.loansAccountTermsStep.disbursementData }; } - // setData(client: any): any { - // const locale = this.settingsService.language.code; - // const dateFormat = this.settingsService.dateFormat; - // // const monthDayFormat = 'dd MMMM'; - // const data = { - // ...this.loansAccount, - // charges: this.loansAccount.charges.map((charge: any) => ({ - // chargeId: charge.id, - // amount: charge.amount - // })), - // clientId: client.id, - // totalLoan: this.totalLoan, - // loanType: 'glim', - // amortizationType: 1, - // isParentAccount: true, - // principal: client.principal, - // syncDisbursementWithMeeting: false, - // expectedDisbursementDate: this.dateUtils.formatDate(this.loansAccount.expectedDisbursementDate, dateFormat), - // submittedOnDate: this.dateUtils.formatDate(this.loansAccount.submittedOnDate, dateFormat), - // dateFormat, - // // monthDayFormat, - // locale - // }; - // data.groupId = this.loansAccountTemplate.group.id; + setData(client: any, totalLoan: number): any { + const locale = this.settingsService.language.code; + const dateFormat = this.settingsService.dateFormat; + // const monthDayFormat = 'dd MMMM'; + const data = { + ...this.loansAccount, + charges: this.loansAccount.charges.map((charge: any) => ({ + chargeId: charge.id, + amount: charge.amount + })), + clientId: client.id, + totalLoan: totalLoan, + loanType: 'glim', + amortizationType: 1, + isParentAccount: true, + principal: client.principal, + syncDisbursementWithMeeting: false, + expectedDisbursementDate: this.dateUtils.formatDate(this.loansAccount.expectedDisbursementDate, dateFormat), + submittedOnDate: this.dateUtils.formatDate(this.loansAccount.submittedOnDate, dateFormat), + dateFormat, + // monthDayFormat, + locale + }; + data.groupId = this.loansAccountTemplate.group.id; - // return JSON.stringify(data); - // } + delete data.principalAmount; + // TODO: 2025-03-17: Apparently (?!) unsupported for GLIM + delete data.allowPartialPeriodInterestCalculation; + delete data.multiDisburseLoan; + delete data.isFloatingInterestRate; + + return JSON.stringify(data); + } + + /** Request Body Data */ + buildRequestData(): any[] { + const requestData = []; + const memberSelected = this.selectedMembers.selectedMembers; + const totalLoan = this.totalLoanAmount(); + for (let index = 0; index < memberSelected.length; index++) { + requestData.push({ + requestId: index.toString(), + method: 'POST', + relativeUrl: 'loans', + body: this.setData(memberSelected[index], totalLoan) + }); + } + return requestData; + } + + totalLoanAmount(): number { + let total = 0; + const memberSelected = this.selectedMembers.selectedMembers; + for (let index = 0; index < memberSelected.length; index++) { + total += memberSelected[index].principal; + } + return total; + } /** * Creates a new GLIM account. */ submit() { - const locale = this.settingsService.language.code; - const dateFormat = this.settingsService.dateFormat; - - const totalLoan = this.loanPrincipal; - const payloadData: any[] = []; - this.loansAccountChargesStep.selectedClientMembers.selectedMembers.forEach((member: any, index: number) => { - this.loansAccountTemplate.clientId = member.id; - this.loansAccountTemplate.loanPurposeId = member.loanPurposeId; - this.loansAccountTemplate.principal = member.principal; - this.loansAccountTemplate.totalLoan = totalLoan; - - const payload = this.loansService.buildLoanRequestPayload( - this.loansAccount, - this.loansAccountTemplate, - this.loansAccountProductTemplate.calendarOptions, - locale, - dateFormat - ); - - payloadData.push(this.getWrapper(payload, index)); - }); - - this.loansService.createGlimAccount(payloadData).subscribe((response: any) => { - this.router.navigate( - [ - '../', - JSON.parse(response[0].body).glimId - ], - { relativeTo: this.route } - ); + const data = this.buildRequestData(); + this.loansService.createGlimAccount(data).subscribe((response: any) => { + const body = JSON.parse(response[0].body); + if (body.glimId) { + this.router.navigate( + [ + '../', + body.glimId + ], + { relativeTo: this.route } + ); + } else { + this.notify(body, data); + } }); } - getWrapper(payload: any, requestId: number): any { - return { - body: JSON.stringify(payload), - method: 'POST', - relativeUrl: 'loans', - requestId: requestId - }; + notify(body: any, data: any) { + let message = body.defaultUserMessage + ' '; + while (body.errors?.length > 0) message += body.errors.pop().developerMessage + ' '; + message += 'Data: ' + JSON.stringify(data); + console.error(message); } } diff --git a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-charges-step/glim-charges-step.component.html b/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-charges-step/glim-charges-step.component.html deleted file mode 100644 index d411cac88..000000000 --- a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-charges-step/glim-charges-step.component.html +++ /dev/null @@ -1,201 +0,0 @@ -
- - {{ 'labels.inputs.Charge' | translate }} - - - {{ charge.name }} - - - - -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{{ '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 }} - - {{ (charge.dueDate | dateFormat) || 'Unassigned' }} - - - {{ (charge.feeOnMonthDay | dateFormat) || 'Unassigned' }} - - - {{ 'labels.inputs.N/A' | translate }} - - - {{ 'labels.inputs.Actions' | translate }} - -
- -

{{ '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 }}
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - {{ 'labels.inputs.Client ID' | translate }}{{ element.id }}{{ 'labels.inputs.Client Name' | translate }}{{ element.displayName }}{{ 'labels.inputs.Loan Purpose' | translate }} - - {{ 'labels.inputs.Select Purpose' | translate }} - - - {{ purpose.name }} - - - - {{ 'labels.inputs.Original Loan' | translate }} - - - -
-
-
- -
- - - -
diff --git a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-charges-step/glim-charges-step.component.scss b/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-charges-step/glim-charges-step.component.scss deleted file mode 100644 index b66af2377..000000000 --- a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-charges-step/glim-charges-step.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -.margin-t { - margin-top: 2em; -} diff --git a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-charges-step/glim-charges-step.component.spec.ts b/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-charges-step/glim-charges-step.component.spec.ts deleted file mode 100644 index 3a945da82..000000000 --- a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-charges-step/glim-charges-step.component.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { GlimChargesStepComponent } from './glim-charges-step.component'; - -describe('GlimChargesStepComponent', () => { - let component: GlimChargesStepComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [GlimChargesStepComponent] - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(GlimChargesStepComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-charges-step/glim-charges-step.component.ts b/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-charges-step/glim-charges-step.component.ts deleted file mode 100644 index f258ec13b..000000000 --- a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-charges-step/glim-charges-step.component.ts +++ /dev/null @@ -1,283 +0,0 @@ -/** Angular Imports */ -import { Component, Input, OnInit, OnChanges } from '@angular/core'; -import { MatDialog } from '@angular/material/dialog'; -import { MatTableDataSource } from '@angular/material/table'; - -/** Dialog Components */ -import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component'; -import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component'; - -/** Custom Services */ -import { DatepickerBase } from 'app/shared/form-dialog/formfield/model/datepicker-base'; -import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base'; -import { InputBase } from 'app/shared/form-dialog/formfield/model/input-base'; -import { SettingsService } from 'app/settings/settings.service'; -import { Dates } from 'app/core/utils/dates'; -import { ActivatedRoute } from '@angular/router'; - -/** - * GLIM Account Charges Step - */ -@Component({ - selector: 'mifosx-glim-charges-step', - templateUrl: './glim-charges-step.component.html', - styleUrls: ['./glim-charges-step.component.scss'] -}) -export class GlimChargesStepComponent implements OnInit, OnChanges { - /** Savings Account Product Template */ - @Input() loansAccountProductTemplate: any; - /** Savings Account Template */ - @Input() loansAccountTemplate: any; - // @Input() loansAccountFormValid: LoansAccountFormValid - @Input() loansAccountFormValid: boolean; - // active Client Members in case of GLIM Account - @Input() activeClientMembers?: any; - - /** Charge Data */ - chargeData: any = []; - /** Charges Data Source */ - chargesDataSource: {}[] = []; - /** Overdue Charges Data Source */ - overDueChargesDataSource: {}[] = []; - /** Display columns for charges table */ - chargesDisplayedColumns: string[] = [ - 'name', - 'chargeCalculationType', - 'amount', - 'chargeTimeType', - 'date', - 'action' - ]; - /** Columns to be displayed in overdue charges table. */ - overdueChargesDisplayedColumns: string[] = [ - 'name', - 'type', - 'amount', - 'collectedon' - ]; - - /** Table Data Source */ - dataSource: any; - /** Check for select all the Clients List */ - selectAllItems = false; - /** Loan Purpose Options */ - loanPurposeOptions: string[] = []; - /** Table Displayed Columns */ - displayedColumn: string[] = [ - 'check', - 'id', - 'name', - 'purpose', - 'amount' - ]; - /** Component is pristine if there has been no changes by user interaction */ - pristine = true; - loanId: any = null; - - /** - * GLIM Account Charges Form Step - * @param {dialog} MatDialog Mat Dialog - * @param {Dates} dateUtils Date Utils - * @param {ActivatedRoute} route Activated Route - * @param {SettingsService} settingsService Settings Service - */ - constructor( - public dialog: MatDialog, - private dateUtils: Dates, - private route: ActivatedRoute, - private settingsService: SettingsService - ) { - this.loanId = this.route.snapshot.params['loanId']; - } - - ngOnInit() { - // TODO: This might still need adjustments due to GLIM - this.dataSource = new MatTableDataSource(this.activeClientMembers); - - // Loan Account code: - if (this.loansAccountTemplate.charges) { - this.chargesDataSource = - this.loansAccountTemplate.charges.map((charge: any) => ({ ...charge, id: charge.chargeId })) || []; - } - } - - ngOnChanges() { - if (this.loansAccountProductTemplate) { - this.loanPurposeOptions = this.loansAccountProductTemplate.loanPurposeOptions; - - this.chargeData = this.loansAccountProductTemplate.chargeOptions; - if (this.loansAccountProductTemplate.overdueCharges) { - this.overDueChargesDataSource = this.loansAccountProductTemplate.overdueCharges; - } - if ( - this.loansAccountProductTemplate.charges && - this.loansAccountProductTemplate.charges.length > 0 && - this.chargesDataSource.length === 0 - ) { - this.chargesDataSource = - this.loansAccountProductTemplate.charges.map((charge: any) => ({ ...charge, id: charge.chargeId })) || []; - } - } - } - - /** - * Adds the charge to charges table - * @param {any} charge Charge - */ - addCharge(charge: any) { - this.chargesDataSource = this.chargesDataSource.concat([charge.value]); - charge.value = ''; - this.pristine = false; - } - - /** - * Edits the Charge Amount - * @param {any} charge Charge - */ - editChargeAmount(charge: any) { - const formfields: FormfieldBase[] = [ - new InputBase({ - controlName: 'amount', - label: 'Amount', - value: charge.amount, - type: 'number', - required: false - }) - - ]; - const data = { - title: 'Edit Charge Amount', - layout: { addButtonText: 'Confirm' }, - formfields: formfields - }; - const editNoteDialogRef = this.dialog.open(FormDialogComponent, { data }); - editNoteDialogRef.afterClosed().subscribe((response: any) => { - if (response.data) { - const newCharge = { ...charge, amount: response.data.value.amount }; - this.chargesDataSource.splice(this.chargesDataSource.indexOf(charge), 1, newCharge); - this.chargesDataSource = this.chargesDataSource.concat([]); - } - }); - this.pristine = false; - } - - /** - * Edits the Charge Date - * @param {any} charge Charge - */ - editChargeDate(charge: any) { - const formfields: FormfieldBase[] = [ - new DatepickerBase({ - controlName: 'date', - label: 'Date', - value: charge.dueDate || charge.feeOnMonthDay || '', - type: 'datetime-local', - required: false - }) - - ]; - const data = { - title: 'Edit Charge Date', - layout: { addButtonText: 'Confirm' }, - formfields: formfields - }; - const editNoteDialogRef = this.dialog.open(FormDialogComponent, { data }); - editNoteDialogRef.afterClosed().subscribe((response: any) => { - if (response.data) { - let newCharge: any; - const dateFormat = this.settingsService.dateFormat; - const date = this.dateUtils.formatDate(response.data.value.date, dateFormat); - switch (charge.chargeTimeType.value) { - case 'Specified due date': - case 'Weekly Fee': - newCharge = { ...charge, dueDate: date }; - break; - case 'Annual Fee': - newCharge = { ...charge, feeOnMonthDay: date }; - break; - } - this.chargesDataSource.splice(this.chargesDataSource.indexOf(charge), 1, newCharge); - this.chargesDataSource = this.chargesDataSource.concat([]); - } - }); - this.pristine = false; - } - - /** - * Edits the Charge Fee Interval - * @param {any} charge Charge - */ - editChargeFeeInterval(charge: any) { - const formfields: FormfieldBase[] = [ - new InputBase({ - controlName: 'feeInterval', - label: 'Fee Interval', - value: charge.feeInterval, - type: 'text', - required: false - }) - - ]; - const data = { - title: 'Edit Charge Fee Interval', - layout: { addButtonText: 'Confirm' }, - formfields: formfields - }; - const editNoteDialogRef = this.dialog.open(FormDialogComponent, { data }); - editNoteDialogRef.afterClosed().subscribe((response: any) => { - if (response.data) { - const newCharge = { ...charge, feeInterval: response.data.value.feeInterval }; - this.chargesDataSource.splice(this.chargesDataSource.indexOf(charge), 1, newCharge); - this.chargesDataSource = this.chargesDataSource.concat([]); - } - }); - this.pristine = false; - } - - /** - * Removes the charge from charges table - * @param {any} charge Charge - */ - deleteCharge(charge: any) { - const deleteChargeDialogRef = this.dialog.open(DeleteDialogComponent, { - data: { deleteContext: `charge ${charge.name}` } - }); - deleteChargeDialogRef.afterClosed().subscribe((response: any) => { - if (response.delete) { - this.chargesDataSource.splice(this.chargesDataSource.indexOf(charge), 1); - this.chargesDataSource = this.chargesDataSource.concat([]); - this.pristine = false; - } - }); - } - - /** - * Returns loan account charges - */ - get loansAccountCharges() { - return { charges: this.chargesDataSource }; - } - - get selectedClientMembers() { - return { selectedMembers: this.activeClientMembers.filter((item: any) => item.selected) }; - } - - get isValid() { - const sum = this.activeClientMembers - ?.filter((item: any) => item.selected) - .reduce((acc: number, member: any) => acc + member.principal, 0); - return sum > 0; - } - - toggleSelects() { - for (const member of this.activeClientMembers) { - member.selected = this.selectAllItems; - } - } - - toggleSelect() { - const len = this.activeClientMembers.length; - this.selectAllItems = - len === 0 ? false : this.activeClientMembers.filter((item: any) => item.selected).length === len; - } -} diff --git a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-details-step/glim-details-step.component.html b/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-details-step/glim-details-step.component.html deleted file mode 100644 index a4a122e08..000000000 --- a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-details-step/glim-details-step.component.html +++ /dev/null @@ -1,107 +0,0 @@ -
-
- - {{ 'labels.inputs.Product Name' | translate }} - - - - - - {{ product.name }} - - - - {{ 'labels.inputs.Product Name' | translate }} {{ 'labels.commons.is' | translate }} - {{ 'labels.commons.required' | translate }} - - -
- -
- - {{ 'labels.inputs.Loan officer' | translate }} - - - {{ loanOfficer.displayName }} - - - - - - {{ 'labels.inputs.Fund' | translate }} - - - {{ fund.name }} - - - - - - {{ 'labels.inputs.Submitted on' | translate }} - - - - - {{ 'labels.inputs.Submitted on' | translate }} {{ 'labels.commons.is' | translate }} - {{ 'labels.commons.required' | translate }} - - - - - {{ 'labels.inputs.Disbursement on' | translate }} - - - - - {{ 'labels.inputs.Disbursement on' | translate }} {{ 'labels.commons.is' | translate }} - {{ 'labels.commons.required' | translate }} - - - - - {{ 'labels.inputs.Link savings' | translate }} - - - {{ savingaccount.accountNumber }} {{ savingaccount.productName }} - - - -
- -
- - - -
-
diff --git a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-details-step/glim-details-step.component.scss b/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-details-step/glim-details-step.component.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-details-step/glim-details-step.component.spec.ts b/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-details-step/glim-details-step.component.spec.ts deleted file mode 100644 index 932fce58f..000000000 --- a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-details-step/glim-details-step.component.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { GlimDetailsStepComponent } from './glim-details-step.component'; - -describe('GlimDetailsStepComponent', () => { - let component: GlimDetailsStepComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [GlimDetailsStepComponent] - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(GlimDetailsStepComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-details-step/glim-details-step.component.ts b/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-details-step/glim-details-step.component.ts deleted file mode 100644 index 8f4f51b16..000000000 --- a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-details-step/glim-details-step.component.ts +++ /dev/null @@ -1,175 +0,0 @@ -/** Angular Imports */ -import { Component, OnInit, Input, Output, EventEmitter, OnDestroy } from '@angular/core'; -import { UntypedFormGroup, UntypedFormBuilder, Validators, UntypedFormControl } from '@angular/forms'; -import { ActivatedRoute } from '@angular/router'; -import { SettingsService } from 'app/settings/settings.service'; - -/** Custom Services */ -import { LoansService } from '../../../../loans.service'; -import { Commons } from 'app/core/utils/commons'; -import { takeUntil } from 'rxjs/operators'; -import { ReplaySubject, Subject } from 'rxjs'; - -// Felix: TODO's: -// - gsimData was already declared, when I found this file. Apparently, -// glim accounts can only be linked to gsim accounts. Needs to be tested -// as soon as gsim accounts are implemented. -/** - * GLIM Account Details Step - */ -@Component({ - selector: 'mifosx-glim-details-step', - templateUrl: './glim-details-step.component.html', - styleUrls: ['./glim-details-step.component.scss'] -}) -export class GlimDetailsStepComponent implements OnInit, OnDestroy { - /** Loans Account Template */ - @Input() loansAccountTemplate: any; - @Input() gsimData: any; - /** Minimum date allowed. */ - minDate = new Date(2000, 0, 1); - /** Maximum date allowed. */ - maxDate = new Date(2100, 0, 1); - /** Product Data */ - productList: any; - /** Loan Officer Data */ - loanOfficerOptions: any; - /** Loan Purpose Options */ - loanPurposeOptions: any; - /** Fund Options */ - fundOptions: any; - /** Account Linking Options */ - accountLinkingOptions: any; - /** For edit loan accounts form */ - isFieldOfficerPatched = false; - /** Loans Account Details Form */ - loansAccountDetailsForm: UntypedFormGroup; - - loanId: any = null; - - loanProductSelected = false; - /** Currency data. */ - protected productData: ReplaySubject = new ReplaySubject(1); - /** control for the filter select */ - protected filterFormCtrl: UntypedFormControl = new UntypedFormControl(''); - /** Subject that emits when the component has been destroyed. */ - protected _onDestroy = new Subject(); - - /** Loans Account Template with product data */ - @Output() loansAccountProductTemplate = new EventEmitter(); - /** - * Sets loans account details form. - * @param {FormBuilder} formBuilder Form Builder. - * @param {LoansService} loansService Loans Service. - * @param {SettingsService} settingsService SettingsService - */ - constructor( - private formBuilder: UntypedFormBuilder, - private loansService: LoansService, - private route: ActivatedRoute, - private settingsService: SettingsService, - private commons: Commons - ) { - this.loanId = this.route.snapshot.params['loanId']; - } - - ngOnInit(): void { - this.createLoansAccountDetailsForm(); - this.maxDate = this.settingsService.maxFutureDate; // Felix: originally: businessDate; - this.buildDependencies(); - if (this.loansAccountTemplate) { - this.productList = this.loansAccountTemplate.productOptions.sort(this.commons.dynamicSort('name')); - if (this.loansAccountTemplate.loanProductId) { - console.log('this.loansAccountTemplate.loanOfficerId: ', this.loansAccountTemplate.loanOfficerId); - this.loansAccountDetailsForm.patchValue({ - productId: this.loansAccountTemplate.loanProductId, - submittedOnDate: - this.loansAccountTemplate.timeline.submittedOnDate && - new Date(this.loansAccountTemplate.timeline.submittedOnDate), - loanOfficerId: this.loansAccountTemplate.loanOfficerId, - loanPurposeId: this.loansAccountTemplate.loanPurposeId, - fundId: this.loansAccountTemplate.fundId, - expectedDisbursementDate: - this.loansAccountTemplate.timeline.expectedDisbursementDate && - new Date(this.loansAccountTemplate.timeline.expectedDisbursementDate), - externalId: this.loansAccountTemplate.externalId - }); - } - } - this.filterFormCtrl.valueChanges.pipe(takeUntil(this._onDestroy)).subscribe(() => { - this.searchItem(); - }); - this.productData.next(this.productList.slice()); - } - - ngOnDestroy(): void { - this._onDestroy.next(); - this._onDestroy.complete(); - } - - searchItem(): void { - if (this.productList) { - const search: string = this.filterFormCtrl.value.toLowerCase(); - - if (!search) { - this.productData.next(this.productList.slice()); - } else { - this.productData.next( - this.productList.filter((option: any) => { - return option['name'].toLowerCase().indexOf(search) >= 0; - }) - ); - } - } - } - - /** - * Creates glim account details form. - */ - createLoansAccountDetailsForm() { - this.loansAccountDetailsForm = this.formBuilder.group({ - productId: [ - '', - Validators.required - ], - loanOfficerId: [''], - // Felix: found: loanPurposeId: [''], - not sure, where we add this list... - fundId: [''], - submittedOnDate: [ - new Date(), - Validators.required - ], - expectedDisbursementDate: [ - '', - Validators.required - ], - externalId: [''], - linkAccountId: [''], - createStandingInstructionAtDisbursement: [''] - }); - } - - /** - * Fetches loans account product template on productId value changes - */ - buildDependencies() { - const groupId = this.loansAccountTemplate.group.id; - this.loansAccountDetailsForm.get('productId').valueChanges.subscribe((productId: string) => { - this.loansService.getLoansAccountTemplateResource(groupId, true, 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; - }); - }); - } - - /** - * Returns loans account details form value. - */ - get loansAccountDetails() { - return this.loansAccountDetailsForm.getRawValue(); // Felix: was: value; - } -} diff --git a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-preview-step/glim-preview-step.component.html b/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-preview-step/glim-preview-step.component.html deleted file mode 100644 index 134c04b53..000000000 --- a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-preview-step/glim-preview-step.component.html +++ /dev/null @@ -1,321 +0,0 @@ -
-

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

- -
- {{ 'labels.inputs.Product' | translate }}: - {{ loansAccount.productId | find: loansAccountTemplate.productOptions : 'id' : 'name' }} -
- -
- {{ 'labels.inputs.Loan officer' | translate }}: - {{ - loansAccount.loanOfficerId | find: loansAccountProductTemplate.loanOfficerOptions : 'id' : 'displayName' - }} -
- -
- {{ 'labels.inputs.Loan purpose' | translate }}: - {{ - loansAccount.loanPurposeId | find: loansAccountProductTemplate.loanPurposeOptions : 'id' : 'name' - }} -
- -
- {{ 'labels.inputs.Fund' | translate }}: - {{ loansAccount.fundId | find: loansAccountProductTemplate.fundOptions : 'id' : 'name' }} -
- -
- {{ 'labels.inputs.Submitted on' | translate }}: - {{ loansAccount.submittedOnDate | dateFormat }} -
- -
- {{ 'labels.inputs.Disbursement on' | translate }}: - {{ loansAccount.expectedDisbursementDate | dateFormat }} -
- -
- {{ 'labels.inputs.External id' | translate }}: - - - -
- -

{{ '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' - }} -
- -
- {{ 'labels.inputs.Enable Down Payments' | translate }}: - {{ loansAccount.enableDownPayment | yesNo }} -
- -
- {{ 'labels.inputs.First repayment on' | translate }}: - {{ loansAccount.repaymentsStartingFromDate | dateFormat }} -
- -
- {{ 'labels.inputs.Interest charged from' | translate }}: - {{ loansAccount.interestChargedFromDate | dateFormat }} -
- -
- {{ 'labels.inputs.Nominal interest rate' | translate }}: - {{ loansAccount.interestRatePerPeriod }}  {{ - loansAccountProductTemplate.interestRateFrequencyType.value - }} -
- -
- {{ 'labels.inputs.Interest method' | translate }}: - {{ loansAccount.interestType }} -
- -
- {{ 'labels.inputs.Is Equal Amortization' | translate }}: - {{ loansAccount.isEqualAmortization }} -
- -
- {{ 'labels.inputs.Amortization' | translate }} - {{ - loansAccount.amortizationType | find: loansAccountProductTemplate.amortizationTypeOptions : 'id' : 'value' - }} -
- -
- {{ 'labels.inputs.Interest calculation period' | translate }}: - {{ - loansAccount.interestCalculationPeriodType - | find: loansAccountProductTemplate.interestCalculationPeriodTypeOptions : 'id' : 'value' - }} -
- -
- {{ 'labels.inputs.Calculate interest for exact days in partial period' | translate }}: - {{ loansAccount.allowPartialPeriodInterestCalculation }} -
- -
- {{ 'labels.inputs.Arrears tolerance' | translate }}: - {{ loansAccount.inArrearsTolerance }} -
- -
- {{ 'labels.inputs.Interest free period' | translate }}: - {{ loansAccount.graceOnInterestCharged }} -
- -
- {{ 'labels.inputs.Repayment strategy' | translate }}: - {{ - loansAccount.transactionProcessingStrategyCode - | find: loansAccountProductTemplate.transactionProcessingStrategyOptions : 'code' : 'name' - }} -
- -
- {{ 'labels.inputs.Installment Amount' | translate }} - {{ loansAccount.fixedEmiAmount | formatNumber }} -
- -
- {{ 'labels.inputs.Balloon Repayment Amount' | translate }} - {{ loansAccount.balloonRepaymentAmount | formatNumber }} -
- - - -

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

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

{{ '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 }} - - {{ (charge.dueDate | dateFormat) || 'Unassigned' }} - - - {{ (charge.feeOnMonthDay | dateFormat) || 'Unassigned' }} - - - {{ 'labels.inputs.N/A' | translate }} - -
-
- -
-

{{ '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/glim-account/create-glim-account/glim-account-stepper/glim-preview-step/glim-preview-step.component.scss b/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-preview-step/glim-preview-step.component.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-preview-step/glim-preview-step.component.spec.ts b/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-preview-step/glim-preview-step.component.spec.ts deleted file mode 100644 index 2421f3fea..000000000 --- a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-preview-step/glim-preview-step.component.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { GlimPreviewStepComponent } from './glim-preview-step.component'; - -describe('GlimPreviewStepComponent', () => { - let component: GlimPreviewStepComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [GlimPreviewStepComponent] - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(GlimPreviewStepComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-preview-step/glim-preview-step.component.ts b/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-preview-step/glim-preview-step.component.ts deleted file mode 100644 index 67d563d06..000000000 --- a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-preview-step/glim-preview-step.component.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Component, EventEmitter, Input, Output, OnChanges, SimpleChanges } from '@angular/core'; - -/** - * Create GLIM Account Preview Step - */ -@Component({ - selector: 'mifosx-glim-preview-step', - templateUrl: './glim-preview-step.component.html', - styleUrls: ['./glim-preview-step.component.scss'] -}) -export class GlimPreviewStepComponent implements OnChanges { - /** Loans Account Template */ - @Input() loansAccountTemplate: any = []; - /** Loans Account Product Template */ - @Input() loansAccountProductTemplate: any; - /** Loans Account Data */ - @Input() loansAccount: any; - /** Submit Loans Account */ - @Output() submitEvent = new EventEmitter(); - - /** Charges Displayed Columns */ - chargesDisplayedColumns: string[] = [ - 'name', - 'chargeCalculationType', - 'amount', - 'chargeTimeType', - 'date' - ]; - /** Overdue Charges Displayed Columns */ - overdueChargesDisplayedColumns: string[] = [ - 'name', - 'type', - 'amount', - 'collectedon' - ]; - - productEnableDownPayment = false; - - constructor() {} - - ngOnChanges(changes: SimpleChanges): void { - this.productEnableDownPayment = this.loansAccountProductTemplate.product.enableDownPayment; - } -} diff --git a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-terms-step/glim-terms-step.component.html b/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-terms-step/glim-terms-step.component.html deleted file mode 100644 index 0c107079b..000000000 --- a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-terms-step/glim-terms-step.component.html +++ /dev/null @@ -1,614 +0,0 @@ -
-
- - -

- {{ 'labels.heading.Term Options' | translate }} - -

- - - {{ 'labels.inputs.Loan Term' | translate }} - - - {{ 'labels.inputs.Loan Term' | translate }} {{ 'labels.commons.is' | translate }} - {{ 'labels.commons.required' | translate }} - - - - - {{ 'labels.inputs.Frequency' | translate }} - - - {{ type.value | translateKey: 'catalogs' }} - - - - {{ 'labels.inputs.Frequency' | translate }} {{ 'labels.commons.is' | translate }} - {{ 'labels.commons.required' | translate }} - - - - - {{ 'labels.inputs.Fixed Length' | translate }} - - - {{ - loansAccountTermsForm.value.loanTermFrequencyType | find: termFrequencyTypeData : 'id' : 'value' - }} - -

Repayments

- - - {{ 'labels.inputs.Number of repayments' | translate }} - - - {{ 'labels.inputs.Number of repayments' | translate }} {{ 'labels.commons.is' | translate }} - {{ 'labels.commons.required' | translate }} - - - - - {{ 'labels.inputs.First repayment on' | translate }} - - - - - - - {{ 'labels.inputs.Interest charged from' | translate }} - - - - - -

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

- - - {{ 'labels.inputs.Repaid every' | translate }} - - - {{ 'labels.inputs.Repaid every' | translate }} {{ 'labels.commons.is' | translate }} - {{ 'labels.commons.required' | translate }} - - - - - {{ 'labels.inputs.Frequency' | translate }} - - - {{ repaymentFrequencyType.value | translateKey: 'catalogs' }} - - - - - - {{ 'labels.inputs.Select On' | translate }} - - - {{ repaymentFrequencyNthDayType.value | translateKey: 'catalogs' }} - - - - - - {{ 'labels.inputs.Select Day' | translate }} - - - {{ repaymentFrequencyDayOfWeekType.value | translateKey: 'catalogs' }} - - - - - - {{ 'labels.inputs.Enable Down Payment' | translate }} - - -

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

- - - - {{ 'labels.inputs.Nominal interest rate' | translate }} % - - - - - {{ 'labels.inputs.Frequency' | translate }} - - - {{ interestRateFrequencyType.value | translateKey: 'catalogs' }} - - - - {{ 'labels.inputs.Nominal interest rate frequency' | translate }} {{ 'labels.commons.is' | translate }} - {{ 'labels.commons.required' | translate }} - - - - - {{ 'labels.inputs.Interest method' | translate }} - - - {{ interestType.value | translateKey: 'catalogs' }} - - - - - - {{ 'labels.inputs.Amortization' | translate }} - - - {{ amortizationType.value | translateKey: 'catalogs' }} - - - - {{ 'labels.inputs.Amortization Type' | translate }} {{ 'labels.commons.is' | translate }} - {{ 'labels.commons.required' | translate }} - - - - - {{ 'labels.inputs.Principal Percentage Per Installment' | translate }} - - - - -

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

-
-
- - -
- - {{ 'labels.inputs.Interest Method' | translate }} - - - {{ interestType.value | translateKey: 'catalogs' }} - - - - - - {{ 'labels.inputs.Amortization' | translate }} - - - {{ amortizationType.value | translateKey: 'catalogs' }} - - - - {{ '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 Type' | translate }}

-

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

-
- - - {{ 'labels.inputs.Repayment Strategy' | translate }} - - - {{ transactionProcessingStrategy.name | translateKey: 'catalogs' }} - - - - {{ 'labels.inputs.Repayment Strategy' | translate }} {{ 'labels.commons.is' | translate }} - {{ 'labels.commons.required' | translate }} - - - - - {{ 'labels.inputs.Installment Amount' | translate }} - - - - - {{ 'labels.inputs.Balloon Repayment Amount' | translate }} - - - -

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

- - - {{ 'labels.inputs.Interest calculation period' | translate }} - - - {{ interestCalculationPeriodType.value | translateKey: 'catalogs' }} - - - - - -

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

-
- - - -

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

-
-
- - - {{ 'labels.inputs.Arrears tolerance' | translate }} - - - - - {{ 'labels.inputs.Interest free period' | translate }} - - - - - -
-

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

-
- -
- -

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

-
-
- - - -

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

-
- - - {{ 'labels.inputs.Loan closed with Topup' | translate }} - - - {{ clientActiveLoan.accountNo }} - - - -
- - - -
- {{ 'labels.inputs.Recalculate Interest' | translate }} - {{ loansAccountTermsData?.isInterestRecalculationEnabled | yesNo }} -
- -
- {{ 'labels.inputs.Days in year' | translate }} - {{ loansAccountTermsData.daysInYearType.value | translateKey: 'catalogs' }} -
- - -
- {{ 'labels.inputs.Advance payments adjustment type' | translate }} - {{ loansAccountTermsData.interestRecalculationData.rescheduleStrategyType.value }} -
- -
- {{ 'labels.inputs.Days in month' | translate }} - {{ loansAccountTermsData.daysInMonthType.value | translateKey: 'catalogs' }} -
-
- - -
- {{ 'labels.inputs.Interest recalculation compounding on' | translate }} - {{ - loansAccountTermsData.interestRecalculationData.interestRecalculationCompoundingType.value - | translateKey: 'catalogs' - }} -
- -
- {{ 'labels.inputs.Frequency Interval for recalculation' | translate }} - - {{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyType.value }} - - on {{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyWeekday.value }} - on day {{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyOnDay }} - on - {{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyNthDay.value }} - {{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyWeekday.value }} - -
-
- -
- {{ 'labels.inputs.Frequency Interval for recalculation' | translate }} - {{ loansAccountTermsData.interestRecalculationData.recalculationRestFrequencyInterval }} -
- - - -
-

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

- - {{ 'labels.inputs.Maximum allowed outstanding balance' | translate }} - - - - - -
-
-

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

-
- - - - - - - - - - - - - - - - - - - -
{{ 'labels.inputs.Eexpected Disbursement Date' | translate }} - {{ row.expectedDisbursementDate | dateFormat }} - {{ 'labels.inputs.Principal' | translate }} - {{ row.principal }} - {{ 'labels.inputs.Actions' | translate }} - -
-
- - -
- {{ 'labels.inputs.Frequency for compounding' | translate }} - {{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyType.value }} - - on {{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyWeekday.value }} - - on day - {{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyOnDay }} - - on - {{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyNthDay.value }} - {{ loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyWeekday.value }} - - -
-
- -
- {{ 'labels.inputs.Frequency Interval for compounding' | translate }} - {{ - loansAccountTermsData.interestRecalculationData.recalculationCompoundingFrequencyInterval - }} -
-
- -
- - - -
-
diff --git a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-terms-step/glim-terms-step.component.scss b/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-terms-step/glim-terms-step.component.scss deleted file mode 100644 index b66af2377..000000000 --- a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-terms-step/glim-terms-step.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -.margin-t { - margin-top: 2em; -} diff --git a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-terms-step/glim-terms-step.component.spec.ts b/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-terms-step/glim-terms-step.component.spec.ts deleted file mode 100644 index be94e1cae..000000000 --- a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-terms-step/glim-terms-step.component.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { GlimTermsStepComponent } from './glim-terms-step.component'; - -describe('GlimTermsStepComponent', () => { - let component: GlimTermsStepComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [GlimTermsStepComponent] - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(GlimTermsStepComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-terms-step/glim-terms-step.component.ts b/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-terms-step/glim-terms-step.component.ts deleted file mode 100644 index 76c19446d..000000000 --- a/src/app/loans/glim-account/create-glim-account/glim-account-stepper/glim-terms-step/glim-terms-step.component.ts +++ /dev/null @@ -1,520 +0,0 @@ -/** Angular Imports */ -import { Component, Input, OnInit, OnChanges } from '@angular/core'; -import { UntypedFormGroup, UntypedFormBuilder, Validators, UntypedFormControl } from '@angular/forms'; -import { MatDialog } from '@angular/material/dialog'; -import { ActivatedRoute } from '@angular/router'; - -/** Custom Services */ -// import { LoansAccountAddCollateralDialogComponent } from 'app/loans/custom-dialog/loans-account-add-collateral-dialog/loans-account-add-collateral-dialog.component'; -import { LoanProducts } from 'app/products/loan-products/loan-products'; -import { LoanProduct } from 'app/products/loan-products/models/loan-product.model'; -import { SettingsService } from 'app/settings/settings.service'; -import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component'; -import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component'; -import { DatepickerBase } from 'app/shared/form-dialog/formfield/model/datepicker-base'; -import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base'; -import { InputBase } from 'app/shared/form-dialog/formfield/model/input-base'; -// import { Currency } from 'app/shared/models/general.model'; -import { CodeName, OptionData } from 'app/shared/models/option-data.model'; - -/** - * Create GLIM Terms Step - */ -@Component({ - selector: 'mifosx-glim-terms-step', - templateUrl: './glim-terms-step.component.html', - styleUrls: ['./glim-terms-step.component.scss'] -}) -export class GlimTermsStepComponent implements OnInit, OnChanges { - /** Loans Product Options */ - @Input() loansProductOptions: any; - /** Loans Account Product Template */ - @Input() loansAccountProductTemplate: any; - /** Loans Account Template */ - @Input() loansAccountTemplate: any; - loansAccountTermsData: any; - - /** Is Multi Disburse Loan */ - multiDisburseLoan: any; - // @Input() loansAccountFormValid: LoansAccountFormValid - @Input() loansAccountFormValid: boolean; - // @Input loanPrincipal: Loan Principle - @Input() loanPrincipal: any; - - /** Minimum date allowed. */ - minDate = new Date(2000, 0, 1); - /** Maximum date allowed. */ - maxDate = new Date(2100, 0, 1); - /** Loans Account Terms Form */ - loansAccountTermsForm: UntypedFormGroup; - /** Term Frequency Type Data */ - termFrequencyTypeData: any; - /** Repayment Frequency Nth Day Type Data */ - repaymentFrequencyNthDayTypeData: any; - /** Repayment Frequency Days of Week Type Data */ - repaymentFrequencyDaysOfWeekTypeData: any; - /** Interest Type Data */ - interestTypeData: any; - /** Amortization Type Data */ - amortizationTypeData: any; - /** Interest Calculation Period Type Data */ - interestCalculationPeriodTypeData: any; - /** Client Active Loan Data */ - clientActiveLoanData: any; - /** Multi Disbursement Data */ - disbursementDataSource: {}[] = []; - /** Loan repayment strategies */ - transactionProcessingStrategyOptions: any = []; - repaymentStrategyDisabled = false; - /** Disbursement Data Displayed Columns */ - disbursementDisplayedColumns: string[] = [ - 'expectedDisbursementDate', - 'principal', - 'actions' - ]; - /** Multi Disbursement Control */ - totalMultiDisbursed: any = 0; - isMultiDisbursedCompleted = false; - - /** Component is pristine if there has been no changes by user interaction */ - pristine = true; - - loanId: any = null; - loanScheduleType: OptionData | null = null; - loanProduct: LoanProduct | null = null; - interestRateFrequencyTypeData: any[] = []; - // currency: Currency; - - productEnableDownPayment = false; - isProgressive = false; - - /** - * Create Loans Account Terms Form - * @param formBuilder FormBuilder - * @param {SettingsService} settingsService SettingsService - * @param {ActivatedRoute} route ActivatedRoute - * @param {MatDialog} dialog MatDialog - */ - constructor( - private formBuilder: UntypedFormBuilder, - private settingsService: SettingsService, - private route: ActivatedRoute, - public dialog: MatDialog - ) { - this.loanId = this.route.snapshot.params['loanId']; - this.createGLIMTermsForm(); - } - /** - * Executes on change of input values - */ - ngOnChanges() { - if (this.loansAccountProductTemplate) { - // this.currency = this.loansAccountProductTemplate.currency; - - this.loansAccountTermsData = this.loansAccountProductTemplate; - if (this.loanId != null && this.loansAccountTemplate.accountNo) { - this.loansAccountTermsData = this.loansAccountTemplate; - } - this.productEnableDownPayment = this.loansAccountTermsData.product.enableDownPayment; - this.isProgressive = - this.loansAccountTermsData.loanScheduleType.code == LoanProducts.LOAN_SCHEDULE_TYPE_PROGRESSIVE; - if (this.loansAccountTermsData.product) { - this.loanProduct = this.loansAccountTermsData.product; - } - - this.interestRateFrequencyTypeData = this.loansAccountTermsData.interestRateFrequencyTypeOptions; - - this.loansAccountTermsForm.patchValue({ - principalAmount: this.loansAccountTermsData.principal, - loanTermFrequency: this.loansAccountTermsData.termFrequency, - loanTermFrequencyType: this.loansAccountTermsData.termPeriodFrequencyType.id, - numberOfRepayments: this.loansAccountTermsData.numberOfRepayments, - repaymentEvery: this.loansAccountTermsData.repaymentEvery, - repaymentFrequencyType: this.loansAccountTermsData.repaymentFrequencyType.id, - amortizationType: this.loansAccountTermsData.amortizationType.id, - isEqualAmortization: this.loansAccountTermsData.isEqualAmortization, - interestType: this.loansAccountTermsData.interestType.id, - isFloatingInterestRate: this.loansAccountTermsData.isLoanProductLinkedToFloatingRate ? false : '', - interestCalculationPeriodType: this.loansAccountTermsData.interestCalculationPeriodType.id, - allowPartialPeriodInterestCalculation: this.loansAccountTermsData.allowPartialPeriodInterestCalculation, - inArrearsTolerance: this.loansAccountTermsData.inArrearsTolerance, - graceOnInterestCharged: this.loansAccountTermsData.graceOnInterestCharged, - fixedEmiAmount: this.loansAccountTermsData.fixedEmiAmount, - maxOutstandingLoanBalance: this.loansAccountTermsData.maxOutstandingLoanBalance, - transactionProcessingStrategyCode: this.loansAccountTermsData.transactionProcessingStrategyCode, - interestRateDifferential: this.loansAccountTermsData.interestRateDifferential, - multiDisburseLoan: this.loansAccountTermsData.multiDisburseLoan, - interestRateFrequencyType: this.loansAccountTermsData.interestRateFrequencyType.id, - balloonRepaymentAmount: this.loansAccountTermsData.balloonRepaymentAmount, - interestRecognitionOnDisbursementDate: this.loansAccountTermsData.interestRecognitionOnDisbursementDate || false - }); - - this.setAdvancedPaymentStrategyControls(); - - if (this.loansAccountTermsData.loanScheduleType.code == LoanProducts.LOAN_SCHEDULE_TYPE_CUMULATIVE) { - this.loansAccountTermsForm.removeControl('interestRecognitionOnDisbursementDate'); - } - - if (this.loansAccountTermsData.isLoanProductLinkedToFloatingRate) { - this.loansAccountTermsForm.removeControl('interestRatePerPeriod'); - } - - this.multiDisburseLoan = this.loansAccountTermsData.multiDisburseLoan; - if (this.loansAccountTermsData.disbursementDetails) { - this.disbursementDataSource = this.loansAccountTermsData.disbursementDetails; - this.totalMultiDisbursed = 0; - this.disbursementDataSource.forEach((item: any) => { - this.totalMultiDisbursed += item.principal; - }); - } - if (this.isDelinquencyEnabled()) { - this.loansAccountTermsForm.addControl( - 'enableInstallmentLevelDelinquency', - new UntypedFormControl( - this.loansAccountTermsData.enableInstallmentLevelDelinquency || - this.loanProduct.enableInstallmentLevelDelinquency - ) - ); - } - if (this.productEnableDownPayment) { - const enableDownPayment = this.loansAccountTermsData['enableDownPayment'] === false ? false : true; - this.loansAccountTermsForm.addControl('enableDownPayment', new UntypedFormControl(enableDownPayment)); - } - - const allowAttributeOverrides = this.loansAccountTermsData.product.allowAttributeOverrides; - if (!allowAttributeOverrides.repaymentEvery) { - this.loansAccountTermsForm.controls.repaymentEvery.disable(); - this.loansAccountTermsForm.controls.repaymentFrequencyType.disable(); - } - if (!allowAttributeOverrides.interestType) { - this.loansAccountTermsForm.controls.interestType.disable(); - } - if (!allowAttributeOverrides.amortizationType) { - this.loansAccountTermsForm.controls.amortizationType.disable(); - } - if (!allowAttributeOverrides.interestCalculationPeriodType) { - this.loansAccountTermsForm.controls.interestCalculationPeriodType.disable(); - this.loansAccountTermsForm.controls.allowPartialPeriodInterestCalculation.disable(); - } - if (!allowAttributeOverrides.inArrearsTolerance) { - this.loansAccountTermsForm.controls.inArrearsTolerance.disable(); - } - if (!allowAttributeOverrides.transactionProcessingStrategyCode) { - this.loansAccountTermsForm.controls.transactionProcessingStrategyCode.disable(); - } - this.setOptions(); - } - } - - ngOnInit() { - this.maxDate = this.settingsService.maxFutureDate; - this.loansAccountTermsData = this.loansAccountProductTemplate; - if (this.loanId != null && this.loansAccountTemplate.accountNo) { - this.loansAccountTermsData = this.loansAccountTemplate; - } - - if (this.loansAccountTermsData) { - if (this.loansAccountTermsData.loanProductId) { - this.loansAccountTermsForm.patchValue({ - repaymentsStartingFromDate: - this.loansAccountTermsData.expectedFirstRepaymentOnDate && - new Date(this.loansAccountTermsData.expectedFirstRepaymentOnDate) - }); - } - this.loansAccountTermsForm.patchValue({ - principalAmount: this.loansAccountTermsData.principal, - loanTermFrequency: this.loansAccountTermsData.termFrequency, - loanTermFrequencyType: this.loansAccountTermsData.termPeriodFrequencyType.id, - numberOfRepayments: this.loansAccountTermsData.numberOfRepayments, - repaymentEvery: this.loansAccountTermsData.repaymentEvery, - repaymentFrequencyType: this.loansAccountTermsData.repaymentFrequencyType.id, - amortizationType: this.loansAccountTermsData.amortizationType.id, - isEqualAmortization: this.loansAccountTermsData.isEqualAmortization, - interestType: this.loansAccountTermsData.interestType.id, - isFloatingInterestRate: this.loansAccountTermsData.isLoanProductLinkedToFloatingRate ? false : '', - interestCalculationPeriodType: this.loansAccountTermsData.interestCalculationPeriodType.id, - allowPartialPeriodInterestCalculation: this.loansAccountTermsData.allowPartialPeriodInterestCalculation, - inArrearsTolerance: this.loansAccountTermsData.inArrearsTolerance, - graceOnInterestCharged: this.loansAccountTermsData.graceOnInterestCharged, - fixedEmiAmount: this.loansAccountTermsData.fixedEmiAmount, - maxOutstandingLoanBalance: this.loansAccountTermsData.maxOutstandingLoanBalance, - transactionProcessingStrategyCode: this.loansAccountTermsData.transactionProcessingStrategyCode, - interestRateDifferential: this.loansAccountTermsData.interestRateDifferential, - multiDisburseLoan: this.loansAccountTermsData.multiDisburseLoan, - interestRateFrequencyType: this.loansAccountTermsData.interestRateFrequencyType.id, - balloonRepaymentAmount: this.loansAccountTermsData.balloonRepaymentAmount, - interestRecognitionOnDisbursementDate: this.loansAccountTermsData.interestRecognitionOnDisbursementDate || false - }); - } - this.createGLIMTermsForm(); - this.setAdvancedPaymentStrategyControls(); - // this.setCustomValidators(); - this.setLoanTermListener(); - } - - allowAddDisbursementDetails() { - return this.multiDisburseLoan && !this.loansAccountTermsData.disallowExpectedDisbursements; - } - - /** Custom Validators for the form */ - // setCustomValidators() { - // const repaymentFrequencyNthDayType = this.loansAccountTermsForm.get('repaymentFrequencyNthDayType'); - // 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.updateValueAndValidity(); - // repaymentFrequencyDayOfWeekType.updateValueAndValidity(); - // }); - // } - - /** Custom Listeners for the form to calculate Loan Term */ - setLoanTermListener() { - this.loansAccountTermsForm.get('numberOfRepayments').valueChanges.subscribe((numberOfRepayments) => { - const repaymentEvery: number = this.loansAccountTermsForm.value.repaymentEvery; - this.calculateLoanTerm(numberOfRepayments, repaymentEvery); - }); - - this.loansAccountTermsForm.get('repaymentEvery').valueChanges.subscribe((repaymentEvery) => { - const numberOfRepayments: number = this.loansAccountTermsForm.value.numberOfRepayments; - this.calculateLoanTerm(numberOfRepayments, repaymentEvery); - }); - - this.loansAccountTermsForm.get('loanTermFrequencyType').valueChanges.subscribe((loanTermFrequencyType) => { - this.loansAccountTermsForm.patchValue({ repaymentFrequencyType: loanTermFrequencyType }); - }); - - this.loansAccountTermsForm.get('amortizationType').valueChanges.subscribe((amortizationType) => { - if (amortizationType === 0) { - // Equal Principal Payments - this.loansAccountTermsForm.addControl('fixedPrincipalPercentagePerInstallment', new UntypedFormControl('')); - } else { - // Equal Installments - this.loansAccountTermsForm.removeControl('fixedPrincipalPercentagePerInstallment'); - } - }); - } - - setAdvancedPaymentStrategyControls(): void { - // Fixed Length validation - if (this.loansAccountTermsData) { - this.loansAccountTermsForm.removeControl('interestRatePerPeriod'); - this.loansAccountTermsForm.removeControl('fixedLength'); - if (this.loansAccountTermsData.product.fixedLength) { - this.loansAccountTermsForm.addControl( - 'interestRatePerPeriod', - new UntypedFormControl({ value: 0, disabled: true }, Validators.required) - ); - this.loansAccountTermsForm.addControl( - 'fixedLength', - new UntypedFormControl(this.loansAccountTermsData.product.fixedLength) - ); - } else { - this.loansAccountTermsForm.addControl( - 'interestRatePerPeriod', - new UntypedFormControl(this.loansAccountTermsData.interestRatePerPeriod, Validators.required) - ); - } - } - } - - hasFixedLength(): boolean { - if (this.loansAccountTermsData) { - return this.loansAccountTermsData.product?.fixedLength ? true : false; - } - return false; - } - - isEqualPrincipalPayments(): boolean { - return this.loansAccountTermsForm.value.amortizationType === 0; - } - - /** Create Loans Account Terms Form */ - createGLIMTermsForm() { - 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: [''], - isEqualAmortization: [''], - amortizationType: [ - '', - Validators.required - ], - interestCalculationPeriodType: [''], - allowPartialPeriodInterestCalculation: [''], - inArrearsTolerance: [''], - graceOnInterestCharged: [''], - loanIdToClose: [''], - fixedEmiAmount: [''], - isTopup: [''], - maxOutstandingLoanBalance: [''], - interestRateDifferential: [''], - transactionProcessingStrategyCode: [ - '', - Validators.required - ], - multiDisburseLoan: [false], - interestRateFrequencyType: [''], - balloonRepaymentAmount: [''], - interestRecognitionOnDisbursementDate: [false] - }); - } - - calculateLoanTerm(numberOfRepayments: number, repaymentEvery: number): void { - const loanTerm = numberOfRepayments * repaymentEvery; - this.loansAccountTermsForm.patchValue({ loanTermFrequency: loanTerm }); - } - - /** - * Gets the Disbursement Data array. - * @returns {Array} Disbursement Data array. - */ - get disbursementData() { - return { - disbursementData: this.disbursementDataSource - }; - } - - /** - * Adds the Disbursement Data entry form to given Disbursement Data entry. - */ - addDisbursementDataEntry() { - const currentPrincipalAmount = this.loansAccountTermsForm.get('principalAmount').value; - const formfields: FormfieldBase[] = [ - new DatepickerBase({ - controlName: 'expectedDisbursementDate', - label: 'Expected Disbursement Date', - value: new Date() || '', - type: 'datetime-local', - minDate: this.minDate, - maxDate: this.maxDate, - required: true, - order: 1 - }), - new InputBase({ - controlName: 'principal', - label: `Principal(It should be less than equal to the ${currentPrincipalAmount})`, - value: '', - type: 'number', - required: true, - order: 2 - }) - - ]; - const data = { - title: 'Add Disbursement Details', - layout: { addButtonText: 'Add' }, - formfields: formfields - }; - const disbursementDialogRef = this.dialog.open(FormDialogComponent, { data }); - disbursementDialogRef.afterClosed().subscribe((response: any) => { - if (response.data) { - const principal = response.data.value.principal * 1; - if (this.totalMultiDisbursed + principal <= currentPrincipalAmount) { - this.disbursementDataSource = this.disbursementDataSource.concat(response.data.value); - this.totalMultiDisbursed += principal; - this.isMultiDisbursedCompleted = this.totalMultiDisbursed === currentPrincipalAmount; - this.pristine = false; - } - } - }); - } - - /** - * Removes the Disbursement Data entry form from given Disbursement Data entry form array at given index. - * @param {number} index Array index from where Disbursement Data entry form needs to be removed. - */ - removeDisbursementDataEntry(index: number) { - const currentPrincipalAmount = this.loansAccountTermsForm.get('principalAmount').value; - const dialogRef = this.dialog.open(DeleteDialogComponent, { - data: { deleteContext: `this` } - }); - dialogRef.afterClosed().subscribe((response: any) => { - if (response.delete) { - const principal = this.disbursementDataSource[index]['principal'] * 1; - this.disbursementDataSource.splice(index, 1); - this.disbursementDataSource = this.disbursementDataSource.concat([]); - this.totalMultiDisbursed -= principal; - this.isMultiDisbursedCompleted = this.totalMultiDisbursed === currentPrincipalAmount; - } - }); - } - - /** - * Sets all select dropdown options. - */ - setOptions() { - this.termFrequencyTypeData = this.loansAccountProductTemplate.termFrequencyTypeOptions; - this.repaymentFrequencyNthDayTypeData = this.loansAccountProductTemplate.repaymentFrequencyNthDayTypeOptions; - this.repaymentFrequencyDaysOfWeekTypeData = - this.loansAccountProductTemplate.repaymentFrequencyDaysOfWeekTypeOptions; - this.interestTypeData = this.loansAccountProductTemplate.interestTypeOptions; - this.amortizationTypeData = this.loansAccountProductTemplate.amortizationTypeOptions; - this.interestCalculationPeriodTypeData = this.loansAccountProductTemplate.interestCalculationPeriodTypeOptions; - this.clientActiveLoanData = this.loansAccountProductTemplate.clientActiveLoanOptions; - this.loanScheduleType = this.loansAccountProductTemplate.loanScheduleType; - this.transactionProcessingStrategyOptions = []; - if (this.loanScheduleType.code === LoanProducts.LOAN_SCHEDULE_TYPE_CUMULATIVE) { - // Filter Advanced Payment Allocation Strategy - this.transactionProcessingStrategyOptions = - this.loansAccountProductTemplate.transactionProcessingStrategyOptions.filter( - (cn: CodeName) => !LoanProducts.isAdvancedPaymentAllocationStrategy(cn.code) - ); - this.repaymentStrategyDisabled = false; - } else { - // Only Advanced Payment Allocation Strategy - this.loansAccountProductTemplate.transactionProcessingStrategyOptions.some((cn: CodeName) => { - if (LoanProducts.isAdvancedPaymentAllocationStrategy(cn.code)) { - this.transactionProcessingStrategyOptions.push(cn); - } - }); - this.repaymentStrategyDisabled = true; - } - } - - isDelinquencyEnabled(): boolean { - return !!this.loanProduct?.delinquencyBucket?.name; - } - - /** - * Returns loans account terms form value. - */ - get loansAccountTerms() { - return this.loansAccountTermsForm.getRawValue(); - } -} diff --git a/src/app/loans/loans-account-stepper/loans-account-charges-step/loans-account-charges-step.component.html b/src/app/loans/loans-account-stepper/loans-account-charges-step/loans-account-charges-step.component.html index 38f67ec3b..d4f5a545b 100644 --- a/src/app/loans/loans-account-stepper/loans-account-charges-step/loans-account-charges-step.component.html +++ b/src/app/loans/loans-account-stepper/loans-account-charges-step/loans-account-charges-step.component.html @@ -132,6 +132,60 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + {{ 'labels.inputs.Client ID' | translate }}{{ element.id }}{{ 'labels.inputs.Client Name' | translate }}{{ element.displayName }}{{ 'labels.inputs.Loan Purpose' | translate }} + + {{ 'labels.inputs.Select Purpose' | translate }} + + + {{ purpose.name }} + + + + {{ 'labels.inputs.Original Loan' | translate }} + + + +
+
diff --git a/src/app/loans/loans-account-stepper/loans-account-charges-step/loans-account-charges-step.component.ts b/src/app/loans/loans-account-stepper/loans-account-charges-step/loans-account-charges-step.component.ts index 2e84abdb4..5a0064bd4 100644 --- a/src/app/loans/loans-account-stepper/loans-account-charges-step/loans-account-charges-step.component.ts +++ b/src/app/loans/loans-account-stepper/loans-account-charges-step/loans-account-charges-step.component.ts @@ -1,12 +1,13 @@ /** Angular Imports */ import { Component, OnInit, Input, OnChanges } from '@angular/core'; -import { FormControl } from '@angular/forms'; +// import { FormControl } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; +import { MatTableDataSource } from '@angular/material/table'; /** Dialog Components */ import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component'; import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component'; -import { LoansAccountAddCollateralDialogComponent } from 'app/loans/custom-dialog/loans-account-add-collateral-dialog/loans-account-add-collateral-dialog.component'; +// import { LoansAccountAddCollateralDialogComponent } from 'app/loans/custom-dialog/loans-account-add-collateral-dialog/loans-account-add-collateral-dialog.component'; /** Custom Services */ import { DatepickerBase } from 'app/shared/form-dialog/formfield/model/datepicker-base'; @@ -31,6 +32,8 @@ export class LoansAccountChargesStepComponent implements OnInit, OnChanges { @Input() loansAccountTemplate: any; // @Input() loansAccountFormValid: LoansAccountFormValid @Input() loansAccountFormValid: boolean; + /** active Client Members in case of GSIM Account */ + @Input() activeClientMembers?: any; /** Charges Data */ chargeData: any; @@ -56,6 +59,20 @@ export class LoansAccountChargesStepComponent implements OnInit, OnChanges { 'amount', 'collectedon' ]; + /** Table Data Source */ + dataSource: any; + /** Check for select all the Clients List */ + selectAllItems = false; + /** Loan Purpose Options */ + loanPurposeOptions: string[] = []; + /** Table Displayed Columns */ + displayedColumn: string[] = [ + 'check', + 'id', + 'name', + 'purpose', + 'amount' + ]; /** Component is pristine if there has been no changes by user interaction */ pristine = true; /** Check if value of collateral added is more than principal amount */ @@ -84,6 +101,7 @@ export class LoansAccountChargesStepComponent implements OnInit, OnChanges { this.chargesDataSource = this.loansAccountTemplate.charges.map((charge: any) => ({ ...charge, id: charge.chargeId })) || []; } + this.dataSource = new MatTableDataSource(this.activeClientMembers); } /** @@ -91,6 +109,7 @@ export class LoansAccountChargesStepComponent implements OnInit, OnChanges { */ ngOnChanges() { if (this.loansAccountProductTemplate) { + this.loanPurposeOptions = this.loansAccountProductTemplate.loanPurposeOptions; this.chargeData = this.loansAccountProductTemplate.chargeOptions; if (this.loansAccountProductTemplate.overdueCharges) { this.overDueChargesDataSource = this.loansAccountProductTemplate.overdueCharges; @@ -236,6 +255,13 @@ export class LoansAccountChargesStepComponent implements OnInit, OnChanges { }); } + get isValid() { + return ( + !this.activeClientMembers || + this.selectedClientMembers?.selectedMembers?.reduce((acc: any, cur: any) => acc + (cur.principal ?? 0), 0) > 0 + ); + } + /** * Returns Loans Account Charges and Collateral Form */ @@ -244,4 +270,22 @@ export class LoansAccountChargesStepComponent implements OnInit, OnChanges { charges: this.chargesDataSource }; } + + get selectedClientMembers() { + return { selectedMembers: this.activeClientMembers.filter((item: any) => item.selected) }; + } + + /** Toggle all checks */ + toggleSelects() { + for (const member of this.activeClientMembers) { + member.selected = this.selectAllItems; + } + } + + /** Check if all the checks are selected */ + toggleSelect() { + const len = this.activeClientMembers.length; + this.selectAllItems = + len === 0 ? false : this.activeClientMembers.filter((item: any) => item.selected).length === len; + } } 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 e739de810..1dd2ffdda 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 @@ -42,6 +42,10 @@
+
+ +
+

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

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 2e23129de..b18ef9975 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 @@ -1,5 +1,6 @@ /** Angular Imports */ import { Component, Input, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core'; +import { MatTableDataSource } from '@angular/material/table'; /** * Create Loans Account Preview Step @@ -16,6 +17,9 @@ export class LoansAccountPreviewStepComponent implements OnChanges { @Input() loansAccountProductTemplate: any; /** Loans Account Data */ @Input() loansAccount: any; + /** active Client Members in case of GSIM Account */ + @Input() activeClientMembers?: any; + /** Submit Loans Account */ @Output() submitEvent = new EventEmitter(); @@ -35,11 +39,20 @@ export class LoansAccountPreviewStepComponent implements OnChanges { 'collectedon' ]; + /** Table Data Source */ + dataSource: any; productEnableDownPayment = false; constructor() {} ngOnChanges(changes: SimpleChanges): void { this.productEnableDownPayment = this.loansAccountProductTemplate.product.enableDownPayment; + if (this.activeClientMembers) { + this.dataSource = new MatTableDataSource(this.activeClientMembers); + this.loansAccount.principalAmount = this.activeClientMembers.reduce( + (acc: number, member: any) => acc + (member.principal ?? 0), + 0 + ); + } } } 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 1f97ca143..8f9f474dc 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 @@ -146,6 +146,7 @@ export class LoansAccountTermsStepComponent implements OnInit, OnChanges { amortizationType: this.loansAccountTermsData.amortizationType.id, isEqualAmortization: this.loansAccountTermsData.isEqualAmortization, interestType: this.loansAccountTermsData.interestType.id, + // TODO: 2025-03-17: Is this correct? isFloatingInterestRate: this.loansAccountTermsData.isLoanProductLinkedToFloatingRate ? false : '', interestCalculationPeriodType: this.loansAccountTermsData.interestCalculationPeriodType.id, allowPartialPeriodInterestCalculation: this.loansAccountTermsData.allowPartialPeriodInterestCalculation, diff --git a/src/app/loans/loans-routing.module.ts b/src/app/loans/loans-routing.module.ts index 0560ed8df..4e12b0570 100644 --- a/src/app/loans/loans-routing.module.ts +++ b/src/app/loans/loans-routing.module.ts @@ -351,7 +351,6 @@ const routes: Routes = [ component: CreateGlimAccountComponent, resolve: { loansAccountTemplate: GLIMLoanTemplateResolver, - gsimData: GSIMAccountsResolver, groupsData: GroupViewResolver } }, diff --git a/src/app/loans/loans.module.ts b/src/app/loans/loans.module.ts index 4cf4d0bbb..5b8d29c1c 100644 --- a/src/app/loans/loans.module.ts +++ b/src/app/loans/loans.module.ts @@ -58,10 +58,6 @@ import { ViewTransactionComponent } from './loans-view/transactions/view-transac import { EditTransactionComponent } from './loans-view/transactions/edit-transaction/edit-transaction.component'; import { GlimAccountComponent } from './glim-account/glim-account.component'; import { CreateGlimAccountComponent } from './glim-account/create-glim-account/create-glim-account.component'; -import { GlimDetailsStepComponent } from './glim-account/create-glim-account/glim-account-stepper/glim-details-step/glim-details-step.component'; -import { GlimChargesStepComponent } from './glim-account/create-glim-account/glim-account-stepper/glim-charges-step/glim-charges-step.component'; -import { GlimTermsStepComponent } from './glim-account/create-glim-account/glim-account-stepper/glim-terms-step/glim-terms-step.component'; -import { GlimPreviewStepComponent } from './glim-account/create-glim-account/glim-account-stepper/glim-preview-step/glim-preview-step.component'; /** Dialog Components */ import { LoansAccountViewGuarantorDetailsDialogComponent } from './custom-dialog/loans-account-view-guarantor-details-dialog/loans-account-view-guarantor-details-dialog.component'; @@ -152,10 +148,6 @@ import { AddInterestPauseComponent } from './loans-view/loan-account-actions/add LoanCreditBalanceRefundComponent, GlimAccountComponent, CreateGlimAccountComponent, - GlimDetailsStepComponent, - GlimChargesStepComponent, - GlimTermsStepComponent, - GlimPreviewStepComponent, LoanDelinquencyTagsTabComponent, LoansAccountScheduleStepComponent, EditRepaymentScheduleComponent, diff --git a/src/app/loans/loans.service.ts b/src/app/loans/loans.service.ts index 93c0c2ee4..f505b3486 100644 --- a/src/app/loans/loans.service.ts +++ b/src/app/loans/loans.service.ts @@ -619,7 +619,7 @@ export class LoansService { })); } - if (loansAccountTemplate.clientId && loansAccountTemplate.group.id) { + if (loansAccountTemplate.clientId && loansAccountTemplate.group?.id) { loansAccountData.clientId = loansAccountTemplate.clientId; loansAccountData.groupId = loansAccountTemplate.group.id; loansAccountData.loanType = 'glim';