Skip to content

Commit 437c404

Browse files
committed
FINERACT-2312: Accruals added for savings accounts
1 parent 7b7118d commit 437c404

File tree

31 files changed

+1086
-9
lines changed

31 files changed

+1086
-9
lines changed

fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingHelper.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ public void mergeProductToAccountMappingChanges(final JsonElement element, final
100100
optionalProductToGLAccountMappingEntries.add("incomeFromGoodwillCreditInterestAccountId");
101101
optionalProductToGLAccountMappingEntries.add("incomeFromGoodwillCreditFeesAccountId");
102102
optionalProductToGLAccountMappingEntries.add("incomeFromGoodwillCreditPenaltyAccountId");
103+
optionalProductToGLAccountMappingEntries.add("interestReceivableAccountId");
103104
optionalProductToGLAccountMappingEntries.add(LoanProductAccountingParams.DEFERRED_INCOME_LIABILITY.getValue());
104105
optionalProductToGLAccountMappingEntries.add(LoanProductAccountingParams.INCOME_FROM_CAPITALIZATION.getValue());
105106
optionalProductToGLAccountMappingEntries.add(LoanProductAccountingParams.BUY_DOWN_EXPENSE.getValue());

fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,8 @@ private Map<String, Object> setAccrualPeriodicSavingsProductToGLAccountMaps(fina
358358
// Assets
359359
if (glAccountForSavings.equals(AccrualAccountsForSavings.SAVINGS_REFERENCE)) {
360360
accountMappingDetails.put(SavingProductAccountingDataParams.SAVINGS_REFERENCE.getValue(), glAccountData);
361+
} else if (glAccountForSavings.equals(AccrualAccountsForSavings.INTEREST_RECEIVABLE)) {
362+
accountMappingDetails.put(SavingProductAccountingDataParams.INTEREST_RECEIVABLE.getValue(), glAccountData);
361363
} else if (glAccountForSavings.equals(AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL)) {
362364
accountMappingDetails.put(SavingProductAccountingDataParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), glAccountData);
363365
} else if (glAccountForSavings.equals(AccrualAccountsForSavings.FEES_RECEIVABLE)) {

fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/SavingsProductToGLAccountMappingHelper.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,10 @@ public void handleChangesToSavingsProductToGLAccountMappings(final Long savingsP
263263
savingsProductId, AccrualAccountsForSavings.FEES_RECEIVABLE.getValue(),
264264
AccrualAccountsForSavings.FEES_RECEIVABLE.toString(), changes);
265265

266+
mergeSavingsToAssetAccountMappingChanges(element, SavingProductAccountingParams.INTEREST_RECEIVABLE.getValue(),
267+
savingsProductId, AccrualAccountsForSavings.INTEREST_RECEIVABLE.getValue(),
268+
AccrualAccountsForSavings.INTEREST_RECEIVABLE.toString(), changes);
269+
266270
mergeSavingsToAssetAccountMappingChanges(element, SavingProductAccountingParams.PENALTIES_RECEIVABLE.getValue(),
267271
savingsProductId, AccrualAccountsForSavings.PENALTIES_RECEIVABLE.getValue(),
268272
AccrualAccountsForSavings.PENALTIES_RECEIVABLE.toString(), changes);

fineract-core/src/main/java/org/apache/fineract/accounting/common/AccountingConstants.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,8 @@ public enum AccrualAccountsForSavings {
312312
ESCHEAT_LIABILITY(14), //
313313
FEES_RECEIVABLE(15), //
314314
PENALTIES_RECEIVABLE(16), //
315-
INTEREST_PAYABLE(17);
315+
INTEREST_PAYABLE(17), //
316+
INTEREST_RECEIVABLE(18);
316317

317318
private final Integer value;
318319

@@ -365,6 +366,7 @@ public enum SavingProductAccountingParams {
365366
INCOME_FROM_INTEREST("incomeFromInterestId"), //
366367
LOSSES_WRITTEN_OFF("writeOffAccountId"), //
367368
ESCHEAT_LIABILITY("escheatLiabilityId"), //
369+
INTEREST_RECEIVABLE("interestReceivableAccountId"), //
368370
PENALTIES_RECEIVABLE("penaltiesReceivableAccountId"), //
369371
FEES_RECEIVABLE("feesReceivableAccountId"), //
370372
INTEREST_PAYABLE("interestPayableAccountId");
@@ -404,7 +406,8 @@ public enum SavingProductAccountingDataParams {
404406
ESCHEAT_LIABILITY("escheatLiabilityAccount"), //
405407
FEES_RECEIVABLE("feeReceivableAccount"), //
406408
PENALTIES_RECEIVABLE("penaltyReceivableAccount"), //
407-
INTEREST_PAYABLE("interestPayableAccount"); //
409+
INTEREST_PAYABLE("interestPayableAccount"), //
410+
INTEREST_RECEIVABLE("interestReceivableAccount"); //
408411

409412
private final String value;
410413

fineract-core/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobName.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public enum JobName {
5858
PURGE_EXTERNAL_EVENTS("Purge External Events"), //
5959
PURGE_PROCESSED_COMMANDS("Purge Processed Commands"), //
6060
ACCRUAL_ACTIVITY_POSTING("Accrual Activity Posting"), //
61-
;
61+
ADD_PERIODIC_ACCRUAL_ENTRIES_FOR_SAVINGS_WITH_INCOME_POSTED_AS_TRANSACTIONS("Add Accrual Transactions For Savings"); //
6262

6363
private final String name;
6464

fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ public class SavingsApiConstants {
104104
public static final String activeParamName = "active";
105105
public static final String nameParamName = "name";
106106
public static final String shortNameParamName = "shortName";
107+
public static final String interestReceivableAccount = "interestReceivableAccountId";
107108
public static final String descriptionParamName = "description";
108109
public static final String currencyCodeParamName = "currencyCode";
109110
public static final String digitsAfterDecimalParamName = "digitsAfterDecimal";

fineract-core/src/main/java/org/apache/fineract/portfolio/savings/domain/interest/PostingPeriod.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ public final class PostingPeriod {
6464

6565
private Integer financialYearBeginningMonth;
6666

67+
public void setOverdraftInterestRateAsFraction(BigDecimal overdraftInterestRateAsFraction) {
68+
this.overdraftInterestRateAsFraction = overdraftInterestRateAsFraction;
69+
}
70+
6771
public static PostingPeriod createFrom(final LocalDateInterval periodInterval, final Money periodStartingBalance,
6872
final List<SavingsAccountTransactionDetailsForPostingPeriod> orderedListOfTransactions, final MonetaryCurrency currency,
6973
final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType,
@@ -545,4 +549,10 @@ public Integer getFinancialYearBeginningMonth() {
545549
return this.financialYearBeginningMonth;
546550
}
547551

552+
// public List<CompoundingPeriod> getCompoundingPeriods() {return compoundingPeriods;}
553+
554+
public Money getClosingBalance() {
555+
return closingBalance;
556+
}
557+
548558
}

fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForSavings.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.apache.fineract.accounting.journalentry.data.ChargePaymentDTO;
2929
import org.apache.fineract.accounting.journalentry.data.SavingsDTO;
3030
import org.apache.fineract.accounting.journalentry.data.SavingsTransactionDTO;
31+
import org.apache.fineract.infrastructure.core.service.MathUtil;
3132
import org.apache.fineract.organisation.office.domain.Office;
3233
import org.springframework.stereotype.Component;
3334

@@ -182,9 +183,21 @@ else if (savingsTransactionDTO.getTransactionType().isInterestPosting()) {
182183
else if (savingsTransactionDTO.getTransactionType().isAccrual()) {
183184
// Post journal entry for Accrual Recognition
184185
if (savingsTransactionDTO.getAmount().compareTo(BigDecimal.ZERO) > 0) {
185-
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
186-
AccrualAccountsForSavings.INTEREST_ON_SAVINGS.getValue(), AccrualAccountsForSavings.INTEREST_PAYABLE.getValue(),
187-
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
186+
if (MathUtil.isGreaterThanZero(overdraftAmount)) {
187+
this.helper.createAccrualBasedDebitJournalEntriesAndReversalsForSavings(office, currencyCode,
188+
AccrualAccountsForSavings.INTEREST_ON_SAVINGS.getValue(), savingsProductId, paymentTypeId, savingsId,
189+
transactionId, transactionDate, amount, isReversal);
190+
this.helper.createAccrualBasedCreditJournalEntriesAndReversalsForSavings(office, currencyCode,
191+
AccrualAccountsForSavings.INTEREST_PAYABLE.getValue(), savingsProductId, paymentTypeId, savingsId,
192+
transactionId, transactionDate, amount, isReversal);
193+
} else {
194+
this.helper.createAccrualBasedDebitJournalEntriesAndReversalsForSavings(office, currencyCode,
195+
AccrualAccountsForSavings.INTEREST_RECEIVABLE.getValue(), savingsProductId, paymentTypeId, savingsId,
196+
transactionId, transactionDate, amount, isReversal);
197+
this.helper.createAccrualBasedCreditJournalEntriesAndReversalsForSavings(office, currencyCode,
198+
AccrualAccountsForSavings.INCOME_FROM_INTEREST.getValue(), savingsProductId, paymentTypeId, savingsId,
199+
transactionId, transactionDate, amount, isReversal);
200+
}
188201
}
189202
}
190203

fineract-provider/src/main/java/org/apache/fineract/accounting/productaccountmapping/service/ProductToGLAccountMappingWritePlatformServiceImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ public void createSavingProductToGLAccountMapping(final Long savingProductId, fi
292292
final JsonElement element = this.fromApiJsonHelper.parse(command.json());
293293
final Integer accountingRuleTypeId = this.fromApiJsonHelper.extractIntegerNamed(accountingRuleParamName, element,
294294
Locale.getDefault());
295+
295296
final AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(accountingRuleTypeId);
296297
switch (accountingRuleType) {
297298
case NONE:
@@ -303,6 +304,10 @@ public void createSavingProductToGLAccountMapping(final Long savingProductId, fi
303304
case ACCRUAL_PERIODIC:
304305
saveSavingsBaseAccountMapping(savingProductId, accountType, command, element);
305306
// assets
307+
this.savingsProductToGLAccountMappingHelper.saveSavingsToAssetAccountMapping(element,
308+
SavingProductAccountingParams.INTEREST_RECEIVABLE.getValue(), savingProductId,
309+
AccrualAccountsForSavings.INTEREST_RECEIVABLE.getValue());
310+
306311
this.savingsProductToGLAccountMappingHelper.saveSavingsToAssetAccountMapping(element,
307312
SavingProductAccountingParams.FEES_RECEIVABLE.getValue(), savingProductId,
308313
AccrualAccountsForSavings.FEES_RECEIVABLE.getValue());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.fineract.portfolio.savings.jobs.addaccrualtransactionforsavings;
20+
21+
import org.apache.fineract.infrastructure.jobs.service.JobName;
22+
import org.apache.fineract.portfolio.savings.service.SavingsAccrualWritePlatformService;
23+
import org.springframework.batch.core.Job;
24+
import org.springframework.batch.core.Step;
25+
import org.springframework.batch.core.job.builder.JobBuilder;
26+
import org.springframework.batch.core.launch.support.RunIdIncrementer;
27+
import org.springframework.batch.core.repository.JobRepository;
28+
import org.springframework.batch.core.step.builder.StepBuilder;
29+
import org.springframework.beans.factory.annotation.Autowired;
30+
import org.springframework.context.annotation.Bean;
31+
import org.springframework.context.annotation.Configuration;
32+
import org.springframework.transaction.PlatformTransactionManager;
33+
34+
@Configuration
35+
public class AddAccrualTransactionForSavingsConfig {
36+
37+
@Autowired
38+
private JobRepository jobRepository;
39+
@Autowired
40+
private PlatformTransactionManager transactionManager;
41+
@Autowired
42+
private SavingsAccrualWritePlatformService savingsAccrualWritePlatformService;
43+
44+
@Bean
45+
protected Step addAccrualTransactionForSavingsStep() {
46+
return new StepBuilder(JobName.ADD_PERIODIC_ACCRUAL_ENTRIES_FOR_SAVINGS_WITH_INCOME_POSTED_AS_TRANSACTIONS.name(), jobRepository)
47+
.tasklet(addAccrualTransactionForSavingsTasklet(), transactionManager).build();
48+
}
49+
50+
@Bean
51+
public Job addAccrualTransactionForSavingsJob() {
52+
return new JobBuilder(JobName.ADD_PERIODIC_ACCRUAL_ENTRIES_FOR_SAVINGS_WITH_INCOME_POSTED_AS_TRANSACTIONS.name(), jobRepository)
53+
.start(addAccrualTransactionForSavingsStep()).incrementer(new RunIdIncrementer()).build();
54+
}
55+
56+
@Bean
57+
public AddAccrualTransactionForSavingsTasklet addAccrualTransactionForSavingsTasklet() {
58+
return new AddAccrualTransactionForSavingsTasklet(savingsAccrualWritePlatformService);
59+
}
60+
}

0 commit comments

Comments
 (0)