Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/app/core/alert/alert.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@
export interface Alert {
type: string;
message: string;
enabled?: boolean;
}
14 changes: 14 additions & 0 deletions src/app/core/utils/dates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,20 @@ export class Dates {
}
}

public isBefore(date1: Date, date2: Date): boolean {
return (
Date.UTC(date1.getFullYear(), date1.getMonth(), date1.getDate()) <
Date.UTC(date2.getFullYear(), date2.getMonth(), date2.getDate())
);
}

public isAfter(date1: Date, date2: Date): boolean {
return (
Date.UTC(date1.getFullYear(), date1.getMonth(), date1.getDate()) >
Date.UTC(date2.getFullYear(), date2.getMonth(), date2.getDate())
);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

public parseDatetime(value: any): Date {
return moment(value).toDate();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export class LoanDelinquencyActionsResolver extends LoanBaseResolver {
resolve(route: ActivatedRouteSnapshot): Observable<any> {
this.initialize(route);
const loanId = route.paramMap.get('loanId') || route.parent.paramMap.get('loanId');
return this.loansService.getDelinquencyActions(this.loanAccountPath, loanId);
if (!isNaN(+loanId)) {
return this.loansService.getDelinquencyActions(this.loanAccountPath, loanId);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export class LoanDelinquencyDataResolver extends LoanBaseResolver {
constructor() {
super();
}

/**
* Returns the Loans with Association data.
* @returns {Observable<any>}
Expand All @@ -36,9 +35,9 @@ export class LoanDelinquencyDataResolver extends LoanBaseResolver {
this.initialize(route);
const loanId = route.paramMap.get('loanId') || route.parent.paramMap.get('loanId');
if (!isNaN(+loanId)) {
if (this.isLoanProduct) {
return this.loansService.getDelinquencyData(loanId);
}
return this.isLoanProduct
? this.loansService.getDelinquencyData(loanId)
: this.loansService.getWorkingCapitalLoanDetails(loanId);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ export class LoanDelinquencyTagsResolver extends LoanBaseResolver {
this.initialize(route);
const loanId = route.paramMap.get('loanId') || route.parent.paramMap.get('loanId');
if (!isNaN(+loanId)) {
return this.loansService.getDelinquencyTags(this.loanAccountPath, loanId);
if (this.isLoanProduct) {
return this.loansService.getDelinquencyTags(loanId);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* 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 { Injectable, inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { LoanBaseResolver } from '../loan-base.resolver';
import { LoansService } from 'app/loans/loans.service';

@Injectable({
providedIn: 'root'
})
export class LoanDelinquencyRangeScheduleResolver extends LoanBaseResolver {
private loansService = inject(LoansService);

constructor() {
super();
}

/**
* Returns the Loans with Association data.
* @returns {Observable<any>}
*/
resolve(route: ActivatedRouteSnapshot): Observable<any> {
this.initialize(route);
const loanId = route.paramMap.get('loanId') || route.parent.paramMap.get('loanId');
if (!isNaN(+loanId)) {
if (this.isWorkingCapital) {
return this.loansService.getWorkingCapitalLoanDelinquencyRangeSchedule(loanId);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,46 +8,48 @@

<h2 mat-dialog-title>{{ 'labels.heading.Loan Delinquency Actions' | translate }}</h2>

<div mat-dialog-content [formGroup]="delinquencyActionForm" class="layout-column">
<mat-form-field class="flex-48" (click)="validFromDatePicker.open()">
<mat-label>{{ 'labels.inputs.Start Date' | translate }}</mat-label>
<input
matInput
[min]="minDate"
[max]="maxDate"
[matDatepicker]="validFromDatePicker"
required
formControlName="startDate"
/>
<mat-datepicker-toggle matSuffix [for]="validFromDatePicker"></mat-datepicker-toggle>
<mat-datepicker #validFromDatePicker></mat-datepicker>
@if (delinquencyActionForm.controls.startDate.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Start Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<div mat-dialog-content [formGroup]="delinquencyActionForm">
<div class="layout-column">
<mat-form-field class="flex-48" (click)="validFromDatePicker.open()">
<mat-label>{{ 'labels.inputs.Start Date' | translate }}</mat-label>
<input
matInput
[min]="minDate"
[max]="maxDate"
[matDatepicker]="validFromDatePicker"
required
formControlName="startDate"
/>
<mat-datepicker-toggle matSuffix [for]="validFromDatePicker"></mat-datepicker-toggle>
<mat-datepicker #validFromDatePicker></mat-datepicker>
@if (delinquencyActionForm.controls.startDate.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Start Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>

<mat-form-field class="flex-48" (click)="validTillDatePicker.open()">
<mat-label>{{ 'labels.inputs.End Date' | translate }}</mat-label>
<input
matInput
[min]="delinquencyActionForm.value.startDate"
[max]="maxDate"
[matDatepicker]="validTillDatePicker"
required
formControlName="endDate"
/>
<mat-datepicker-toggle matSuffix [for]="validTillDatePicker"></mat-datepicker-toggle>
<mat-datepicker #validTillDatePicker></mat-datepicker>
@if (delinquencyActionForm.controls.endDate.hasError('required')) {
<mat-error>
{{ 'labels.inputs.End Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
<mat-form-field class="flex-48" (click)="validTillDatePicker.open()">
<mat-label>{{ 'labels.inputs.End Date' | translate }}</mat-label>
<input
matInput
[min]="delinquencyActionForm.value.startDate"
[max]="maxDate"
[matDatepicker]="validTillDatePicker"
required
formControlName="endDate"
/>
<mat-datepicker-toggle matSuffix [for]="validTillDatePicker"></mat-datepicker-toggle>
<mat-datepicker #validTillDatePicker></mat-datepicker>
@if (delinquencyActionForm.controls.endDate.hasError('required')) {
<mat-error>
{{ 'labels.inputs.End Date' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
</mat-form-field>
</div>
</div>

<mat-dialog-actions class="layout-row layout-xs-column layout-align-center gap-2percent">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<!--
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/.
-->

<h2 mat-dialog-title>{{ 'labels.heading.Loan Delinquency Actions' | translate }}</h2>

<div mat-dialog-content [formGroup]="delinquencyActionForm">
<div class="layout-column">
<mat-form-field class="flex-98">
<mat-label>{{ 'labels.inputs.Minimum Payment' | translate }}</mat-label>
<input type="number" matInput formControlName="minimumPayment" />
</mat-form-field>

<mat-form-field class="flex-98">
<mat-label>{{ 'labels.inputs.Minimum Payment Type' | translate }}</mat-label>
<mat-select formControlName="minimumPaymentType">
@for (minimumPaymentType of minimumPaymentTypeOptions; track minimumPaymentType) {
<mat-option [value]="minimumPaymentType.id">
{{ minimumPaymentType.value | translateKey: 'catalogs' }}
</mat-option>
}
</mat-select>
</mat-form-field>

<mat-form-field class="flex-98">
<mat-label>{{ 'labels.inputs.Period Payment Frequency' | translate }}</mat-label>
<input
type="number"
matInput
formControlName="frequency"
matTooltip="{{ 'tooltips.Fields are input to calculating the repayment schedule' | translate }}"
/>
</mat-form-field>

<mat-form-field class="flex-98">
<mat-label>{{ 'labels.inputs.Period Payment Frequency Type' | translate }}</mat-label>
<mat-select formControlName="frequencyType">
@for (frequencyType of frequencyTypeOptions; track frequencyType) {
<mat-option [value]="frequencyType.id">
{{ frequencyType.value | translateKey: 'catalogs' }}
</mat-option>
}
</mat-select>
</mat-form-field>
</div>
</div>

<mat-dialog-actions class="layout-row layout-xs-column layout-align-center gap-2percent">
<button mat-raised-button mat-dialog-close>{{ 'labels.buttons.Cancel' | translate }}</button>
<button
mat-raised-button
color="primary"
[mat-dialog-close]="{ data: delinquencyActionForm }"
[disabled]="!delinquencyActionForm.valid || delinquencyActionForm.pristine"
>
{{ 'labels.buttons.Reschedule' | translate }}
</button>
</mat-dialog-actions>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* 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/.
*/
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* 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, inject } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
import {
MAT_DIALOG_DATA,
MatDialogRef,
MatDialogTitle,
MatDialogContent,
MatDialogActions,
MatDialogClose
} from '@angular/material/dialog';
import { CdkScrollable } from '@angular/cdk/scrolling';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
import { MatTooltip } from '@angular/material/tooltip';
import { StringEnumOptionData } from 'app/shared/models/option-data.model';

@Component({
selector: 'mifosx-loan-delinquency-action-reschedule-dialog',
templateUrl: './loan-delinquency-action-reschedule-dialog.component.html',
styleUrl: './loan-delinquency-action-reschedule-dialog.component.scss',
imports: [
...STANDALONE_SHARED_IMPORTS,
MatDialogTitle,
CdkScrollable,
MatDialogContent,
MatDialogActions,
MatDialogClose,
MatTooltip
]
})
export class LoanDelinquencyActionRescheduleDialogComponent {
dialogRef = inject<MatDialogRef<LoanDelinquencyActionRescheduleDialogComponent>>(MatDialogRef);
data = inject(MAT_DIALOG_DATA);
private formBuilder = inject(UntypedFormBuilder);

delinquencyActionForm: UntypedFormGroup;

frequencyTypeOptions: StringEnumOptionData[] = [];
minimumPaymentTypeOptions: StringEnumOptionData[] = [];

constructor() {
this.createDelinquencyActionForm();
this.frequencyTypeOptions = this.data.frequencyTypeOptions;
this.minimumPaymentTypeOptions = this.data.minimumPaymentTypeOptions;
}

createDelinquencyActionForm() {
this.delinquencyActionForm = this.formBuilder.group({
minimumPayment: [
''
],
minimumPaymentType: [
''
],
frequency: [
''
],
frequencyType: [
''
]
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ <h4 class="mat-h4 flex-98">
/>
@if (loansAccountTermsForm.controls.repaymentEvery.hasError('required')) {
<mat-error>
{{ 'labels.inputs.Repaid every' | translate }} {{ 'labels.commons.is' | translate }}
{{ 'labels.inputs.Period Payment Frequency' | translate }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
}
Expand Down
4 changes: 3 additions & 1 deletion src/app/loans/loans-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ import { LoanBuyDownFeesDataResolver } from './common-resolvers/loan-buy-down-fe
import { LoanOriginatorsTabComponent } from './loans-view/loan-originators-tab/loan-originators-tab.component';
import { LoanOriginatorsResolver } from './common-resolvers/loan-originators.resolver';
import { LoanProductsResolver } from './common-resolvers/loan-products.resolver';
import { LoanDelinquencyRangeScheduleResolver } from './common-resolvers/working-capital/loan-delinquency-actions.resolver';

/** Loans Route. */
const routes: Routes = [
Expand Down Expand Up @@ -168,7 +169,8 @@ const routes: Routes = [
resolve: {
loanDelinquencyTagsData: LoanDelinquencyTagsResolver,
loanDelinquencyData: LoanDelinquencyDataResolver,
loanDelinquencyActions: LoanDelinquencyActionsResolver
loanDelinquencyActions: LoanDelinquencyActionsResolver,
wcLoanDelinquencyRangeSchedule: LoanDelinquencyRangeScheduleResolver
},
children: [
{
Expand Down
Loading
Loading