Skip to content

Commit afd26da

Browse files
Merge pull request #3520 from alberto-art3ch/WEB-657/workingcapital-product-gl-account-mappings
WEB-657: Working Capital product with GL Account mappings
2 parents 2fe316a + dd9731e commit afd26da

25 files changed

Lines changed: 1558 additions & 1112 deletions

src/app/core/utils/accounting.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,20 @@ export class Accounting {
2929
];
3030
}
3131

32-
public getAccountingRulesForLoans(): string[] {
33-
return [
34-
'NONE',
35-
'Cash',
36-
'Accrual (periodic)',
37-
'Accrual (upfront)'
38-
];
32+
public getAccountingRulesForLoans(isLoanProduct: boolean): string[] {
33+
if (isLoanProduct) {
34+
return [
35+
'NONE',
36+
'Cash',
37+
'Accrual (periodic)',
38+
'Accrual (upfront)'
39+
];
40+
} else {
41+
return [
42+
'NONE',
43+
'CASH_BASED'
44+
];
45+
}
3946
}
4047

4148
public getAccountRuleName(value: string): string {

src/app/products/loan-products/common/loan-product-summary/loan-product-summary.component.html

Lines changed: 325 additions & 313 deletions
Large diffs are not rendered by default.

src/app/products/loan-products/common/loan-product-summary/loan-product-summary.component.ts

Lines changed: 71 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ export class LoanProductSummaryComponent extends LoanProductBaseComponent implem
135135
writeOffReasonsToExpenseMappings: ChargeOffReasonToExpenseAccountMapping[] = [];
136136

137137
ngOnInit() {
138-
this.accountingRuleData = this.accounting.getAccountingRulesForLoans();
138+
this.accountingRuleData = this.accounting.getAccountingRulesForLoans(this.loanProductService.isLoanProduct);
139139
this.setCurrentValues();
140140
}
141141

@@ -180,87 +180,82 @@ export class LoanProductSummaryComponent extends LoanProductBaseComponent implem
180180
}
181181
}
182182

