Skip to content

Commit 41cd56d

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

42 files changed

Lines changed: 1767 additions & 1133 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/loan-base.resolver.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export class LoanBaseResolver {
4242
return this.isLoanProduct ? 'loanproducts' : 'working-capital-loan-products';
4343
}
4444

45-
get loanAccountPath(): string {
45+
get loanAccountPath(): 'loans' | 'working-capital-loans' {
4646
return this.isLoanProduct ? 'loans' : 'working-capital-loans';
4747
}
4848
}

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,36 @@ 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 (
41+
loanId === null ||
42+
transactionId === null ||
43+
Number.isNaN(Number(loanId)) ||
44+
Number.isNaN(Number(transactionId))
45+
) {
46+
throw new Error('Invalid loan or transaction route params');
47+
}
48+
return this.loansService.getLoansAccountTransaction(this.loanAccountPath, loanId, transactionId);
3549
}
3650
}

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: 11 additions & 107 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() {
@@ -101,91 +74,22 @@ export class GeneralTabComponent extends LoanProductBaseComponent implements OnI
10174
this.loanDetails = data.loanDetailsData;
10275
this.currencyCode = this.loanDetails.currency.code;
10376
if (this.loanDetails.transactions) {
104-
this.loanDetails.transactions.some((transaction: any) => {
105-
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-
];
116-
return;
117-
}
118-
});
77+
this.hasChargeBack = this.loanDetails.transactions.some(
78+
(transaction: any) => transaction.type.code === 'loanTransactionType.chargeback'
79+
);
11980
}
12081
});
12182
}
12283

12384
ngOnInit() {
12485
this.status = this.loanDetails.value;
12586
if (this.loanDetails.summary) {
126-
this.setloanSummaryTableData();
12787
this.setloanDetailsTableData();
12888
} else {
12989
this.setloanNonDetailsTableData();
13090
}
13191
}
13292

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-
18993
setloanDetailsTableData() {
19094
this.loanDetailsTableData = [
19195
{

0 commit comments

Comments
 (0)