WEB-257: Loan Capitalized Income - Fetch amortization details

This commit is contained in:
Jose Alberto Hernandez
2025-07-21 11:04:16 +02:00
committed by Adam Saghy
parent 704c61d37f
commit e55aaf90be
21 changed files with 213 additions and 1 deletions
@@ -0,0 +1,29 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
import { Observable } from 'rxjs';
/** Custom Services */
import { LoansService } from '../loans.service';
/**
* Loan Delinquency data resolver.
*/
@Injectable()
export class LoanDeferredIncomeDataResolver {
/**
* @param {LoansService} LoansService Loans service.
*/
constructor(private loansService: LoansService) {}
/**
* Returns the Loans with Association data.
* @returns {Observable<any>}
*/
resolve(route: ActivatedRouteSnapshot): Observable<any> {
const loanId = route.paramMap.get('loanId') || route.parent.paramMap.get('loanId');
return this.loansService.getDeferredIncomeData(loanId);
}
}
+17 -1
View File
@@ -62,6 +62,8 @@ import { LoanDelinquencyDataResolver } from './common-resolvers/loan-delinquency
import { LoanDelinquencyActionsResolver } from './common-resolvers/loan-delinquency-actions.resolver';
import { LoanTermVariationsTabComponent } from './loans-view/loan-term-variations-tab/loan-term-variations-tab.component';
import { LoanTermVariationsResolver } from './common-resolvers/loan-term-variations.resolver';
import { LoanDeferredIncomeTabComponent } from './loans-view/loan-deferred-income-tab/loan-deferred-income-tab.component';
import { LoanDeferredIncomeDataResolver } from './common-resolvers/loan-deferred-income-data.resolver';
/** Loans Route. */
const routes: Routes = [
@@ -130,6 +132,19 @@ const routes: Routes = [
}
]
},
{
path: 'deferred-income',
data: { title: 'Loans Deferred Income', breadcrumb: 'Deferred income', routeParamBreadcrumb: false },
resolve: {
loanDeferredIncomeData: LoanDeferredIncomeDataResolver
},
children: [
{
path: '',
component: LoanDeferredIncomeTabComponent
}
]
},
{
path: 'delinquencytags',
data: { title: 'Loans Delinquency Tags', breadcrumb: 'Delinquency Tags', routeParamBreadcrumb: false },
@@ -391,7 +406,8 @@ const routes: Routes = [
GLIMLoanTemplateResolver,
ExternalAssetOwnerResolver,
LoanDelinquencyDataResolver,
LoanTermVariationsResolver
LoanTermVariationsResolver,
LoanDeferredIncomeDataResolver
]
})
export class LoansRoutingModule {}
@@ -0,0 +1,36 @@
<div class="container">
<h3>{{ 'labels.inputs.Deferred income' | translate }} - {{ 'labels.menus.Capitalized Income' | translate }}</h3>
<table mat-table [dataSource]="capitalizedIncomeData" *ngIf="capitalizedIncomeData.length > 0">
<ng-container matColumnDef="amount">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Amount' | translate }}</th>
<td mat-cell *matCellDef="let item">
{{ item.amount | formatNumber }}
</td>
</ng-container>
<ng-container matColumnDef="amortizedAmount">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Amortized Amount' | translate }}</th>
<td mat-cell *matCellDef="let item">
{{ item.amortizedAmount | formatNumber: '0.00' }}
</td>
</ng-container>
<ng-container matColumnDef="unrecognizedAmount">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Unrecognized Amount' | translate }}</th>
<td mat-cell *matCellDef="let item">
{{ item.unrecognizedAmount | formatNumber: '0.00' }}
</td>
</ng-container>
<ng-container matColumnDef="amountAdjustment">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Adjustment Amount' | translate }}</th>
<td mat-cell *matCellDef="let item">
{{ item.amountAdjustment | formatNumber: '0.00' }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="capitalizedIncomeColumns"></tr>
<tr mat-row *matRowDef="let row; columns: capitalizedIncomeColumns"></tr>
</table>
</div>
@@ -0,0 +1,66 @@
import { NgClass } from '@angular/common';
import { Component } from '@angular/core';
import {
MatCell,
MatCellDef,
MatColumnDef,
MatHeaderCell,
MatHeaderCellDef,
MatHeaderRow,
MatHeaderRowDef,
MatRow,
MatRowDef,
MatTable
} from '@angular/material/table';
import { ActivatedRoute } from '@angular/router';
import { FormatNumberPipe } from '@pipes/format-number.pipe';
import { LoanCapitalizedIncomeData, LoanDeferredIncomeData } from 'app/loans/models/loan-account.model';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
@Component({
selector: 'mifosx-loan-deferred-income-tab',
templateUrl: './loan-deferred-income-tab.component.html',
styleUrl: './loan-deferred-income-tab.component.scss',
imports: [
...STANDALONE_SHARED_IMPORTS,
MatTable,
MatColumnDef,
MatHeaderCellDef,
MatHeaderCell,
MatCellDef,
MatCell,
MatHeaderRowDef,
MatHeaderRow,
MatRowDef,
MatRow,
FormatNumberPipe
]
})
export class LoanDeferredIncomeTabComponent {
capitalizedIncomeData: LoanCapitalizedIncomeData[] = [];
loanId: any;
capitalizedIncomeColumns: string[] = [
'amount',
'amortizedAmount',
'unrecognizedAmount',
'amountAdjustment'
];
constructor(private route: ActivatedRoute) {
this.loanId = this.route.parent.parent.snapshot.params['loanId'];
let capitalizedIncomeData: LoanCapitalizedIncomeData[] = [];
this.route.parent.data.subscribe((data: { loanDeferredIncomeData: LoanDeferredIncomeData }) => {
capitalizedIncomeData = data.loanDeferredIncomeData.capitalizedIncomeData || [];
capitalizedIncomeData.forEach((item: LoanCapitalizedIncomeData) => {
item.amortizedAmount = item.amortizedAmount | 0;
item.unrecognizedAmount = item.unrecognizedAmount | 0;
item.amountAdjustment = item.amountAdjustment | 0;
this.capitalizedIncomeData.push(item);
});
console.log(this.capitalizedIncomeData);
});
}
}
@@ -208,6 +208,17 @@
{{ 'labels.inputs.Transactions' | translate }}
</a>
</ng-container>
<ng-container *ngIf="loanDetailsData.enableIncomeCapitalization">
<a
mat-tab-link
[routerLink]="['./deferred-income']"
routerLinkActive
#deferredIncome="routerLinkActive"
[active]="deferredIncome.isActive"
>
{{ 'labels.inputs.Deferred income' | translate }}
</a>
</ng-container>
<ng-container *ngIf="loanDetailsData.status.active">
<a
mat-tab-link
+4
View File
@@ -100,6 +100,10 @@ export class LoansService {
return this.http.post(`/loans/${loanId}/delinquency-actions`, delinquencyActions);
}
getDeferredIncomeData(loanId: string) {
return this.http.get(`/loans/${loanId}/deferredincome`);
}
/**
* Returns the loan template data with specific condition
* @param loanId Loan Id
@@ -122,3 +122,14 @@ export interface DisbursementData {
principal: number;
id?: number;
}
export interface LoanDeferredIncomeData {
capitalizedIncomeData: LoanCapitalizedIncomeData[];
}
export interface LoanCapitalizedIncomeData {
amount: number;
amortizedAmount?: number;
unrecognizedAmount?: number;
amountAdjustment?: number;
}