183+
const assetAccountData = this.loanProductsTemplate.accountingMappingOptions.assetAccountOptions || [];
184+
const incomeAccountData = this.loanProductsTemplate.accountingMappingOptions.incomeAccountOptions || [];
185+
const expenseAccountData = this.loanProductsTemplate.accountingMappingOptions.expenseAccountOptions || [];
186+
const liabilityAccountData = this.loanProductsTemplate.accountingMappingOptions.liabilityAccountOptions || [];
187+
const assetAndLiabilityAccountData = assetAccountData.concat(liabilityAccountData);
188+
const chargeOffReasonOptions: any = this.loanProductsTemplate.chargeOffReasonOptions || [];
189+
const writeOffReasonOptions: any = this.loanProductsTemplate.writeOffReasonOptions || [];
190+
191+
this.accountingMappings = {
192+
fundSourceAccount: this.glAccountLookUp(this.loanProduct.fundSourceAccountId, assetAndLiabilityAccountData),
193+
loanPortfolioAccount: this.glAccountLookUp(this.loanProduct.loanPortfolioAccountId, assetAccountData),
194+
receivableInterestAccount: this.glAccountLookUp(this.loanProduct.receivableInterestAccountId, assetAccountData),
195+
receivableFeeAccount: this.glAccountLookUp(this.loanProduct.receivableFeeAccountId, assetAccountData),
196+
receivablePenaltyAccount: this.glAccountLookUp(this.loanProduct.receivablePenaltyAccountId, assetAccountData),
197+
transfersInSuspenseAccount: this.glAccountLookUp(
198+
this.loanProduct.transfersInSuspenseAccountId,
199+
assetAccountData
200+
),
201+
202+
interestOnLoanAccount: this.glAccountLookUp(this.loanProduct.interestOnLoanAccountId, incomeAccountData),
203+
incomeFromDiscountFeeAccount: this.glAccountLookUp(
204+
this.loanProduct.incomeFromDiscountFeeAccountId,
205+
incomeAccountData
206+
),
207+
incomeFromFeeAccount: this.glAccountLookUp(this.loanProduct.incomeFromFeeAccountId, incomeAccountData),
208+
incomeFromPenaltyAccount: this.glAccountLookUp(this.loanProduct.incomeFromPenaltyAccountId, incomeAccountData),
209+
incomeFromRecoveryAccount: this.glAccountLookUp(
210+
this.loanProduct.incomeFromRecoveryAccountId,
211+
incomeAccountData
212+
),
213+
incomeFromChargeOffInterestAccount: this.glAccountLookUp(
214+
this.loanProduct.incomeFromChargeOffInterestAccountId,
215+
incomeAccountData
216+
),
217+
incomeFromChargeOffFeesAccount: this.glAccountLookUp(
218+
this.loanProduct.incomeFromChargeOffFeesAccountId,
219+
incomeAccountData
220+
),
221+
incomeFromChargeOffPenaltyAccount: this.glAccountLookUp(
222+
this.loanProduct.incomeFromChargeOffPenaltyAccountId,
223+
incomeAccountData
224+
),
225+
incomeFromCapitalizationAccount: this.glAccountLookUp(
226+
this.loanProduct.incomeFromCapitalizationAccountId,
227+
incomeAccountData
228+
),
229+
incomeFromBuyDownAccount: this.glAccountLookUp(this.loanProduct.incomeFromBuyDownAccountId, incomeAccountData),
230+
231+
writeOffAccount: this.glAccountLookUp(this.loanProduct.writeOffAccountId, expenseAccountData),
232+
goodwillCreditAccount: this.glAccountLookUp(this.loanProduct.goodwillCreditAccountId, expenseAccountData),
233+
chargeOffExpenseAccount: this.glAccountLookUp(this.loanProduct.chargeOffExpenseAccountId, expenseAccountData),
234+
chargeOffFraudExpenseAccount: this.glAccountLookUp(
235+
this.loanProduct.chargeOffFraudExpenseAccountId,
236+
expenseAccountData
237+
),
238+
buyDownExpenseAccount: this.glAccountLookUp(this.loanProduct.buyDownExpenseAccountId, expenseAccountData),
239+
240+
overpaymentLiabilityAccount: this.glAccountLookUp(
241+
this.loanProduct.overpaymentLiabilityAccountId,
242+
liabilityAccountData
243+
),
244+
deferredIncomeLiabilityAccount: this.glAccountLookUp(
245+
this.loanProduct.deferredIncomeLiabilityAccountId,
246+
liabilityAccountData
247+
)
248+
};
249+
183250
if (this.loanProductService.isLoanProduct) {
184251
if (
185252
(this.loanProduct.accountingRule && this.loanProduct.accountingRule > 1) ||
186253
this.loanProductsTemplate.accountingRule.value !== 'NONE'
187254
) {
188-
const assetAccountData = this.loanProductsTemplate.accountingMappingOptions.assetAccountOptions || [];
189-
const incomeAccountData = this.loanProductsTemplate.accountingMappingOptions.incomeAccountOptions || [];
190-
const expenseAccountData = this.loanProductsTemplate.accountingMappingOptions.expenseAccountOptions || [];
191-
const liabilityAccountData = this.loanProductsTemplate.accountingMappingOptions.liabilityAccountOptions || [];
192-
const assetAndLiabilityAccountData =
193-
this.loanProductsTemplate.accountingMappingOptions.assetAndLiabilityAccountOptions || [];
194-
const chargeOffReasonOptions: any = this.loanProductsTemplate.chargeOffReasonOptions || [];
195-
const writeOffReasonOptions: any = this.loanProductsTemplate.writeOffReasonOptions || [];
196255
const buydownFeeClassificationOptions: any = this.loanProductsTemplate.buydownFeeClassificationOptions || [];
197256
const capitalizedIncomeClassificationOptions: any =
198257
this.loanProductsTemplate.capitalizedIncomeClassificationOptions || [];
199258

200-
this.accountingMappings = {
201-
fundSourceAccount: this.glAccountLookUp(this.loanProduct.fundSourceAccountId, assetAndLiabilityAccountData),
202-
loanPortfolioAccount: this.glAccountLookUp(this.loanProduct.loanPortfolioAccountId, assetAccountData),
203-
receivableInterestAccount: this.glAccountLookUp(
204-
this.loanProduct.receivableInterestAccountId,
205-
assetAccountData
206-
),
207-
receivableFeeAccount: this.glAccountLookUp(this.loanProduct.receivableFeeAccountId, assetAccountData),
208-
receivablePenaltyAccount: this.glAccountLookUp(
209-
this.loanProduct.receivablePenaltyAccountId,
210-
assetAccountData
211-
),
212-
transfersInSuspenseAccount: this.glAccountLookUp(
213-
this.loanProduct.transfersInSuspenseAccountId,
214-
assetAccountData
215-
),
216-
217-
interestOnLoanAccount: this.glAccountLookUp(this.loanProduct.interestOnLoanAccountId, incomeAccountData),
218-
incomeFromFeeAccount: this.glAccountLookUp(this.loanProduct.incomeFromFeeAccountId, incomeAccountData),
219-
incomeFromPenaltyAccount: this.glAccountLookUp(
220-
this.loanProduct.incomeFromPenaltyAccountId,
221-
incomeAccountData
222-
),
223-
incomeFromRecoveryAccount: this.glAccountLookUp(
224-
this.loanProduct.incomeFromRecoveryAccountId,
225-
incomeAccountData
226-
),
227-
incomeFromChargeOffInterestAccount: this.glAccountLookUp(
228-
this.loanProduct.incomeFromChargeOffInterestAccountId,
229-
incomeAccountData
230-
),
231-
incomeFromChargeOffFeesAccount: this.glAccountLookUp(
232-
this.loanProduct.incomeFromChargeOffFeesAccountId,
233-
incomeAccountData
234-
),
235-
incomeFromChargeOffPenaltyAccount: this.glAccountLookUp(
236-
this.loanProduct.incomeFromChargeOffPenaltyAccountId,
237-
incomeAccountData
238-
),
239-
incomeFromCapitalizationAccount: this.glAccountLookUp(
240-
this.loanProduct.incomeFromCapitalizationAccountId,
241-
incomeAccountData
242-
),
243-
incomeFromBuyDownAccount: this.glAccountLookUp(
244-
this.loanProduct.incomeFromBuyDownAccountId,
245-
incomeAccountData
246-
),
247-
248-
writeOffAccount: this.glAccountLookUp(this.loanProduct.writeOffAccountId, expenseAccountData),
249-
goodwillCreditAccount: this.glAccountLookUp(this.loanProduct.goodwillCreditAccountId, expenseAccountData),
250-
chargeOffExpenseAccount: this.glAccountLookUp(this.loanProduct.writeOffAccountId, expenseAccountData),
251-
chargeOffFraudExpenseAccount: this.glAccountLookUp(this.loanProduct.writeOffAccountId, expenseAccountData),
252-
buyDownExpenseAccount: this.glAccountLookUp(this.loanProduct.buyDownExpenseAccountId, expenseAccountData),
253-
254-
overpaymentLiabilityAccount: this.glAccountLookUp(
255-
this.loanProduct.overpaymentLiabilityAccountId,
256-
liabilityAccountData
257-
),
258-
deferredIncomeLiabilityAccount: this.glAccountLookUp(
259-
this.loanProduct.deferredIncomeLiabilityAccountId,
260-
liabilityAccountData
261-
)
262-
};
263-
264259
this.paymentChannelToFundSourceMappings = [];
265260
if (this.loanProduct.paymentChannelToFundSourceMappings?.length > 0) {
266261
const paymentTypesData = this.loanProductsTemplate.paymentTypeOptions || [];
@@ -658,10 +653,7 @@ export class LoanProductSummaryComponent extends LoanProductBaseComponent implem
658653
return delinquencyBucketData;
659654
}
660655

661-
accountingRule(): number {
662-
if (this.loanProductService.isWorkingCapital) {
663-
return 0;
664-
}
656+
accountingRule(): any {
665657
return this.loanProduct.accountingRule.id ? this.loanProduct.accountingRule.id : this.loanProduct.accountingRule;
666658
}
667659

@@ -670,7 +662,7 @@ export class LoanProductSummaryComponent extends LoanProductBaseComponent implem
670662
}
671663

672664
isAccountingEnabled(): boolean {
673-
return this.accountingRule() >= 2;
665+
return this.loanProductService.isLoanProduct ? this.accountingRule() >= 2 : this.accountingRule() !== 'NONE';
674666
}
675667

676668
isAdvancedAccountingEnabled(): boolean {
@@ -690,7 +682,7 @@ export class LoanProductSummaryComponent extends LoanProductBaseComponent implem
690682
}
691683

692684
getAccountingRuleName(value: string): string {
693-
return this.loanProductService.isWorkingCapital ? '' : this.accounting.getAccountRuleName(value.toUpperCase());
685+
return this.accounting.getAccountRuleName(value.toUpperCase());
694686
}
695687

696688
mapHumanReadableValueStringEnumOptionDataList(incomingParameter: StringEnumOptionData[]): string[] {

src/app/products/loan-products/create-loan-product/create-loan-product.component.html

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -151,21 +151,19 @@
151151
</mat-step>
152152
}
153153

154-
@if (loanProductService.isLoanProduct) {
155-
<mat-step [stepControl]="loanProductAccountingForm">
156-
<ng-template matStepLabel
157-
><strong>{{ getProductTypeLabel(true) }} : </strong>{{ 'labels.inputs.ACCOUNTING' | translate }}</ng-template
158-
>
154+
<mat-step>
155+
<ng-template matStepLabel
156+
><strong>{{ getProductTypeLabel(true) }} : </strong>{{ 'labels.inputs.ACCOUNTING' | translate }}</ng-template
157+
>
159158

160-
<mifosx-loan-product-accounting-step
161-
[loanProductsTemplate]="loanProductsTemplate"
162-
[accountingRuleData]="accountingRuleData"
163-
[loanProductFormValid]="loanProductFormValid"
164-
[deferredIncomeRecognition]="deferredIncomeRecognition"
165-
>
166-
</mifosx-loan-product-accounting-step>
167-
</mat-step>
168-
}
159+
<mifosx-loan-product-accounting-step
160+
[loanProductsTemplate]="loanProductsTemplate"
161+
[accountingRuleData]="accountingRuleData"
162+
[loanProductFormValid]="loanProductFormValid"
163+
[deferredIncomeRecognition]="deferredIncomeRecognition"
164+
>
165+
</mifosx-loan-product-accounting-step>
166+
</mat-step>
169167

170168
@if (loanProductFormValid) {
171169
<mat-step state="preview" completed>

src/app/products/loan-products/create-loan-product/create-loan-product.component.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export class CreateLoanProductComponent extends LoanProductBaseComponent impleme
8686
loanProductSettingsStep: LoanProductSettingsStepComponent;
8787
@ViewChild(LoanProductChargesStepComponent, { static: false })
8888
loanProductChargesStep: LoanProductChargesStepComponent;
89-
@ViewChild(LoanProductAccountingStepComponent, { static: false })
89+
@ViewChild(LoanProductAccountingStepComponent, { static: true })
9090
loanProductAccountingStep: LoanProductAccountingStepComponent;
9191

9292
loanProductsTemplate: any;
@@ -127,10 +127,9 @@ export class CreateLoanProductComponent extends LoanProductBaseComponent impleme
127127
}
128128

129129
ngOnInit() {
130-
this.accountingRuleData = this.accounting.getAccountingRulesForLoans();
130+
this.accountingRuleData = this.accounting.getAccountingRulesForLoans(this.loanProductService.isLoanProduct);
131131
this.buildAdvancedPaymentAllocation();
132132
if (this.loanProductService.isWorkingCapital) {
133-
this.accountingRuleData = ['NONE'];
134133
this.loanProductsTemplate['creditAllocationTransactionTypes'] = [];
135134
}
136135
}
@@ -249,9 +248,7 @@ export class CreateLoanProductComponent extends LoanProductBaseComponent impleme
249248
}
250249

251250
get loanProductAccountingForm() {
252-
if (this.loanProductService.isLoanProduct) {
253-
return this.loanProductAccountingStep?.loanProductAccountingForm;
254-
}
251+
return this.loanProductAccountingStep?.loanProductAccountingForm;
255252
}
256253

257254
get loanProductFormValid() {
@@ -280,7 +277,8 @@ export class CreateLoanProductComponent extends LoanProductBaseComponent impleme
280277
this.loanProductDetailsForm.valid &&
281278
this.loanProductCurrencyForm.valid &&
282279
this.loanProductTermsForm.valid &&
283-
this.loanProductSettingsForm.valid
280+
this.loanProductSettingsForm.valid &&
281+
this.loanProductAccountingForm?.valid
284282
);
285283
}
286284
}
@@ -328,7 +326,8 @@ export class CreateLoanProductComponent extends LoanProductBaseComponent impleme
328326
...this.loanProductDetailsStep.loanProductDetails,
329327
...this.loanProductCurrencyStep.loanProductCurrency,
330328
...this.loanProductTermsStep.loanProductTerms,
331-
...this.loanProductSettingsStep.loanProductSettings
329+
...this.loanProductSettingsStep.loanProductSettings,
330+
...this.loanProductAccountingStep.loanProductAccounting
332331
};
333332
loanProduct['paymentAllocation'] = this.paymentAllocation;
334333
return loanProduct;
@@ -376,7 +375,14 @@ export class CreateLoanProductComponent extends LoanProductBaseComponent impleme
376375
submitWCProduct(): void {
377376
const loanProduct = this.loanProducts.buildPayload(this.loanProduct, this.itemsByDefault);
378377

379-
loanProduct['accountingRule'] = 'NONE';
378+
// No Empty values to be sent
379+
[
380+
'nearBreachId'
381+
].forEach((attr: string) => {
382+
if (loanProduct[attr] === null || loanProduct[attr] === '') {
383+
delete loanProduct[attr];
384+
}
385+
});
380386

381387
this.productsService
382388
.createLoanProduct(this.loanProductService.loanProductPath, loanProduct)

src/app/products/loan-products/edit-loan-product/edit-loan-product.component.html

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -151,21 +151,19 @@
151151
</mat-step>
152152
}
153153

