/** * 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/. */ import { Component, ViewChild, inject } from '@angular/core'; import { ActivatedRoute, Router } 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'; import { LoansAccountChargesStepComponent } from '../loans-account-stepper/loans-account-charges-step/loans-account-charges-step.component'; /** Custom Services */ import { SettingsService } from 'app/settings/settings.service'; import { Dates } from 'app/core/utils/dates'; import { MatStepper, MatStepperIcon, MatStep, MatStepLabel } from '@angular/material/stepper'; 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'; /** * Edit Loans */ @Component({ selector: 'mifosx-edit-loans-account', templateUrl: './edit-loans-account.component.html', styleUrls: ['./edit-loans-account.component.scss'], imports: [ ...STANDALONE_SHARED_IMPORTS, MatStepper, MatStepperIcon, FaIconComponent, MatStep, MatStepLabel, LoansAccountDetailsStepComponent, LoansAccountTermsStepComponent, LoansAccountChargesStepComponent, LoansAccountScheduleStepComponent, LoansAccountPreviewStepComponent ] }) export class EditLoansAccountComponent { private route = inject(ActivatedRoute); private router = inject(Router); private dateUtils = inject(Dates); private loansService = inject(LoansService); private settingsService = inject(SettingsService); @ViewChild(LoansAccountDetailsStepComponent, { static: true }) loansAccountDetailsStep: LoansAccountDetailsStepComponent; @ViewChild(LoansAccountTermsStepComponent, { static: true }) loansAccountTermsStep: LoansAccountTermsStepComponent; @ViewChild(LoansAccountChargesStepComponent, { static: true }) loansAccountChargesStep: LoansAccountChargesStepComponent; loansAccountAndTemplate: any; /** Loans Account Product Template */ loansAccountProductTemplate: any; /** Collateral Options */ collateralOptions: any; /** Loan Id */ loanId: any; /** 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 */ constructor() { this.route.data.subscribe((data: { loansAccountAndTemplate: any }) => { this.loansAccountAndTemplate = data.loansAccountAndTemplate; }); this.loanId = this.route.snapshot.params['loanId']; } /** * 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; if (this.loansAccountProductTemplate.loanProductId) { this.loansService .getLoansCollateralTemplateResource(this.loansAccountProductTemplate.loanProductId) .subscribe((response: any) => { this.collateralOptions = response.loanCollateralOptions; }); } } /** Get Loans Account Details Form Data */ get loansAccountDetailsForm() { return this.loansAccountDetailsStep.loansAccountDetailsForm; } /** Get Loans Account Terms Form Data */ get loansAccountTermsForm() { return this.loansAccountTermsStep.loansAccountTermsForm; } /** 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) ); } /** 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 }; } /** * Submits Data to create loan account */ submit() { const locale = this.settingsService.language.code; const dateFormat = this.settingsService.dateFormat; const loanType = 'individual'; const uniqueCharges = new Map(); (this.loansAccount.charges ?? []).forEach((charge: any) => { const chargeId = charge.chargeId; if (chargeId == null) { return; } // Skip malformed entries uniqueCharges.set(chargeId, charge); }); const loansAccountData = { ...this.loansAccount, clientId: this.loansAccountAndTemplate.clientId, charges: Array.from(uniqueCharges.values()).map((charge: any) => { const result: any = { chargeId: charge.chargeId, amount: charge.amount, dueDate: charge.dueDate && this.dateUtils.formatDate(charge.dueDate, dateFormat) }; if (charge.id && charge.id !== charge.chargeId) { result.id = charge.id; } return result; }), collateral: this.loansAccount.collateral.map((collateralEle: any) => ({ type: collateralEle.type, value: collateralEle.value, description: collateralEle.description })), disbursementData: this.loansAccount.disbursementData.map((item: any) => ({ expectedDisbursementDate: this.dateUtils.formatDate(item.expectedDisbursementDate, dateFormat), principal: item.principal })), interestChargedFromDate: this.dateUtils.formatDate(this.loansAccount.interestChargedFromDate, dateFormat), repaymentsStartingFromDate: this.dateUtils.formatDate(this.loansAccount.repaymentsStartingFromDate, dateFormat), submittedOnDate: this.dateUtils.formatDate(this.loansAccount.submittedOnDate, dateFormat), expectedDisbursementDate: this.dateUtils.formatDate(this.loansAccount.expectedDisbursementDate, dateFormat), dateFormat, locale, loanType }; delete loansAccountData.isValid; if (loansAccountData.syncRepaymentsWithMeeting) { loansAccountData.calendarId = this.loansAccountProductTemplate.calendarOptions[0].id; delete loansAccountData.syncRepaymentsWithMeeting; } if (loansAccountData.recalculationRestFrequencyDate) { loansAccountData.recalculationRestFrequencyDate = this.dateUtils.formatDate( this.loansAccount.recalculationRestFrequencyDate, dateFormat ); } if (loansAccountData.interestCalculationPeriodType === 0) { loansAccountData.allowPartialPeriodInterestCalculation = false; } if ( !loansAccountData.isLoanProductLinkedToFloatingRate || loansAccountData.isLoanProductLinkedToFloatingRate === false ) { delete loansAccountData.isFloatingInterestRate; } loansAccountData.principal = loansAccountData.principalAmount; delete loansAccountData.principalAmount; delete loansAccountData.multiDisburseLoan; // In Fineract, the POST and PUT endpoints for /v1/loans have a typo in the field // allowPartialPeriodInterestCalculation. Until that is fixed, we need to replace the field name in the payload. loansAccountData.allowPartialPeriodInterestCalculation = loansAccountData.allowPartialPeriodInterestCalculation; delete loansAccountData.allowPartialPeriodInterestCalculation; this.loansService.updateLoansAccount(this.loanId, loansAccountData).subscribe((response: any) => { this.router.navigate(['../'], { relativeTo: this.route }); }); } }