diff --git a/src/app/core/http/api-prefix.interceptor.ts b/src/app/core/http/api-prefix.interceptor.ts index 5574075c1..86d33a13c 100644 --- a/src/app/core/http/api-prefix.interceptor.ts +++ b/src/app/core/http/api-prefix.interceptor.ts @@ -16,7 +16,7 @@ export class ApiPrefixInterceptor implements HttpInterceptor { /** * @param {SettingsService} settingsService Settings Service */ - constructor(private settingsService: SettingsService) {} + constructor(private settingsService: SettingsService) { } /** * Intercepts a Http request and prefixes it with `serverUrl`. @@ -25,7 +25,7 @@ export class ApiPrefixInterceptor implements HttpInterceptor { /** * Ignore URLs that are complete for i18n */ - if (!request.url.includes('http:') && !request.url.includes('https:')) { + if (!request.url.includes('http:') && !request.url.includes('https:')) { request = request.clone({ url: this.settingsService.serverUrl + request.url }); } diff --git a/src/app/loans/loans-view/loan-account-actions/edit-repayment-schedule/edit-repayment-schedule.component.html b/src/app/loans/loans-view/loan-account-actions/edit-repayment-schedule/edit-repayment-schedule.component.html index 455acf523..089e3848d 100644 --- a/src/app/loans/loans-view/loan-account-actions/edit-repayment-schedule/edit-repayment-schedule.component.html +++ b/src/app/loans/loans-view/loan-account-actions/edit-repayment-schedule/edit-repayment-schedule.component.html @@ -2,9 +2,20 @@ - + +
+ + +
+ + + + +
diff --git a/src/app/loans/loans-view/loan-account-actions/edit-repayment-schedule/edit-repayment-schedule.component.ts b/src/app/loans/loans-view/loan-account-actions/edit-repayment-schedule/edit-repayment-schedule.component.ts index 132d130e0..3070741ee 100644 --- a/src/app/loans/loans-view/loan-account-actions/edit-repayment-schedule/edit-repayment-schedule.component.ts +++ b/src/app/loans/loans-view/loan-account-actions/edit-repayment-schedule/edit-repayment-schedule.component.ts @@ -1,4 +1,15 @@ import { Component, OnInit } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; +import { ActivatedRoute, Router } from '@angular/router'; +import { Dates } from 'app/core/utils/dates'; +import { LoansService } from 'app/loans/loans.service'; +import { SettingsService } from 'app/settings/settings.service'; +import { ConfirmationDialogComponent } from 'app/shared/confirmation-dialog/confirmation-dialog.component'; +import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component'; +import { 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 { SelectBase } from 'app/shared/form-dialog/formfield/model/select-base'; @Component({ selector: 'mifosx-edit-repayment-schedule', @@ -7,9 +18,149 @@ import { Component, OnInit } from '@angular/core'; }) export class EditRepaymentScheduleComponent implements OnInit { - constructor() { } + /** Loan ID. */ + loanId: string; + /** Indicates If the Schedule has been changed */ + wasChanged = false; + /** Indicates If the Schedule has been validated */ + wasValidated = false; + /** Stores the Repayment Schedule data */ + repaymentScheduleDetails: any[] = []; + /** Stores the Installments changed */ + repaymentScheduleChanges: any = {}; + + /** + * @param {LoansService} systemService Loan Service. + * @param {Router} router Router for navigation. + * @param {ActivatedRoute} route Activated Route. + * @param {MatDialog} dialog Confirmation Dialogs. + * @param {Dates} dateUtils Dates Utils. + * @param {SettingsService} settingsService Settings Service + */ + constructor(private loansService: LoansService, + private router: Router, + private route: ActivatedRoute, + private dialog: MatDialog, + private dateUtils: Dates, + private settingsService: SettingsService) { + this.loanId = this.route.parent.snapshot.params['loanId']; + this.getRepaymentSchedule(); + } ngOnInit(): void { + this.repaymentScheduleChanges = {}; + } + + getRepaymentSchedule(): void { + this.loansService.getLoanAccountResource(this.loanId, 'repaymentSchedule').subscribe((response: any) => { + this.repaymentScheduleDetails = response.repaymentSchedule; + }); + } + + applyPattern(): void { + const periods: any = []; + this.repaymentScheduleDetails['periods'].forEach((period: any) => { + if (period.period) { + periods.push({idx: period.period, dueDate: this.dateUtils.formatDate(period.dueDate, this.settingsService.dateFormat) }); + } + }); + const formfields: FormfieldBase[] = [ + new SelectBase({ + controlName: 'fromPeriod', + label: 'From Date', + value: '', + options: { label: 'dueDate', value: 'idx', data: periods }, + required: true + }), + new SelectBase({ + controlName: 'toPeriod', + label: 'To Date', + value: '', + options: { label: 'dueDate', value: 'idx', data: periods }, + required: true + }), + new InputBase({ + controlName: 'amount', + label: 'Installment Amount', + value: '', + type: 'number', + required: true + }), + ]; + const data = { + title: 'Pattern Update', + formfields: formfields + }; + const addDialogRef = this.dialog.open(FormDialogComponent, { data }); + addDialogRef.afterClosed().subscribe((response: any) => { + if (response.data) { + const fromPeriod = response.data.value.fromPeriod; + const toPeriod = response.data.value.toPeriod; + const amount = response.data.value.amount; + const periodsVariation: any = []; + this.repaymentScheduleDetails['periods'].forEach((period: any) => { + const dueDate = this.dateUtils.formatDate(period.dueDate, this.settingsService.dateFormat); + if (period.period && fromPeriod <= period.period && toPeriod >= period.period) { + if (period.totalDueForPeriod !== amount) { + period.totalDueForPeriod = amount; + this.repaymentScheduleChanges[dueDate] = {dueDate: dueDate, installmentAmount: amount}; + this.wasChanged = true; + period['changed'] = true; + } + } + periodsVariation.push(period); + }); + this.repaymentScheduleDetails['periods'] = periodsVariation; + } + }); + } + + reset(): void { + const recoverScheduleDialogRef = this.dialog.open(ConfirmationDialogComponent, { + data: { heading: 'Recover Original Schedule', dialogContext: 'Are you sure you want recover the Original Schedule'} + }); + recoverScheduleDialogRef.afterClosed().subscribe((responseConfirmation: any) => { + if (responseConfirmation.confirm) { + this.loansService.applyCommandLoanScheduleVariations(this.loanId, 'deleteVariations', {}).subscribe((response: any) => { + this.getRepaymentSchedule(); + this.wasChanged = false; + this.wasValidated = false; + }); + } + }); + } + + validate(): void { + this.loansService.applyCommandLoanScheduleVariations(this.loanId, 'calculateLoanSchedule', this.getPayload()).subscribe((response: any) => { + this.repaymentScheduleDetails['periods'] = []; + response['periods'].forEach((period: any) => { + period['changed'] = true; + this.repaymentScheduleDetails['periods'].push(period); + this.wasValidated = true; + }); + }); + } + + submit(): void { + this.loansService.applyCommandLoanScheduleVariations(this.loanId, 'addVariations', this.getPayload()).subscribe((response: any) => { + this.router.navigate(['../../repayment-schedule'], { relativeTo: this.route }); + }); + } + + private getPayload(): any { + const modifiedinstallments: any = []; + Object.keys(this.repaymentScheduleChanges).forEach((key: string) => { + modifiedinstallments.push(this.repaymentScheduleChanges[key]); + }); + const dateFormat = this.settingsService.dateFormat; + const locale = this.settingsService.language.code; + return { + exceptions: { + modifiedinstallments + }, + dateFormat, + locale + }; } } diff --git a/src/app/loans/loans-view/loan-account-actions/loan-account-actions.component.ts b/src/app/loans/loans-view/loan-account-actions/loan-account-actions.component.ts index 5bcb7d48a..0f6c80cc0 100644 --- a/src/app/loans/loans-view/loan-account-actions/loan-account-actions.component.ts +++ b/src/app/loans/loans-view/loan-account-actions/loan-account-actions.component.ts @@ -39,7 +39,8 @@ export class LoanAccountActionsComponent { 'Goodwill Credit': boolean, 'Merchant Issued Refund': boolean, 'Payout Refund': boolean, - 'Credit Balance Refund': boolean + 'Credit Balance Refund': boolean, + 'Edit Repayment Schedule': boolean } = { 'Close': false, 'Undo Approval': false, @@ -67,7 +68,8 @@ export class LoanAccountActionsComponent { 'Goodwill Credit': false, 'Merchant Issued Refund': false, 'Payout Refund': false, - 'Credit Balance Refund': false + 'Credit Balance Refund': false, + 'Edit Repayment Schedule': false }; actionButtonData: any; diff --git a/src/app/loans/loans-view/loan-account-actions/undo-disbursal/undo-disbursal.component.html b/src/app/loans/loans-view/loan-account-actions/undo-disbursal/undo-disbursal.component.html index 3ab1693c7..fc2b5f306 100644 --- a/src/app/loans/loans-view/loan-account-actions/undo-disbursal/undo-disbursal.component.html +++ b/src/app/loans/loans-view/loan-account-actions/undo-disbursal/undo-disbursal.component.html @@ -4,10 +4,14 @@ - - Note - - +
+ + + Note + + + +
diff --git a/src/app/loans/loans-view/loan-account-actions/undo-disbursal/undo-disbursal.component.ts b/src/app/loans/loans-view/loan-account-actions/undo-disbursal/undo-disbursal.component.ts index 2b71f3324..d075d0741 100644 --- a/src/app/loans/loans-view/loan-account-actions/undo-disbursal/undo-disbursal.component.ts +++ b/src/app/loans/loans-view/loan-account-actions/undo-disbursal/undo-disbursal.component.ts @@ -1,6 +1,6 @@ /** Angular Imports */ import { Component, Input, OnInit } from '@angular/core'; -import { FormControl, FormBuilder } from '@angular/forms'; +import { FormControl, FormBuilder, Validators } from '@angular/forms'; import { Router, ActivatedRoute } from '@angular/router'; /** Custom Services */ @@ -40,7 +40,7 @@ export class UndoDisbursalComponent implements OnInit { * Creates the undo disbursal form. */ ngOnInit() { - this.note = this.formBuilder.control(''); + this.note = this.formBuilder.control('', Validators.required); } /** diff --git a/src/app/loans/loans-view/loans-view.component.ts b/src/app/loans/loans-view/loans-view.component.ts index 2b80c77cd..ff69831a3 100644 --- a/src/app/loans/loans-view/loans-view.component.ts +++ b/src/app/loans/loans-view/loans-view.component.ts @@ -53,15 +53,16 @@ export class LoansViewComponent implements OnInit { ngOnInit() { this.recalculateInterest = this.loanDetailsData.recalculateInterest || true; this.status = this.loanDetailsData.status.value; - this.setConditionalButtons(); - - if (this.loanDetailsData.multiDisburseLoan) { - this.loanDetailsData.transactions.forEach((tranaction: any) => { - if (tranaction.type.disbursement) { - this.disburseTransactionNo++; - } - }); + if (this.loanDetailsData.status.active && this.loanDetailsData.multiDisburseLoan) { + if (this.loanDetailsData) { + this.loanDetailsData.transactions.forEach((transaction: any) => { + if (transaction.type.disbursement) { + this.disburseTransactionNo++; + } + }); + } } + this.setConditionalButtons(); if (this.router.url.includes('clients')) { this.entityType = 'Client'; } else if (this.router.url.includes('groups')) { diff --git a/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.html b/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.html index 2d9d77d89..6045af15a 100644 --- a/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.html +++ b/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.html @@ -1,6 +1,6 @@
- +
@@ -16,7 +16,7 @@ - + @@ -29,7 +29,7 @@ @@ -133,6 +133,76 @@
# Date {{ ele.dueDate | dateFormat}} {{ ele.dueDate | dateFormat}}   - +
-
+ +
- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
# {{ ele.period }}   Date {{ ele.dueDate | dateFormat}} Balance Of Loan {{ ele.principalLoanBalanceOutstanding | number }}   Principal Due {{ ele.principalDue | number }} {{ repaymentScheduleDetails.totalPrincipalExpected | currency }} Interest {{ ele.interestOriginalDue | number}} {{ repaymentScheduleDetails.totalInterestCharged | currency }} Fees {{ ele.feeChargesDue | number}} {{ repaymentScheduleDetails.totalFeeChargesCharged | currency }} Installment Amount + + {{ ele.totalDueForPeriod | number}} + + + {{ ele.totalDueForPeriod | number}} + + {{ repaymentScheduleDetails.totalRepaymentExpected | currency }} Actions + +
+ +
+ + diff --git a/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.scss b/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.scss index e38332f65..90858405f 100644 --- a/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.scss +++ b/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.scss @@ -1,3 +1,6 @@ +@import "assets/styles/helper"; +@import "assets/styles/helper"; + table { width: 100%; margin: 3% 0%; @@ -10,3 +13,7 @@ table { .check { padding-left: 15px; } + +.amount-changed { + color: $status-approved; +} diff --git a/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.ts b/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.ts index 98bc4fa82..be393fe71 100644 --- a/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.ts +++ b/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; @Component({ @@ -8,6 +8,8 @@ import { ActivatedRoute } from '@angular/router'; }) export class RepaymentScheduleTabComponent implements OnInit { + /** Loan Repayment Schedule to be Edited */ + @Input() forEditing = false; /** Loan Repayment Schedule Details Data */ @Input() repaymentScheduleDetails: any = null; loanDetailsDataRepaymentSchedule: any = []; @@ -16,6 +18,11 @@ export class RepaymentScheduleTabComponent implements OnInit { isWaived: boolean; /** Columns to be displayed in original schedule table. */ displayedColumns: string[] = ['number', 'days', 'date', 'paiddate', 'check', 'balanceOfLoan', 'principalDue', 'interest', 'fees', 'penalties', 'due', 'paid', 'inadvance', 'late', 'waived', 'outstanding']; + /** Columns to be displayed in editable schedule table. */ + displayedColumnsEdit: string[] = ['number', 'date', 'balanceOfLoan', 'principalDue', 'interest', 'fees', 'due']; + + /** Form functions event */ + @Output() editPeriod = new EventEmitter(); /** * Retrieves the loans with associations data from `resolve`. diff --git a/src/app/loans/loans.service.ts b/src/app/loans/loans.service.ts index 265d8df85..ef813d93c 100644 --- a/src/app/loans/loans.service.ts +++ b/src/app/loans/loans.service.ts @@ -401,7 +401,7 @@ export class LoansService { } /** - * @param {string} accountId Loans Account Id + * @param {string} accountId Loans Account Id * @param {any} data Charge Data * @param {any} chargeId Charge Id * @returns {Observable} @@ -411,7 +411,7 @@ export class LoansService { } /** - * @param {string} accountId Loans Account Id + * @param {string} accountId Loans Account Id * @param {any} chargeId Charge Id * @returns {Observable} */ @@ -419,6 +419,15 @@ export class LoansService { return this.http.delete(`/loans/${accountId}/charges/${chargeId}`); } + /** + * @param {string} loanId Loans Account Id + * @param {string} command Schedule command + * @returns {Observable} + */ + applyCommandLoanScheduleVariations(loanId: string, command: string, payload: any): Observable { + return this.http.post(`/loans/${loanId}/schedule?command=${command}`, payload); + } + /** * @param {string} accountId Loans Account Id * @param {string} transactionId Transaction Id diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.html b/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.html index c86ffafc6..52a697691 100644 --- a/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.html +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.html @@ -74,7 +74,7 @@ Delinquency Bucket - + {{ delinquencyBucket.name }} @@ -162,7 +162,10 @@ Maximum gap between Installments - + + + Maximum gap between Installments is required + diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.ts b/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.ts index 33883d145..971d4b39d 100644 --- a/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.ts +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.ts @@ -174,7 +174,7 @@ export class LoanProductSettingsStepComponent implements OnInit { 'graceOnPrincipalAndInterestPayment': [true], 'graceOnArrearsAgeing': [true] }), - 'delinquencyBucketId': [''] + 'delinquencyBucketId': ['', Validators.required] }); } @@ -194,7 +194,7 @@ export class LoanProductSettingsStepComponent implements OnInit { .subscribe((allowVariableInstallments: any) => { if (allowVariableInstallments) { this.loanProductSettingsForm.addControl('minimumGap', new FormControl('', Validators.required)); - this.loanProductSettingsForm.addControl('maximumGap', new FormControl('')); + this.loanProductSettingsForm.addControl('maximumGap', new FormControl('', Validators.required)); } else { this.loanProductSettingsForm.removeControl('minimumGap'); this.loanProductSettingsForm.removeControl('maximumGap'); diff --git a/src/app/savings/saving-account-actions/manage-savings-account/manage-savings-account.component.ts b/src/app/savings/saving-account-actions/manage-savings-account/manage-savings-account.component.ts index 2b5e00c56..440560a5f 100644 --- a/src/app/savings/saving-account-actions/manage-savings-account/manage-savings-account.component.ts +++ b/src/app/savings/saving-account-actions/manage-savings-account/manage-savings-account.component.ts @@ -124,10 +124,8 @@ export class ManageSavingsAccountComponent implements OnInit { } else { payload = { ... this.manageSavingsAccountForm.value - } - if (this.transactionType.blockaccount) { - command = 'block'; - } + }; + command = 'block'; this.savingsService.executeSavingsAccountCommand(this.savingAccountId, command, payload).subscribe((response: any) => { this.router.navigate(['../../transactions'], { relativeTo: this.route }); diff --git a/src/app/shared/footer/footer.component.html b/src/app/shared/footer/footer.component.html index 70ea445f5..025affead 100644 --- a/src/app/shared/footer/footer.component.html +++ b/src/app/shared/footer/footer.component.html @@ -1,7 +1,11 @@ diff --git a/src/app/shared/footer/footer.component.ts b/src/app/shared/footer/footer.component.ts index 4888d0a98..906c2e000 100644 --- a/src/app/shared/footer/footer.component.ts +++ b/src/app/shared/footer/footer.component.ts @@ -25,6 +25,7 @@ export class FooterComponent implements OnInit, OnDestroy { version: string = environment.version; /** Mifos X hash */ hash: string = environment.hash; + server = ''; /** Business Date */ businessDate: Date = null; @@ -58,6 +59,7 @@ export class FooterComponent implements OnInit, OnDestroy { } }); this.getConfigurations(); + this.server = this.settingsService.server; } ngOnDestroy() { diff --git a/src/app/system/manage-data-tables/edit-data-table/edit-data-table.component.html b/src/app/system/manage-data-tables/edit-data-table/edit-data-table.component.html index 881fbd1ca..064ebac9a 100644 --- a/src/app/system/manage-data-tables/edit-data-table/edit-data-table.component.html +++ b/src/app/system/manage-data-tables/edit-data-table/edit-data-table.component.html @@ -74,17 +74,17 @@ Mandatory - - + - Unique - + Indexed - + ; /** Paginator for columns table. */ @@ -204,8 +204,8 @@ export class EditDataTableComponent implements OnInit { this.dataForDialog.columnName = column.columnName; this.dataForDialog.columnDisplayType = column.columnDisplayType; this.dataForDialog.isColumnNullable = !column.isColumnNullable; - this.dataForDialog.isColumnUnique = !column.isColumnUnique; - this.dataForDialog.isColumnIndexed = !column.isColumnIndexed; + this.dataForDialog.isColumnUnique = column.isColumnUnique; + this.dataForDialog.isColumnIndexed = column.isColumnIndexed; this.dataForDialog.columnLength = column.columnLength; this.dataForDialog.columnCode = column.columnCode; this.dataForDialog.type = column.type; diff --git a/src/app/system/manage-data-tables/view-data-table/view-data-table.component.html b/src/app/system/manage-data-tables/view-data-table/view-data-table.component.html index d2b0d5cce..26b15e766 100644 --- a/src/app/system/manage-data-tables/view-data-table/view-data-table.component.html +++ b/src/app/system/manage-data-tables/view-data-table/view-data-table.component.html @@ -60,7 +60,7 @@ Mandatory - + Unique - + Indexed - +