Skip to content

Commit 0d785cc

Browse files
WEB-657: Loan view and Repayment for Working Capital
1 parent 92b9984 commit 0d785cc

41 files changed

Lines changed: 1746 additions & 1126 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/app/loans/common-resolvers/loan-action-button.resolver.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ export class LoanActionButtonResolver {
3838
if (loanActionButton === 'Assign Loan Officer' || loanActionButton === 'Change Loan Officer') {
3939
return this.loansService.getLoanTemplate(loanId);
4040
} else if (loanActionButton === 'Make Repayment') {
41-
return this.loansService.getLoanActionTemplate(loanId, 'repayment');
41+
return this.loanProductService.isLoanProduct
42+
? this.loansService.getLoanActionTemplate(loanId, 'repayment')
43+
: this.loansService.getWorkingCapitalLoanActionTemplate(loanId, 'repayment');
4244
} else if (loanActionButton === 'Goodwill Credit') {
4345
return this.loansService.getLoanActionTemplate(loanId, 'goodwillCredit');
4446
} else if (loanActionButton === 'Interest Payment Waiver') {

src/app/loans/common-resolvers/loans-account-transaction.resolver.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,30 @@ import { Observable } from 'rxjs';
1515

1616
/** Custom Services */
1717
import { LoansService } from '../loans.service';
18+
import { LoanBaseResolver } from './loan-base.resolver';
1819

1920
/**
2021
* Loans Account Transaction data resolver.
2122
*/
2223
@Injectable()
23-
export class LoansAccountTransactionResolver {
24+
export class LoansAccountTransactionResolver extends LoanBaseResolver {
2425
private loansService = inject(LoansService);
2526

27+
constructor() {
28+
super();
29+
}
30+
2631
/**
2732
* Returns the Loans Account Transaction data.
2833
* @param {ActivatedRouteSnapshot} route Route Snapshot
2934
* @returns {Observable<any>}
3035
*/
3136
resolve(route: ActivatedRouteSnapshot): Observable<any> {
37+
this.initialize(route);
3238
const loanId = route.paramMap.get('loanId');
3339
const transactionId = route.paramMap.get('id');
34-
return this.loansService.getLoansAccountTransaction(loanId, transactionId);
40+
if (!isNaN(+loanId) && !isNaN(+transactionId)) {
41+
return this.loansService.getLoansAccountTransaction(this.loanAccountPath, loanId, transactionId);
42+
}
3543
}
3644
}

src/app/loans/loans-view/general-tab/general-tab.component.html

Lines changed: 28 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -13,80 +13,41 @@ <h3>{{ 'labels.heading.Performance History' | translate }}</h3>
1313
<table>
1414
<tbody>
1515
<tr>
16-
<td class="flex-25">
17-
<b>{{ 'labels.inputs.Number of Repayments' | translate }} :</b>
18-
</td>
19-
<td class="flex-25 left">
20-
{{ loanDetails?.numberOfRepayments | formatNumber }}
21-
</td>
22-
<td class="flex-25">
23-
<b>{{ 'labels.inputs.Maturity Date' | translate }} :</b>
24-
</td>
25-
<td class="flex-25 left">
26-
{{ loanDetails?.timeline.expectedMaturityDate | dateFormat }}
27-
</td>
16+
@if (loanProductService.isLoanProduct) {
17+
<td class="flex-25">
18+
<b>{{ 'labels.inputs.Number of Repayments' | translate }} :</b>
19+
</td>
20+
<td class="flex-25 left">
21+
{{ loanDetails?.numberOfRepayments | formatNumber }}
22+
</td>
23+
<td class="flex-25">
24+
<b>{{ 'labels.inputs.Maturity Date' | translate }} :</b>
25+
</td>
26+
<td class="flex-25 left">
27+
{{ loanDetails?.timeline.expectedMaturityDate | dateFormat }}
28+
</td>
29+
}
30+
@if (loanProductService.isWorkingCapital) {
31+
<td class="flex-25">
32+
<b>{{ 'labels.inputs.Number of Repayments' | translate }} :</b>
33+
</td>
34+
<td class="flex-25 left">
35+
{{ loanDetails?.totalNoPayments | formatNumber }}
36+
</td>
37+
}
2838
</tr>
2939
</tbody>
3040
</table>
3141
</div>
3242
}
3343

3444
@if (loanDetails.summary) {
35-
<div>
36-
<h3>{{ 'labels.heading.Loan Summary' | translate }}</h3>
37-
<table mat-table [dataSource]="dataSource">
38-
<ng-container matColumnDef="Empty">
39-
<th mat-header-cell *matHeaderCellDef></th>
40-
<td mat-cell *matCellDef="let ele">{{ 'labels.inputs.' + ele.property | translate }}</td>
41-
</ng-container>
42-
<ng-container matColumnDef="Original">
43-
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Original' | translate }}</th>
44-
<td mat-cell class="r-amount" *matCellDef="let ele">
45-
{{ ele.original | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
46-
</td>
47-
</ng-container>
48-
<ng-container matColumnDef="Paid">
49-
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Paid' | translate }}</th>
50-
<td mat-cell class="r-amount amount-minus" *matCellDef="let ele">
51-
{{ ele.paid | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
52-
</td>
53-
</ng-container>
54-
<ng-container matColumnDef="Adjustments">
55-
<th mat-header-cell class="r-amount" *matHeaderCellDef>
56-
{{ 'labels.inputs.Credit Adjustments' | translate }}
57-
</th>
58-
<td mat-cell class="r-amount amount-plus" *matCellDef="let ele">
59-
{{ ele.adjustment | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
60-
</td>
61-
</ng-container>
62-
<ng-container matColumnDef="Waived">
63-
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Waived' | translate }}</th>
64-
<td mat-cell class="r-amount amount-minus" *matCellDef="let ele">
65-
{{ ele.waived | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
66-
</td>
67-
</ng-container>
68-
<ng-container matColumnDef="Written Off">
69-
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Written Off' | translate }}</th>
70-
<td mat-cell class="r-amount amount-minus" *matCellDef="let ele">
71-
{{ ele.writtenOff | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
72-
</td>
73-
</ng-container>
74-
<ng-container matColumnDef="Outstanding">
75-
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Outstanding' | translate }}</th>
76-
<td mat-cell class="r-amount" *matCellDef="let ele">
77-
{{ ele.outstanding | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
78-
</td>
79-
</ng-container>
80-
<ng-container matColumnDef="Over Due">
81-
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Over Due' | translate }}</th>
82-
<td mat-cell class="r-amount" *matCellDef="let ele">
83-
{{ ele.overdue | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
84-
</td>
85-
</ng-container>
86-
<tr mat-header-row *matHeaderRowDef="loanSummaryColumns"></tr>
87-
<tr mat-row *matRowDef="let row; columns: loanSummaryColumns"></tr>
88-
</table>
89-
</div>
45+
<mifosx-loan-summary-balance-component
46+
[summary]="loanDetails.summary"
47+
[currency]="loanDetails.currency"
48+
[hasChargeBack]="hasChargeBack"
49+
>
50+
</mifosx-loan-summary-balance-component>
9051

9152
<div>
9253
<h3>{{ 'labels.heading.Loan Details' | translate }}</h3>

src/app/loans/loans-view/general-tab/general-tab.component.ts

Lines changed: 9 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,8 @@ import {
1212
MatTableDataSource,
1313
MatTable,
1414
MatColumnDef,
15-
MatHeaderCellDef,
16-
MatHeaderCell,
1715
MatCellDef,
1816
MatCell,
19-
MatHeaderRowDef,
20-
MatHeaderRow,
2117
MatRowDef,
2218
MatRow
2319
} from '@angular/material/table';
@@ -28,6 +24,7 @@ import { FormatNumberPipe } from '../../../pipes/format-number.pipe';
2824
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
2925
import { LoanProductService } from 'app/products/loan-products/services/loan-product.service';
3026
import { LoanProductBaseComponent } from 'app/products/loan-products/common/loan-product-base.component';
27+
import { LoanSummaryBalanceComponentComponent } from './loan-summary-balance-component/loan-summary-balance-component.component';
3128

3229
@Component({
3330
selector: 'mifosx-general-tab',
@@ -37,58 +34,34 @@ import { LoanProductBaseComponent } from 'app/products/loan-products/common/loan
3734
...STANDALONE_SHARED_IMPORTS,
3835
MatTable,
3936
MatColumnDef,
40-
MatHeaderCellDef,
41-
MatHeaderCell,
4237
MatCellDef,
4338
MatCell,
44-
MatHeaderRowDef,
45-
MatHeaderRow,
4639
MatRowDef,
4740
MatRow,
4841
ExternalIdentifierComponent,
4942
CurrencyPipe,
5043
DateFormatPipe,
51-
FormatNumberPipe
44+
FormatNumberPipe,
45+
LoanSummaryBalanceComponentComponent
5246
],
5347
changeDetection: ChangeDetectionStrategy.OnPush
5448
})
5549
export class GeneralTabComponent extends LoanProductBaseComponent implements OnInit {
5650
private route = inject(ActivatedRoute);
5751

5852
/** Currency Code */
59-
currencyCode: string;
53+
currencyCode: string | null = null;
6054
loanDetails: any;
6155
status: any;
62-
loanSummaryColumns: string[] = [
63-
'Empty',
64-
'Original',
65-
'Paid',
66-
'Waived',
67-
'Written Off',
68-
'Outstanding',
69-
'Over Due'
70-
];
56+
7157
loanDetailsColumns: string[] = [
7258
'Key',
7359
'Value'
7460
];
75-
loanSummaryTableData: {
76-
property: string;
77-
original: number;
78-
adjustment: number;
79-
paid: number;
80-
waived: number;
81-
writtenOff: number;
82-
outstanding: number;
83-
overdue: number;
84-
}[];
85-
loanDetailsTableData: {
86-
key: string;
87-
value?: string;
88-
}[];
61+
loanDetailsTableData: { key: string; value?: string }[] = [];
62+
hasChargeBack: boolean = false;
8963

90-
/** Data source for loans summary table. */
91-
dataSource: MatTableDataSource<any>;
64+
/** Data source for loans details table. */
9265
detailsDataSource: MatTableDataSource<any>;
9366

9467
constructor() {
@@ -103,16 +76,7 @@ export class GeneralTabComponent extends LoanProductBaseComponent implements OnI
10376
if (this.loanDetails.transactions) {
10477
this.loanDetails.transactions.some((transaction: any) => {
10578
if (transaction.type.code === 'loanTransactionType.chargeback') {
106-
this.loanSummaryColumns = [
107-
'Empty',
108-
'Original',
109-
'Adjustments',
110-
'Paid',
111-
'Waived',
112-
'Written Off',
113-
'Outstanding',
114-
'Over Due'
115-
];
79+
this.hasChargeBack = true;
11680
return;
11781
}
11882
});
@@ -123,69 +87,12 @@ export class GeneralTabComponent extends LoanProductBaseComponent implements OnI
12387
ngOnInit() {
12488
this.status = this.loanDetails.value;
12589
if (this.loanDetails.summary) {
126-
this.setloanSummaryTableData();
12790
this.setloanDetailsTableData();
12891
} else {
12992
this.setloanNonDetailsTableData();
13093
}
13194
}
13295

133-
setloanSummaryTableData() {
134-
this.loanSummaryTableData = [
135-
{
136-
property: 'Principal',
137-
original: this.loanDetails.summary.totalPrincipal,
138-
adjustment: this.loanDetails.summary.principalAdjustments || 0,
139-
paid: this.loanDetails.summary.principalPaid,
140-
waived: this.loanDetails.summary.principalWaived || 0,
141-
writtenOff: this.loanDetails.summary.principalWrittenOff,
142-
outstanding: this.loanDetails.summary.principalOutstanding,
143-
overdue: this.loanDetails.summary.principalOverdue
144-
},
145-
{
146-
property: 'Interest',
147-
original: this.loanDetails.summary.interestCharged,
148-
adjustment: 0,
149-
paid: this.loanDetails.summary.interestPaid,
150-
waived: this.loanDetails.summary.interestWaived,
151-
writtenOff: this.loanDetails.summary.interestWrittenOff,
152-
outstanding: this.loanDetails.summary.interestOutstanding,
153-
overdue: this.loanDetails.summary.interestOverdue
154-
},
155-
{
156-
property: 'Fees',
157-
original: this.loanDetails.summary.feeChargesCharged,
158-
adjustment: 0,
159-
paid: this.loanDetails.summary.feeChargesPaid,
160-
waived: this.loanDetails.summary.feeChargesWaived,
161-
writtenOff: this.loanDetails.summary.feeChargesWrittenOff,
162-
outstanding: this.loanDetails.summary.feeChargesOutstanding,
163-
overdue: this.loanDetails.summary.feeChargesOverdue
164-
},
165-
{
166-
property: 'Penalties',
167-
original: this.loanDetails.summary.penaltyChargesCharged,
168-
adjustment: 0,
169-
paid: this.loanDetails.summary.penaltyChargesPaid,
170-
waived: this.loanDetails.summary.penaltyChargesWaived,
171-
writtenOff: this.loanDetails.summary.penaltyChargesWrittenOff,
172-
outstanding: this.loanDetails.summary.penaltyChargesOutstanding,
173-
overdue: this.loanDetails.summary.penaltyChargesOverdue
174-
},
175-
{
176-
property: 'Total',
177-
original: this.loanDetails.summary.totalExpectedRepayment,
178-
adjustment: this.loanDetails.summary.principalAdjustments || 0,
179-
paid: this.loanDetails.summary.totalRepayment,
180-
waived: this.loanDetails.summary.totalWaived,
181-
writtenOff: this.loanDetails.summary.totalWrittenOff,
182-
outstanding: this.loanDetails.summary.totalOutstanding,
183-
overdue: this.loanDetails.summary.totalOverdue
184-
}
185-
];
186-
this.dataSource = new MatTableDataSource(this.loanSummaryTableData);
187-
}
188-
18996
setloanDetailsTableData() {
19097
this.loanDetailsTableData = [
19198
{
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<!--
2+
Copyright since 2025 Mifos Initiative
3+
4+
This Source Code Form is subject to the terms of the Mozilla Public
5+
License, v. 2.0. If a copy of the MPL was not distributed with this
6+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
7+
-->
8+
9+
<div class="tab-container mat-typography">
10+
@if (summary) {
11+
<div>
12+
<h3>{{ 'labels.heading.Loan Summary' | translate }}</h3>
13+
<table mat-table [dataSource]="dataSource">
14+
<ng-container matColumnDef="Empty">
15+
<th mat-header-cell *matHeaderCellDef></th>
16+
<td mat-cell *matCellDef="let ele">{{ 'labels.inputs.' + ele.property | translate }}</td>
17+
</ng-container>
18+
<ng-container matColumnDef="Original">
19+
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Original' | translate }}</th>
20+
<td mat-cell class="r-amount" *matCellDef="let ele">
21+
{{ ele.original | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
22+
</td>
23+
</ng-container>
24+
<ng-container matColumnDef="Paid">
25+
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Paid' | translate }}</th>
26+
<td mat-cell class="r-amount amount-minus" *matCellDef="let ele">
27+
{{ ele.paid | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
28+
</td>
29+
</ng-container>
30+
<ng-container matColumnDef="Adjustments">
31+
<th mat-header-cell class="r-amount" *matHeaderCellDef>
32+
{{ 'labels.inputs.Credit Adjustments' | translate }}
33+
</th>
34+
<td mat-cell class="r-amount amount-plus" *matCellDef="let ele">
35+
{{ ele.adjustment | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
36+
</td>
37+
</ng-container>
38+
<ng-container matColumnDef="Waived">
39+
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Waived' | translate }}</th>
40+
<td mat-cell class="r-amount amount-minus" *matCellDef="let ele">
41+
{{ ele.waived | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
42+
</td>
43+
</ng-container>
44+
<ng-container matColumnDef="Written Off">
45+
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Written Off' | translate }}</th>
46+
<td mat-cell class="r-amount amount-minus" *matCellDef="let ele">
47+
{{ ele.writtenOff | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
48+
</td>
49+
</ng-container>
50+
<ng-container matColumnDef="Outstanding">
51+
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Outstanding' | translate }}</th>
52+
<td mat-cell class="r-amount" *matCellDef="let ele">
53+
{{ ele.outstanding | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
54+
</td>
55+
</ng-container>
56+
<ng-container matColumnDef="Over Due">
57+
<th mat-header-cell class="r-amount" *matHeaderCellDef>{{ 'labels.inputs.Over Due' | translate }}</th>
58+
<td mat-cell class="r-amount" *matCellDef="let ele">
59+
{{ ele.overdue | currency: currencyCode : 'symbol-narrow' : '1.2-2' }}
60+
</td>
61+
</ng-container>
62+
<tr mat-header-row *matHeaderRowDef="loanSummaryColumns"></tr>
63+
<tr mat-row *matRowDef="let row; columns: loanSummaryColumns"></tr>
64+
</table>
65+
</div>
66+
}
67+
</div>

0 commit comments

Comments
 (0)