154-
@if (loanProductService.isLoanProduct) {
155-
<mat-step [stepControl]="loanProductAccountingForm" completed>
156-
<ng-template matStepLabel
157-
><strong>{{ getProductTypeLabel(true) }} : </strong>{{ 'labels.inputs.ACCOUNTING' | translate }}</ng-template
158-
>
154+
<mat-step completed>
155+
<ng-template matStepLabel
156+
><strong>{{ getProductTypeLabel(true) }} : </strong>{{ 'labels.inputs.ACCOUNTING' | translate }}</ng-template
157+
>
159158

160-
<mifosx-loan-product-accounting-step
161-
[loanProductsTemplate]="loanProductAndTemplate"
162-
[accountingRuleData]="accountingRuleData"
163-
[loanProductFormValid]="loanProductFormValidAndNotPristine"
164-
[deferredIncomeRecognition]="deferredIncomeRecognition"
165-
>
166-
</mifosx-loan-product-accounting-step>
167-
</mat-step>
168-
}
159+
<mifosx-loan-product-accounting-step
160+
[loanProductsTemplate]="loanProductAndTemplate"
161+
[accountingRuleData]="accountingRuleData"
162+
[loanProductFormValid]="loanProductFormValidAndNotPristine"
163+
[deferredIncomeRecognition]="deferredIncomeRecognition"
164+
>
165+
</mifosx-loan-product-accounting-step>
166+
</mat-step>
169167

170168
@if (loanProductFormValidAndNotPristine) {
171169
<mat-step state="preview" completed>

0 commit comments

Comments
 (0)