Skip to content

Commit 9911030

Browse files
alberto-art3chadamsaghy
authored andcommitted
WEB-657: Working Capital product with Advanced accounting
1 parent e3946ad commit 9911030

24 files changed

Lines changed: 686 additions & 603 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
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="flex-fill layout-row-wrap responsive-column">
10+
<h3 class="mat-h3 flex-100">{{ 'labels.heading.Advanced Accounting Rules' | translate }}</h3>
11+
<mat-divider [inset]="true"></mat-divider>
12+
@if (paymentChannelToFundSourceMappings?.length > 0) {
13+
<div class="flex-100 layout-row-wrap responsive-column">
14+
<h4 class="mat-h4 flex-100">
15+
{{ 'labels.heading.Configure Fund Sources for Payment Channels' | translate }}
16+
</h4>
17+
<table class="mat-elevation-z1 flex-100" mat-table [dataSource]="paymentChannelToFundSourceMappings">
18+
<ng-container matColumnDef="paymentTypeId">
19+
<th mat-header-cell *matHeaderCellDef>{{ 'labels.heading.Payment Type' | translate }}</th>
20+
<td mat-cell *matCellDef="let paymentFundSource">
21+
{{ paymentFundSource.paymentType?.name }}
22+
</td>
23+
</ng-container>
24+
<ng-container matColumnDef="fundSourceAccountId">
25+
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Fund Source' | translate }}</th>
26+
<td mat-cell *matCellDef="let paymentFundSource">
27+
{{ paymentFundSource.fundSourceAccount?.name }}
28+
</td>
29+
</ng-container>
30+
<tr mat-header-row *matHeaderRowDef="paymentFundSourceDisplayedColumns"></tr>
31+
<tr mat-row *matRowDef="let row; columns: paymentFundSourceDisplayedColumns"></tr>
32+
</table>
33+
</div>
34+
}
35+
@if (feeToIncomeAccountMappings?.length > 0) {
36+
<div class="flex-100 layout-row-wrap responsive-column">
37+
<h4 class="mat-h4 flex-100">
38+
{{ 'labels.heading.Map Fees to Specific Income Accounts' | translate }}
39+
</h4>
40+
<table class="mat-elevation-z1 flex-100" mat-table [dataSource]="feeToIncomeAccountMappings">
41+
<ng-container matColumnDef="chargeId">
42+
<th mat-header-cell *matHeaderCellDef>{{ 'labels.catalogs.Fees' | translate }}</th>
43+
<td mat-cell *matCellDef="let feesIncome">
44+
{{ feesIncome.charge?.name }}
45+
</td>
46+
</ng-container>
47+
<ng-container matColumnDef="incomeAccountId">
48+
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Income Account' | translate }}</th>
49+
<td mat-cell *matCellDef="let feesIncome">
50+
@if (feesIncome.incomeAccount) {
51+
<span>
52+
{{ feesIncome.incomeAccount.name }}
53+
</span>
54+
}
55+
</td>
56+
</ng-container>
57+
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
58+
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns"></tr>
59+
</table>
60+
</div>
61+
}
62+
@if (penaltyToIncomeAccountMappings?.length > 0) {
63+
<div class="flex-100 layout-row-wrap responsive-column">
64+
<h4 class="mat-h4 flex-100">
65+
{{ 'labels.heading.Map Penalties to Specific Income Accounts' | translate }}
66+
</h4>
67+
<table class="mat-elevation-z1 flex-100" mat-table [dataSource]="penaltyToIncomeAccountMappings">
68+
<ng-container matColumnDef="chargeId">
69+
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Penalty' | translate }}</th>
70+
<td mat-cell *matCellDef="let penaltyIncome">
71+
{{ penaltyIncome.charge.name }}
72+
</td>
73+
</ng-container>
74+
<ng-container matColumnDef="incomeAccountId">
75+
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Income Account' | translate }}</th>
76+
<td mat-cell *matCellDef="let penaltyIncome">
77+
{{ penaltyIncome.incomeAccount?.name }}
78+
</td>
79+
</ng-container>
80+
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
81+
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns"></tr>
82+
</table>
83+
</div>
84+
}
85+
@if (chargeOffReasonToExpenseAccountMappings?.length > 0) {
86+
<div class="flex-100 layout-row-wrap responsive-column">
87+
<h4 class="mat-h4 flex-100">
88+
{{ 'labels.heading.Map Charge-off reasons to Expense accounts' | translate }}
89+
</h4>
90+
<table class="mat-elevation-z1 flex-100" mat-table [dataSource]="chargeOffReasonToExpenseAccountMappings">
91+
<ng-container matColumnDef="chargeOffReasonCodeValueId">
92+
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Charge-off Reason' | translate }}</th>
93+
<td mat-cell *matCellDef="let chargeOffReasonToExpenseAccountMapping">
94+
{{ chargeOffReasonToExpenseAccountMapping.reasonCodeValue?.name }}
95+
</td>
96+
</ng-container>
97+
<ng-container matColumnDef="expenseAccountId">
98+
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Expense Account' | translate }}</th>
99+
<td mat-cell *matCellDef="let chargeOffReasonToExpenseAccountMapping">
100+
({{ chargeOffReasonToExpenseAccountMapping.expenseAccount?.glCode }})
101+
{{ chargeOffReasonToExpenseAccountMapping.expenseAccount?.name }}
102+
</td>
103+
</ng-container>
104+
<tr mat-header-row *matHeaderRowDef="chargeOffReasonExpenseDisplayedColumns"></tr>
105+
<tr mat-row *matRowDef="let row; columns: chargeOffReasonExpenseDisplayedColumns"></tr>
106+
</table>
107+
</div>
108+
}
109+
@if (buydownFeeClassificationToIncomeAccountMappings?.length > 0) {
110+
<div class="flex-100 layout-row-wrap responsive-column">
111+
<h4 class="mat-h4 flex-100">
112+
{{ 'labels.heading.Buydown Fee classifications to Income accounts' | translate }}
113+
</h4>
114+
<table class="mat-elevation-z1 flex-100" mat-table [dataSource]="buydownFeeClassificationToIncomeAccountMappings">
115+
<ng-container matColumnDef="chargeOffReasonCodeValueId">
116+
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Classification' | translate }}</th>
117+
<td mat-cell *matCellDef="let classificationToIncomeAccountMapping">
118+
{{ classificationToIncomeAccountMapping.classificationCodeValue?.name }}
119+
</td>
120+
</ng-container>
121+
<ng-container matColumnDef="expenseAccountId">
122+
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Income Account' | translate }}</th>
123+
<td mat-cell *matCellDef="let classificationToIncomeAccountMapping">
124+
({{ classificationToIncomeAccountMapping.incomeAccount?.glCode }})
125+
{{ classificationToIncomeAccountMapping.incomeAccount?.name }}
126+
</td>
127+
</ng-container>
128+
<tr mat-header-row *matHeaderRowDef="chargeOffReasonExpenseDisplayedColumns"></tr>
129+
<tr mat-row *matRowDef="let row; columns: chargeOffReasonExpenseDisplayedColumns"></tr>
130+
</table>
131+
</div>
132+
}
133+
@if (capitalizedIncomeClassificationToIncomeAccountMappings?.length > 0) {
134+
<div class="flex-100 layout-row-wrap responsive-column">
135+
<h4 class="mat-h4 flex-100">
136+
{{ 'labels.heading.Capitalized Income classifications to Income accounts' | translate }}
137+
</h4>
138+
<table
139+
class="mat-elevation-z1 flex-100"
140+
mat-table
141+
[dataSource]="capitalizedIncomeClassificationToIncomeAccountMappings"
142+
>
143+
<ng-container matColumnDef="chargeOffReasonCodeValueId">
144+
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Classification' | translate }}</th>
145+
<td mat-cell *matCellDef="let capitalizedIncomeClassificationToIncomeAccountMapping">
146+
{{ capitalizedIncomeClassificationToIncomeAccountMapping.classificationCodeValue?.name }}
147+
</td>
148+
</ng-container>
149+
<ng-container matColumnDef="expenseAccountId">
150+
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Income Account' | translate }}</th>
151+
<td mat-cell *matCellDef="let capitalizedIncomeClassificationToIncomeAccountMapping">
152+
({{ capitalizedIncomeClassificationToIncomeAccountMapping.incomeAccount?.glCode }})
153+
{{ capitalizedIncomeClassificationToIncomeAccountMapping.incomeAccount?.name }}
154+
</td>
155+
</ng-container>
156+
<tr mat-header-row *matHeaderRowDef="chargeOffReasonExpenseDisplayedColumns"></tr>
157+
<tr mat-row *matRowDef="let row; columns: chargeOffReasonExpenseDisplayedColumns"></tr>
158+
</table>
159+
</div>
160+
}
161+
@if (writeOffReasonsToExpenseMappings?.length > 0) {
162+
<div class="flex-100 layout-row-wrap responsive-column">
163+
<h4 class="mat-h4 flex-100">
164+
{{ 'labels.heading.WriteOff reasons to Expense accounts' | translate }}
165+
</h4>
166+
<table class="mat-elevation-z1 flex-100" mat-table [dataSource]="writeOffReasonsToExpenseMappings">
167+
<ng-container matColumnDef="chargeOffReasonCodeValueId">
168+
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.WriteOff Reason' | translate }}</th>
169+
<td mat-cell *matCellDef="let writeOffReasonsToExpenseMapping">
170+
{{ writeOffReasonsToExpenseMapping.reasonCodeValue?.name }}
171+
</td>
172+
</ng-container>
173+
<ng-container matColumnDef="expenseAccountId">
174+
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Expense Account' | translate }}</th>
175+
<td mat-cell *matCellDef="let writeOffReasonsToExpenseMapping">
176+
({{ writeOffReasonsToExpenseMapping.expenseAccount?.glCode }})
177+
{{ writeOffReasonsToExpenseMapping.expenseAccount?.name }}
178+
</td>
179+
</ng-container>
180+
<tr mat-header-row *matHeaderRowDef="chargeOffReasonExpenseDisplayedColumns"></tr>
181+
<tr mat-row *matRowDef="let row; columns: chargeOffReasonExpenseDisplayedColumns"></tr>
182+
</table>
183+
</div>
184+
}
185+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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+
@use 'assets/styles/helper';
10+
@use 'assets/styles/colours' as *;
11+
12+
table {
13+
width: 100%;
14+
}
15+
16+
h2,
17+
h3,
18+
h4 {
19+
margin: 0;
20+
font-weight: 500;
21+
}
22+
23+
.mat-h3 {
24+
margin-top: 10px !important;
25+
font-weight: 300;
26+
color: $status-approved;
27+
}
28+
29+
.mat-h4 {
30+
margin-top: 10px !important;
31+
font-weight: 200;
32+
color: $status-approved;
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
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+
import { Component, Input } from '@angular/core';
10+
import { MatDivider } from '@angular/material/divider';
11+
import {
12+
MatCell,
13+
MatCellDef,
14+
MatColumnDef,
15+
MatHeaderCell,
16+
MatHeaderCellDef,
17+
MatHeaderRow,
18+
MatHeaderRowDef,
19+
MatRow,
20+
MatRowDef,
21+
MatTable
22+
} from '@angular/material/table';
23+
import {
24+
ChargeOffReasonToExpenseAccountMapping,
25+
ChargeToIncomeAccountMapping,
26+
ClassificationToIncomeAccountMapping,
27+
PaymentChannelToFundSourceMapping
28+
} from 'app/shared/models/general.model';
29+
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
30+
31+
@Component({
32+
selector: 'mifosx-loan-product-summary-adv-accounting',
33+
templateUrl: './loan-product-summary-adv-accounting.component.html',
34+
styleUrl: './loan-product-summary-adv-accounting.component.scss',
35+
imports: [
36+
...STANDALONE_SHARED_IMPORTS,
37+
MatDivider,
38+
MatTable,
39+
MatColumnDef,
40+
MatHeaderCellDef,
41+
MatHeaderCell,
42+
MatCellDef,
43+
MatCell,
44+
MatHeaderRowDef,
45+
MatHeaderRow,
46+
MatRowDef,
47+
MatRow
48+
]
49+
})
50+
export class LoanProductSummaryAdvAccountingComponent {
51+
@Input() paymentChannelToFundSourceMappings: PaymentChannelToFundSourceMapping[] = [];
52+
@Input() feeToIncomeAccountMappings: ChargeToIncomeAccountMapping[] = [];
53+
@Input() penaltyToIncomeAccountMappings: ChargeToIncomeAccountMapping[] = [];
54+
@Input() chargeOffReasonToExpenseAccountMappings: ChargeOffReasonToExpenseAccountMapping[] = [];
55+
@Input() buydownFeeClassificationToIncomeAccountMappings: ClassificationToIncomeAccountMapping[] = [];
56+
@Input() capitalizedIncomeClassificationToIncomeAccountMappings: ClassificationToIncomeAccountMapping[] = [];
57+
@Input() writeOffReasonsToExpenseMappings: ChargeOffReasonToExpenseAccountMapping[] = [];
58+
59+
paymentFundSourceDisplayedColumns: string[] = [
60+
'paymentTypeId',
61+
'fundSourceAccountId'
62+
];
63+
feesPenaltyIncomeDisplayedColumns: string[] = [
64+
'chargeId',
65+
'incomeAccountId'
66+
];
67+
chargeOffReasonExpenseDisplayedColumns: string[] = [
68+
'chargeOffReasonCodeValueId',
69+
'expenseAccountId'
70+
];
71+
}

0 commit comments

Comments
 (0)