diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm
index bf5da8ff5..f4969a1a8 100644
--- a/api-docs/apiLive.htm
+++ b/api-docs/apiLive.htm
@@ -13145,6 +13145,8 @@ Request Body:
allow-transactions-on-non_workingday - defaults to false - if true allows transactions on non-working days
reschedule-repayments-on-holidays - defaults to false - if true reschedules repayemnts which falls on a non-working day to defined reschedule date
allow-transactions-on-holiday - defaults to false - if true allows transactions on holidays
+ savings-interest-posting-current-period-end - Set it at the database level before any savings interest is posted. When set as false(default), interest will be posted on the first date of next period. If set as true, interest will be posted on last date of current period. There is no difference in the interest amount posted.
+ financial-year-beginning-month - Set it at the database level before any savings interest is posted. Allowed values 1 - 12 (January - December). Interest posting periods are evaluated based on this configuration.
diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/FlexibleSavingsInterestPostingIntegrationTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/FlexibleSavingsInterestPostingIntegrationTest.java
new file mode 100644
index 000000000..688443f85
--- /dev/null
+++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/FlexibleSavingsInterestPostingIntegrationTest.java
@@ -0,0 +1,148 @@
+/**
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.mifosplatform.integrationtests;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map.Entry;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mifosplatform.integrationtests.common.ClientHelper;
+import org.mifosplatform.integrationtests.common.CommonConstants;
+import org.mifosplatform.integrationtests.common.GlobalConfigurationHelper;
+import org.mifosplatform.integrationtests.common.Utils;
+import org.mifosplatform.integrationtests.common.savings.SavingsAccountHelper;
+import org.mifosplatform.integrationtests.common.savings.SavingsProductHelper;
+import org.mifosplatform.integrationtests.common.savings.SavingsStatusChecker;
+
+import com.jayway.restassured.builder.RequestSpecBuilder;
+import com.jayway.restassured.builder.ResponseSpecBuilder;
+import com.jayway.restassured.http.ContentType;
+import com.jayway.restassured.specification.RequestSpecification;
+import com.jayway.restassured.specification.ResponseSpecification;
+
+@SuppressWarnings({ "rawtypes", "unused", "unchecked" })
+public class FlexibleSavingsInterestPostingIntegrationTest {
+
+ public static final String ACCOUNT_TYPE_INDIVIDUAL = "INDIVIDUAL";
+
+ private ResponseSpecification responseSpec;
+ private RequestSpecification requestSpec;
+ private SavingsProductHelper savingsProductHelper;
+ private SavingsAccountHelper savingsAccountHelper;
+
+ @Before
+ public void setup() {
+ Utils.initializeRESTAssured();
+ this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
+ this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
+ this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
+ this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec);
+ this.savingsProductHelper = new SavingsProductHelper();
+ }
+
+ @Test
+ public void testSavingsInterestPostingAtPeriodEnd() {
+ //client activation, savings activation and 1st transaction date
+ final String startDate = "01 December 2013";
+ final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, startDate);
+ Assert.assertNotNull(clientID);
+
+ // Configuring global config flags
+ configureInterestPosting(true, 4);
+
+ final Integer savingsId = createSavingsAccount(clientID, startDate);
+
+ Integer depositTransactionId = (Integer) this.savingsAccountHelper.depositToSavingsAccount(savingsId, "1000",
+ startDate, CommonConstants.RESPONSE_RESOURCE_ID);
+
+ /***
+ * Perform Post interest transaction and verify the posted transaction date
+ */
+ this.savingsAccountHelper.postInterestForSavings(savingsId);
+ HashMap accountDetails = this.savingsAccountHelper.getSavingsDetails(savingsId);
+ ArrayList> transactions = (ArrayList>)
+ accountDetails.get("transactions");
+ HashMap interestPostingTransaction = transactions.get(0);
+ for(Entry entry : interestPostingTransaction.entrySet())
+ System.out.println(entry.getKey() + "-" + entry.getValue().toString());
+ //1st Dec 13 to 31st March 14 - 365 days, daily compounding using daily balance
+ //33.7016 obtained from formula in excel provided by Subramanya
+ assertEquals("Equality check for interest posted amount",
+ "33.7016", interestPostingTransaction.get("amount").toString());
+ assertEquals("Date check for Interest Posting transaction",
+ "[2014, 3, 31]", interestPostingTransaction.get("date").toString());
+
+ }
+
+ private Integer createSavingsAccount(final Integer clientID, final String startDate) {
+ final Integer savingsProductID = createSavingsProduct();
+ Assert.assertNotNull(savingsProductID);
+ final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplicationOnDate(clientID,
+ savingsProductID, ACCOUNT_TYPE_INDIVIDUAL, startDate);
+ Assert.assertNotNull(savingsId);
+ HashMap savingsStatusHashMap = this.savingsAccountHelper.approveSavingsOnDate(savingsId, startDate);
+ SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap);
+ savingsStatusHashMap = this.savingsAccountHelper.activateSavingsAccount(savingsId, startDate);
+ SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap);
+ return savingsId;
+ }
+
+ private void configureInterestPosting(final Boolean periodEndEnable,
+ final Integer financialYearBeginningMonth) {
+ final ArrayList globalConfig = GlobalConfigurationHelper.getAllGlobalConfigurations(this.requestSpec,
+ this.responseSpec);
+ Assert.assertNotNull(globalConfig);
+
+ // Updating flag for interest posting at period end
+ Integer periodEndConfigId = (Integer) globalConfig.get(10).get("id");
+ Assert.assertNotNull(periodEndConfigId);
+
+ HashMap periodEndConfigData = GlobalConfigurationHelper.getGlobalConfigurationById(this.requestSpec, this.responseSpec,
+ periodEndConfigId.toString());
+ Assert.assertNotNull(periodEndConfigData);
+
+ Boolean enabled = (Boolean) globalConfig.get(10).get("enabled");
+
+ if (enabled != periodEndEnable)
+ periodEndConfigId = GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(this.requestSpec, this.responseSpec,
+ periodEndConfigId.toString(), periodEndEnable);
+
+
+ //Updating value for financial year beginning month
+ Integer financialYearBeginningConfigId = (Integer) globalConfig.get(11).get("id");
+ Assert.assertNotNull(financialYearBeginningConfigId);
+
+ HashMap financialYearBeginningConfigData = GlobalConfigurationHelper.getGlobalConfigurationById(this.requestSpec, this.responseSpec,
+ financialYearBeginningConfigId.toString());
+ Assert.assertNotNull(financialYearBeginningConfigData);
+
+ financialYearBeginningConfigId = GlobalConfigurationHelper.updateValueForGlobalConfiguration(this.requestSpec, this.responseSpec,
+ financialYearBeginningConfigId.toString(), financialYearBeginningMonth.toString());
+ Assert.assertNotNull(financialYearBeginningConfigId);
+ }
+
+ private Integer createSavingsProduct() {
+ final String savingsProductJSON = this.savingsProductHelper
+ .withInterestCompoundingPeriodTypeAsDaily()
+ .withInterestPostingPeriodTypeAsAnnual()
+ .withInterestCalculationPeriodTypeAsDailyBalance()
+ .build();
+ return SavingsProductHelper.createSavingsProduct(savingsProductJSON, requestSpec, responseSpec);
+ }
+
+ //Reset configuration fields
+ @After
+ public void tearDown() {
+ configureInterestPosting(false, 1);
+ }
+
+}
diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/savings/SavingsAccountHelper.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/savings/SavingsAccountHelper.java
index cbd2765fb..3d2345db5 100644
--- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/savings/SavingsAccountHelper.java
+++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/savings/SavingsAccountHelper.java
@@ -59,9 +59,14 @@ public class SavingsAccountHelper {
}
public Integer applyForSavingsApplication(final Integer ID, final Integer savingsProductID, final String accountType) {
- System.out.println("--------------------------------APPLYING FOR SAVINGS APPLICATION--------------------------------");
+ return applyForSavingsApplicationOnDate(ID, savingsProductID, accountType, CREATED_DATE);
+ }
+
+ public Integer applyForSavingsApplicationOnDate(final Integer ID, final Integer savingsProductID, final String accountType,
+ final String submittedOnDate) {
+ System.out.println("--------------------------------APPLYING FOR SAVINGS APPLICATION--------------------------------");
final String savingsApplicationJSON = new SavingsApplicationTestBuilder() //
- .withSubmittedOnDate(CREATED_DATE) //
+ .withSubmittedOnDate(submittedOnDate) //
.build(ID.toString(), savingsProductID.toString(), accountType);
return Utils.performServerPost(this.requestSpec, this.responseSpec, SAVINGS_ACCOUNT_URL + "?" + Utils.TENANT_IDENTIFIER,
savingsApplicationJSON, "savingsId");
@@ -77,8 +82,15 @@ public class SavingsAccountHelper {
}
public HashMap approveSavings(final Integer savingsID) {
- System.out.println("--------------------------------- APPROVING SAVINGS APPLICATION ------------------------------------");
- return performSavingApplicationActions(createSavingsOperationURL(APPROVE_SAVINGS_COMMAND, savingsID), getApproveSavingsAsJSON());
+ return approveSavingsOnDate(savingsID, null);
+ }
+
+ public HashMap approveSavingsOnDate(final Integer savingsID, final String approvalDate) {
+ System.out.println("--------------------------------- APPROVING SAVINGS APPLICATION ------------------------------------");
+ final String savingsOperationURL = createSavingsOperationURL(APPROVE_SAVINGS_COMMAND, savingsID);
+ if(approvalDate == null || approvalDate == "")
+ return performSavingApplicationActions(savingsOperationURL, getApproveSavingsAsJSON());
+ return performSavingApplicationActions(savingsOperationURL, getApproveSavingsAsJsonOnDate(approvalDate));
}
public HashMap undoApproval(final Integer savingsID) {
@@ -185,10 +197,14 @@ public class SavingsAccountHelper {
}
private String getApproveSavingsAsJSON() {
- final HashMap map = new HashMap<>();
+ return getApproveSavingsAsJsonOnDate(CREATED_DATE_PLUS_ONE);
+ }
+
+ private String getApproveSavingsAsJsonOnDate(final String approvalDate) {
+ final HashMap map = new HashMap<>();
map.put("locale", CommonConstants.locale);
map.put("dateFormat", CommonConstants.dateFormat);
- map.put("approvedOnDate", CREATED_DATE_PLUS_ONE);
+ map.put("approvedOnDate", approvalDate);
map.put("note", "Approval NOTE");
String savingsAccountApproveJson = new Gson().toJson(map);
System.out.println(savingsAccountApproveJson);
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/data/GlobalConfigurationPropertyData.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/data/GlobalConfigurationPropertyData.java
index 6d36cd9c7..c7da31a5c 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/data/GlobalConfigurationPropertyData.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/data/GlobalConfigurationPropertyData.java
@@ -18,18 +18,24 @@ public class GlobalConfigurationPropertyData {
private final Long value;
@SuppressWarnings("unused")
private final Long id;
+ @SuppressWarnings("unused")
+ private final String description;
- public GlobalConfigurationPropertyData(final String name, final boolean enabled, final Long value) {
+ public GlobalConfigurationPropertyData(final String name, final boolean enabled, final Long value,
+ final String description) {
this.name = name;
this.enabled = enabled;
this.value = value;
this.id = null;
+ this.description = description;
}
- public GlobalConfigurationPropertyData(final String name, final boolean enabled, final Long value, final Long id) {
+ public GlobalConfigurationPropertyData(final String name, final boolean enabled, final Long value,
+ final Long id, final String description) {
this.name = name;
this.enabled = enabled;
this.value = value;
this.id = id;
+ this.description = description;
}
}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainService.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainService.java
index 795d2912b..182b3cbf6 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainService.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainService.java
@@ -35,4 +35,8 @@ public interface ConfigurationDomainService {
Long retrieveGraceOnPenaltyPostingPeriod();
+ boolean isSavingsInterestPostingAtCurrentPeriodEnd();
+
+ Integer retrieveFinancialYearBeginningMonth();
+
}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
index 5e30959b1..3e48b0d73 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
@@ -135,5 +135,21 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName);
return property.getValue();
}
+
+ @Override
+ public boolean isSavingsInterestPostingAtCurrentPeriodEnd() {
+ final String propertyName = "savings-interest-posting-current-period-end";
+ final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName);
+ return property.isEnabled();
+ }
+
+ @Override
+ public Integer retrieveFinancialYearBeginningMonth() {
+ final String propertyName = "financial-year-beginning-month";
+ final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName);
+ if(property.isEnabled())
+ return property.getValue().intValue();
+ return 1;
+ }
}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/GlobalConfigurationProperty.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/GlobalConfigurationProperty.java
index dce9c075a..424f5ed63 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/GlobalConfigurationProperty.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/GlobalConfigurationProperty.java
@@ -27,17 +27,23 @@ public class GlobalConfigurationProperty extends AbstractPersistable {
@Column(name = "value", nullable = true)
private Long value;
+
+ @Column(name = "description", nullable = true)
+ private final String description;
protected GlobalConfigurationProperty() {
this.name = null;
this.enabled = false;
this.value = null;
+ this.description = null;
}
- public GlobalConfigurationProperty(final String name, final boolean enabled, final Long value) {
+ public GlobalConfigurationProperty(final String name, final boolean enabled, final Long value,
+ final String description) {
this.name = name;
this.enabled = enabled;
this.value = value;
+ this.description = description;
}
public boolean isEnabled() {
@@ -78,7 +84,7 @@ public class GlobalConfigurationProperty extends AbstractPersistable {
public static GlobalConfigurationProperty newSurveyConfiguration(final String name)
{
- return new GlobalConfigurationProperty(name,false,null);
+ return new GlobalConfigurationProperty(name, false, null, null);
}
}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/service/ConfigurationReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/service/ConfigurationReadPlatformServiceImpl.java
index 265bb75b3..d124443b6 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/service/ConfigurationReadPlatformServiceImpl.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/service/ConfigurationReadPlatformServiceImpl.java
@@ -39,7 +39,7 @@ public class ConfigurationReadPlatformServiceImpl implements ConfigurationReadPl
this.context.authenticatedUser();
- String sql = "SELECT c.id, c.name, c.enabled, c.value FROM c_configuration c ";
+ String sql = "SELECT c.id, c.name, c.enabled, c.value, c.description FROM c_configuration c ";
if(survey)
{
@@ -59,7 +59,8 @@ public class ConfigurationReadPlatformServiceImpl implements ConfigurationReadPl
this.context.authenticatedUser();
- final String sql = "SELECT c.id, c.name, c.enabled, c.value FROM c_configuration c where c.id=? order by c.id";
+ final String sql = "SELECT c.id, c.name, c.enabled, c.value, c.description FROM "
+ + "c_configuration c where c.id=? order by c.id";
final GlobalConfigurationPropertyData globalConfiguration = this.jdbcTemplate.queryForObject(sql, this.rm, new Object[] {configId});
return globalConfiguration;
@@ -76,9 +77,10 @@ public class ConfigurationReadPlatformServiceImpl implements ConfigurationReadPl
final String name = rs.getString("name");
final boolean enabled = rs.getBoolean("enabled");
final Long value = rs.getLong("value");
+ final String description = rs.getString("description");
final Long id = rs.getLong("id");
- return new GlobalConfigurationPropertyData(name, enabled, value, id);
+ return new GlobalConfigurationPropertyData(name, enabled, value, id, description);
}
}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/service/GlobalConfigurationWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/service/GlobalConfigurationWritePlatformServiceJpaRepositoryImpl.java
index ca3e6b950..4e1a1cdc3 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/service/GlobalConfigurationWritePlatformServiceJpaRepositoryImpl.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/service/GlobalConfigurationWritePlatformServiceJpaRepositoryImpl.java
@@ -50,7 +50,7 @@ public class GlobalConfigurationWritePlatformServiceJpaRepositoryImpl implements
this.globalConfigurationDataValidator.validateForUpdate(command);
final GlobalConfigurationProperty configItemForUpdate = this.repository.findOneWithNotFoundDetection(configId);
-
+
final Map changes = configItemForUpdate.update(command);
if (!changes.isEmpty()) {
@@ -66,7 +66,6 @@ public class GlobalConfigurationWritePlatformServiceJpaRepositoryImpl implements
}
-
@Transactional
@Override
public void addSurveyConfig(final String name)
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/DepositAccountDomainServiceJpa.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/DepositAccountDomainServiceJpa.java
index 31beb81bc..c6a1ba12f 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/DepositAccountDomainServiceJpa.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/DepositAccountDomainServiceJpa.java
@@ -20,6 +20,7 @@ import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.mifosplatform.accounting.journalentry.service.JournalEntryWritePlatformService;
+import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.service.DateUtils;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
@@ -53,6 +54,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
private final DepositAccountAssembler depositAccountAssembler;
private final SavingsAccountDomainService savingsAccountDomainService;
private final AccountTransfersWritePlatformService accountTransfersWritePlatformService;
+ private final ConfigurationDomainService configurationDomainService;
@Autowired
public DepositAccountDomainServiceJpa(final SavingsAccountRepositoryWrapper savingsAccountRepository,
@@ -60,7 +62,8 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
final JournalEntryWritePlatformService journalEntryWritePlatformService,
final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory, final DepositAccountAssembler depositAccountAssembler,
final SavingsAccountDomainService savingsAccountDomainService,
- final AccountTransfersWritePlatformService accountTransfersWritePlatformService) {
+ final AccountTransfersWritePlatformService accountTransfersWritePlatformService,
+ final ConfigurationDomainService configurationDomainService) {
this.savingsAccountRepository = savingsAccountRepository;
this.applicationCurrencyRepositoryWrapper = applicationCurrencyRepositoryWrapper;
this.journalEntryWritePlatformService = journalEntryWritePlatformService;
@@ -68,6 +71,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
this.depositAccountAssembler = depositAccountAssembler;
this.savingsAccountDomainService = savingsAccountDomainService;
this.accountTransfersWritePlatformService = accountTransfersWritePlatformService;
+ this.configurationDomainService = configurationDomainService;
}
@Transactional
@@ -100,6 +104,12 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
public SavingsAccountTransaction handleRDDeposit(final RecurringDepositAccount account, final DateTimeFormatter fmt,
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail,
final boolean isRegularTransaction) {
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
+
boolean isAccountTransfer = false;
final boolean isPreMatureClosure = false;
final MathContext mc = MathContext.DECIMAL64;
@@ -107,7 +117,8 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction);
account.handleScheduleInstallments(deposit);
- account.updateMaturityDateAndAmount(mc, isPreMatureClosure);
+ account.updateMaturityDateAndAmount(mc, isPreMatureClosure,
+ isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
account.updateOverduePayments(DateUtils.getLocalDateOfTenant());
return deposit;
}
@@ -116,6 +127,12 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
@Override
public Long handleFDAccountClosure(final FixedDepositAccount account, final PaymentDetail paymentDetail, final AppUser user,
final JsonCommand command, final LocalDate tenantsTodayDate, final Map changes) {
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
+
boolean isRegularTransaction = false;
boolean isAccountTransfer = false;
final boolean isPreMatureClosure = false;
@@ -140,13 +157,15 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
final LocalDate closedDate = command.localDateValueOfParameterNamed(SavingsApiConstants.closedOnDateParamName);
Long savingsTransactionId = null;
- account.postMaturityInterest();
+ account.postMaturityInterest(isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
final Integer onAccountClosureId = command.integerValueOfParameterNamed(onAccountClosureIdParamName);
final DepositAccountOnClosureType onClosureType = DepositAccountOnClosureType.fromInt(onAccountClosureId);
if (onClosureType.isReinvest()) {
FixedDepositAccount reinvestedDeposit = account.reInvest(account.getAccountBalance());
this.depositAccountAssembler.assignSavingAccountHelpers(reinvestedDeposit);
- reinvestedDeposit.updateMaturityDateAndAmountBeforeAccountActivation(mc, isPreMatureClosure);
+ reinvestedDeposit.updateMaturityDateAndAmountBeforeAccountActivation(mc, isPreMatureClosure,
+ isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
this.savingsAccountRepository.save(reinvestedDeposit);
autoGenerateAccountNumber(reinvestedDeposit);
final SavingsAccountTransaction withdrawal = this.handleWithdrawal(account, fmt, closedDate, account.getAccountBalance(),
@@ -185,6 +204,12 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
@Override
public Long handleRDAccountClosure(final RecurringDepositAccount account, final PaymentDetail paymentDetail, final AppUser user,
final JsonCommand command, final LocalDate tenantsTodayDate, final Map changes) {
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
+
boolean isRegularTransaction = false;
boolean isAccountTransfer = false;
final boolean isPreMatureClosure = false;
@@ -197,16 +222,19 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
final LocalDate closedDate = command.localDateValueOfParameterNamed(SavingsApiConstants.closedOnDateParamName);
Long savingsTransactionId = null;
- account.postMaturityInterest();
+ account.postMaturityInterest(isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
final BigDecimal transactionAmount = account.getAccountBalance();
final Integer onAccountClosureId = command.integerValueOfParameterNamed(onAccountClosureIdParamName);
final DepositAccountOnClosureType onClosureType = DepositAccountOnClosureType.fromInt(onAccountClosureId);
if (onClosureType.isReinvest()) {
RecurringDepositAccount reinvestedDeposit = account.reInvest(transactionAmount);
depositAccountAssembler.assignSavingAccountHelpers(reinvestedDeposit);
- reinvestedDeposit.updateMaturityDateAndAmount(mc, isPreMatureClosure);
+ reinvestedDeposit.updateMaturityDateAndAmount(mc, isPreMatureClosure,
+ isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
reinvestedDeposit.processAccountUponActivation(fmt);
- reinvestedDeposit.updateMaturityDateAndAmount(mc, isPreMatureClosure);
+ reinvestedDeposit.updateMaturityDateAndAmount(mc, isPreMatureClosure,
+ isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
this.savingsAccountRepository.save(reinvestedDeposit);
Money amountForDeposit = reinvestedDeposit.activateWithBalance();
@@ -214,7 +242,8 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
handleRDDeposit(reinvestedDeposit, fmt, reinvestedDeposit.getActivationLocalDate(), amountForDeposit.getAmount(),
paymentDetail, isRegularTransaction);
}
- reinvestedDeposit.updateMaturityDateAndAmount(mc, isPreMatureClosure);
+ reinvestedDeposit.updateMaturityDateAndAmount(mc, isPreMatureClosure,
+ isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
this.savingsAccountRepository.save(reinvestedDeposit);
autoGenerateAccountNumber(reinvestedDeposit);
@@ -265,6 +294,12 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
@Override
public Long handleFDAccountPreMatureClosure(final FixedDepositAccount account, final PaymentDetail paymentDetail, final AppUser user,
final JsonCommand command, final LocalDate tenantsTodayDate, final Map changes) {
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
+
boolean isAccountTransfer = false;
boolean isRegularTransaction = false;
final boolean isPreMatureClosure = true;
@@ -277,7 +312,8 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
Long savingsTransactionId = null;
// post interest
- account.postPreMaturityInterest(closedDate, isPreMatureClosure);
+ account.postPreMaturityInterest(closedDate, isPreMatureClosure,
+ isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
final Integer closureTypeValue = command.integerValueOfParameterNamed(DepositsApiConstants.onAccountClosureIdParamName);
DepositAccountOnClosureType closureType = DepositAccountOnClosureType.fromInt(closureTypeValue);
@@ -315,7 +351,13 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
@Override
public Long handleRDAccountPreMatureClosure(final RecurringDepositAccount account, final PaymentDetail paymentDetail,
final AppUser user, final JsonCommand command, final LocalDate tenantsTodayDate, final Map changes) {
- boolean isAccountTransfer = false;
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
+
+ boolean isAccountTransfer = false;
final boolean isPreMatureClosure = true;
boolean isRegularTransaction = false;
final Set existingTransactionIds = new HashSet<>();
@@ -327,7 +369,8 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
Long savingsTransactionId = null;
// post interest
- account.postPreMaturityInterest(closedDate, isPreMatureClosure);
+ account.postPreMaturityInterest(closedDate, isPreMatureClosure,
+ isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
final Integer closureTypeValue = command.integerValueOfParameterNamed(DepositsApiConstants.onAccountClosureIdParamName);
DepositAccountOnClosureType closureType = DepositAccountOnClosureType.fromInt(closureTypeValue);
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/FixedDepositAccount.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/FixedDepositAccount.java
index 4c5a53536..6f963aac0 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/FixedDepositAccount.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/FixedDepositAccount.java
@@ -174,7 +174,9 @@ public class FixedDepositAccount extends SavingsAccount {
return applicableInterestRate.divide(BigDecimal.valueOf(100l), mc);
}
- public void updateMaturityDateAndAmountBeforeAccountActivation(final MathContext mc, final boolean isPreMatureClosure) {
+ public void updateMaturityDateAndAmountBeforeAccountActivation(final MathContext mc,
+ final boolean isPreMatureClosure, final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
+ final Integer financialYearBeginningMonth) {
List allTransactions = new ArrayList<>();
final Money transactionAmountMoney = Money.of(getCurrency(), this.accountTermAndPreClosure.depositAmount());
final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(null, office(), null,
@@ -182,15 +184,20 @@ public class FixedDepositAccount extends SavingsAccount {
transaction.updateRunningBalance(transactionAmountMoney);
transaction.updateCumulativeBalanceAndDates(this.getCurrency(), interestCalculatedUpto());
allTransactions.add(transaction);
- updateMaturityDateAndAmount(mc, allTransactions, isPreMatureClosure);
+ updateMaturityDateAndAmount(mc, allTransactions, isPreMatureClosure,
+ isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
}
- public void updateMaturityDateAndAmount(final MathContext mc, final boolean isPreMatureClosure) {
- updateMaturityDateAndAmount(mc, retreiveOrderedNonInterestPostingTransactions(), isPreMatureClosure);
+ public void updateMaturityDateAndAmount(final MathContext mc, final boolean isPreMatureClosure,
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
+ final Integer financialYearBeginningMonth) {
+ updateMaturityDateAndAmount(mc, retreiveOrderedNonInterestPostingTransactions(), isPreMatureClosure,
+ isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
}
public void updateMaturityDateAndAmount(final MathContext mc, final List transactions,
- final boolean isPreMatureClosure) {
+ final boolean isPreMatureClosure, final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
+ final Integer financialYearBeginningMonth) {
final LocalDate maturityDate = calculateMaturityDate();
final LocalDate interestCalculationUpto = maturityDate.minusDays(1);
@@ -198,7 +205,9 @@ public class FixedDepositAccount extends SavingsAccount {
// calculation
this.resetAccountTransactionsEndOfDayBalances(transactions, maturityDate);
- final List postingPeriods = calculateInterestPayable(mc, interestCalculationUpto, transactions, isPreMatureClosure);
+ final List postingPeriods = calculateInterestPayable(mc, interestCalculationUpto,
+ transactions, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
// reset end of day balance back to today's date
this.resetAccountTransactionsEndOfDayBalances(transactions, DateUtils.getLocalDateOfTenant());
@@ -213,7 +222,8 @@ public class FixedDepositAccount extends SavingsAccount {
this.accountTermAndPreClosure.updateMaturityDetails(maturityAmount.getAmount(), maturityDate);
}
- public void updateMaturityStatus() {
+ public void updateMaturityStatus(final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
+ final Integer financialYearBeginningMonth) {
final List dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(FIXED_DEPOSIT_ACCOUNT_RESOURCE_NAME + SavingsApiConstants.updateMaturityDetailsAction);
@@ -228,7 +238,8 @@ public class FixedDepositAccount extends SavingsAccount {
if (!this.maturityDate().isAfter(todayDate)) {
// update account status
this.status = SavingsAccountStatusType.MATURED.getValue();
- postMaturityInterest();
+ postMaturityInterest(isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
}
}
@@ -258,7 +269,9 @@ public class FixedDepositAccount extends SavingsAccount {
}
private List calculateInterestPayable(final MathContext mc, final LocalDate maturityDate,
- final List transactions, final boolean isPreMatureClosure) {
+ final List transactions, final boolean isPreMatureClosure,
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
+ final Integer financialYearBeginningMonth) {
final SavingsPostingInterestPeriodType postingPeriodType = SavingsPostingInterestPeriodType.fromInt(this.interestPostingPeriodType);
@@ -269,7 +282,8 @@ public class FixedDepositAccount extends SavingsAccount {
.fromInt(this.interestCalculationDaysInYearType);
final List postingPeriodIntervals = this.savingsHelper.determineInterestPostingPeriods(
- accountSubmittedOrActivationDate(), maturityDate, postingPeriodType);
+ accountSubmittedOrActivationDate(), maturityDate, postingPeriodType,
+ financialYearBeginningMonth);
final List allPostingPeriods = new ArrayList<>();
@@ -284,7 +298,8 @@ public class FixedDepositAccount extends SavingsAccount {
final PostingPeriod postingPeriod = PostingPeriod.createFrom(periodInterval, periodStartingBalance, transactions,
this.currency, compoundingPeriodType, interestCalculationType, interestRateAsFraction, daysInYearType.getValue(),
- maturityDate, interestPostTransactions, isInterestTransfer, minBalanceForInterestCalculation);
+ maturityDate, interestPostTransactions, isInterestTransfer, minBalanceForInterestCalculation,
+ isSavingsInterestPostingAtCurrentPeriodEnd);
periodStartingBalance = postingPeriod.closingBalance();
@@ -455,11 +470,14 @@ public class FixedDepositAccount extends SavingsAccount {
// this.savingsAccountTransactionSummaryWrapper, this.transactions);
}
- public void postMaturityInterest() {
+ public void postMaturityInterest(final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
+ final Integer financialYearBeginningMonth) {
final LocalDate interestPostingUpToDate = maturityDate();
final MathContext mc = MathContext.DECIMAL64;
final boolean isInterestTransfer = false;
- final List postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer);
+ final List postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate,
+ isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
Money interestPostedToDate = Money.zero(this.currency);
@@ -503,13 +521,17 @@ public class FixedDepositAccount extends SavingsAccount {
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
}
- public void postPreMaturityInterest(final LocalDate accountCloseDate, final boolean isPreMatureClosure) {
+ public void postPreMaturityInterest(final LocalDate accountCloseDate, final boolean isPreMatureClosure,
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
+ final Integer financialYearBeginningMonth) {
Money interestPostedToDate = totalInterestPosted();
// calculate interest before one day of closure date
final LocalDate interestCalculatedToDate = accountCloseDate.minusDays(1);
final Money interestOnMaturity = calculatePreMatureInterest(interestCalculatedToDate,
- retreiveOrderedNonInterestPostingTransactions(), isPreMatureClosure);
+ retreiveOrderedNonInterestPostingTransactions(), isPreMatureClosure,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
boolean recalucateDailyBalance = false;
// post remaining interest
@@ -531,12 +553,15 @@ public class FixedDepositAccount extends SavingsAccount {
}
- public BigDecimal calculatePreMatureAmount(final LocalDate preMatureDate, final boolean isPreMatureClosure) {
+ public BigDecimal calculatePreMatureAmount(final LocalDate preMatureDate, final boolean isPreMatureClosure,
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
+ final Integer financialYearBeginningMonth) {
final Money interestPostedToDate = totalInterestPosted().copy();
final Money interestEarnedTillDate = calculatePreMatureInterest(preMatureDate, retreiveOrderedNonInterestPostingTransactions(),
- isPreMatureClosure);
+ isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
final Money accountBalance = Money.of(getCurrency(), getAccountBalance());
final Money maturityAmount = accountBalance.minus(interestPostedToDate).plus(interestEarnedTillDate);
@@ -545,9 +570,12 @@ public class FixedDepositAccount extends SavingsAccount {
}
private Money calculatePreMatureInterest(final LocalDate preMatureDate, final List transactions,
- final boolean isPreMatureClosure) {
+ final boolean isPreMatureClosure, final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
+ final Integer financialYearBeginningMonth) {
final MathContext mc = MathContext.DECIMAL64;
- final List postingPeriods = calculateInterestPayable(mc, preMatureDate, transactions, isPreMatureClosure);
+ final List postingPeriods = calculateInterestPayable(mc, preMatureDate, transactions,
+ isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
Money interestOnMaturity = Money.zero(this.currency);
@@ -560,15 +588,23 @@ public class FixedDepositAccount extends SavingsAccount {
}
@Override
- public void postInterest(final MathContext mc, final LocalDate postingDate, boolean isInterestTransfer) {
+ public void postInterest(final MathContext mc, final LocalDate postingDate, boolean isInterestTransfer,
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
+ final Integer financialYearBeginningMonth) {
final LocalDate interestPostingUpToDate = interestPostingUpToDate(postingDate);
- super.postInterest(mc, interestPostingUpToDate, isInterestTransfer);
- }
+ super.postInterest(mc, interestPostingUpToDate, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
+ }
@Override
- public List calculateInterestUsing(final MathContext mc, final LocalDate postingDate, boolean isInterestTransfer) {
+ public List calculateInterestUsing(final MathContext mc, final LocalDate postingDate,
+ boolean isInterestTransfer, final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
+ final Integer financialYearBeginningMonth) {
final LocalDate interestPostingUpToDate = interestPostingUpToDate(postingDate);
- return super.calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer);
+ return super.calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
}
private LocalDate interestPostingUpToDate(final LocalDate interestPostingDate) {
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/RecurringDepositAccount.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/RecurringDepositAccount.java
index 326d38692..d17b89b4a 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/RecurringDepositAccount.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/RecurringDepositAccount.java
@@ -206,13 +206,16 @@ public class RecurringDepositAccount extends SavingsAccount {
return applicableInterestRate.divide(BigDecimal.valueOf(100l), mc);
}
- public void updateMaturityDateAndAmount(final MathContext mc, final boolean isPreMatureClosure) {
+ public void updateMaturityDateAndAmount(final MathContext mc, final boolean isPreMatureClosure,
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
+ final Integer financialYearBeginningMonth) {
final LocalDate maturityDate = calculateMaturityDate();
final LocalDate interestCalculationUpto = maturityDate.minusDays(1);
final List allTransactions = generateIncludingFutureTransactions(interestCalculationUpto);
final List postingPeriods = calculateInterestPayable(mc, interestCalculationUpto, allTransactions,
- isPreMatureClosure);
+ isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
Money totalInterestPayable = Money.zero(getCurrency());
Money totalDepositAmount = Money.zero(getCurrency());
for (PostingPeriod postingPeriod : postingPeriods) {
@@ -223,7 +226,8 @@ public class RecurringDepositAccount extends SavingsAccount {
this.accountTermAndPreClosure.updateMaturityDetails(totalDepositAmount.getAmount(), totalInterestPayable.getAmount(), maturityDate);
}
- public void updateMaturityStatus() {
+ public void updateMaturityStatus(final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
+ final Integer financialYearBeginningMonth) {
final List dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(RECURRING_DEPOSIT_ACCOUNT_RESOURCE_NAME + SavingsApiConstants.updateMaturityDetailsAction);
@@ -238,7 +242,8 @@ public class RecurringDepositAccount extends SavingsAccount {
if (!this.maturityDate().isAfter(todayDate)) {
// update account status
this.status = SavingsAccountStatusType.MATURED.getValue();
- postMaturityInterest();
+ postMaturityInterest(isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
}
}
@@ -268,7 +273,9 @@ public class RecurringDepositAccount extends SavingsAccount {
}
private List calculateInterestPayable(final MathContext mc, final LocalDate maturityDate,
- final List transactions, final boolean isPreMatureClosure) {
+ final List transactions, final boolean isPreMatureClosure,
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
+ final Integer financialYearBeginningMonth) {
// 1. default to calculate interest based on entire history OR
// 2. determine latest 'posting period' and find interest credited to
@@ -284,7 +291,7 @@ public class RecurringDepositAccount extends SavingsAccount {
.fromInt(this.interestCalculationDaysInYearType);
final List postingPeriodIntervals = this.savingsHelper.determineInterestPostingPeriods(depositStartDate(),
- maturityDate, postingPeriodType);
+ maturityDate, postingPeriodType, financialYearBeginningMonth);
final List allPostingPeriods = new ArrayList<>();
@@ -298,7 +305,8 @@ public class RecurringDepositAccount extends SavingsAccount {
for (final LocalDateInterval periodInterval : postingPeriodIntervals) {
final PostingPeriod postingPeriod = PostingPeriod.createFrom(periodInterval, periodStartingBalance, transactions,
this.currency, compoundingPeriodType, interestCalculationType, interestRateAsFraction, daysInYearType.getValue(),
- maturityDate, interestPostTransactions, isInterestTransfer, minBalanceForInterestCalculation);
+ maturityDate, interestPostTransactions, isInterestTransfer, minBalanceForInterestCalculation,
+ isSavingsInterestPostingAtCurrentPeriodEnd);
periodStartingBalance = postingPeriod.closingBalance();
@@ -560,11 +568,14 @@ public class RecurringDepositAccount extends SavingsAccount {
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
}
- public void postMaturityInterest() {
+ public void postMaturityInterest(final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
+ final Integer financialYearBeginningMonth) {
final LocalDate interestPostingUpToDate = maturityDate();
final MathContext mc = MathContext.DECIMAL64;
boolean isInterestTransfer = false;
- final List postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer);
+ final List postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate,
+ isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
Money interestPostedToDate = Money.zero(this.currency);
@@ -606,13 +617,17 @@ public class RecurringDepositAccount extends SavingsAccount {
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
}
- public void postPreMaturityInterest(final LocalDate accountCloseDate, final boolean isPreMatureClosure) {
+ public void postPreMaturityInterest(final LocalDate accountCloseDate, final boolean isPreMatureClosure,
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
+ final Integer financialYearBeginningMonth) {
final Money interestPostedToDate = totalInterestPosted();
// calculate interest before one day of closure date
final LocalDate interestCalculatedToDate = accountCloseDate.minusDays(1);
final Money interestOnMaturity = calculatePreMatureInterest(interestCalculatedToDate,
- retreiveOrderedNonInterestPostingTransactions(), isPreMatureClosure);
+ retreiveOrderedNonInterestPostingTransactions(), isPreMatureClosure,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
boolean recalucateDailyBalance = false;
@@ -635,12 +650,15 @@ public class RecurringDepositAccount extends SavingsAccount {
this.accountTermAndPreClosure.updateMaturityDetails(this.getAccountBalance(), accountCloseDate);
}
- public BigDecimal calculatePreMatureAmount(final LocalDate preMatureDate, final boolean isPreMatureClosure) {
+ public BigDecimal calculatePreMatureAmount(final LocalDate preMatureDate, final boolean isPreMatureClosure,
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
+ final Integer financialYearBeginningMonth) {
final Money interestPostedToDate = totalInterestPosted().copy();
final Money interestEarnedTillDate = calculatePreMatureInterest(preMatureDate, retreiveOrderedNonInterestPostingTransactions(),
- isPreMatureClosure);
+ isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
final Money accountBalance = Money.of(getCurrency(), getAccountBalance());
final Money maturityAmount = accountBalance.minus(interestPostedToDate).plus(interestEarnedTillDate);
@@ -649,9 +667,12 @@ public class RecurringDepositAccount extends SavingsAccount {
}
private Money calculatePreMatureInterest(final LocalDate preMatureDate, final List transactions,
- final boolean isPreMatureClosure) {
+ final boolean isPreMatureClosure, final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
+ final Integer financialYearBeginningMonth) {
final MathContext mc = MathContext.DECIMAL64;
- final List postingPeriods = calculateInterestPayable(mc, preMatureDate, transactions, isPreMatureClosure);
+ final List postingPeriods = calculateInterestPayable(mc, preMatureDate, transactions,
+ isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
Money interestOnMaturity = Money.zero(this.currency);
@@ -664,15 +685,20 @@ public class RecurringDepositAccount extends SavingsAccount {
}
@Override
- public void postInterest(final MathContext mc, final LocalDate postingDate, final boolean isInterestTransfer) {
+ public void postInterest(final MathContext mc, final LocalDate postingDate, final boolean isInterestTransfer,
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth) {
final LocalDate interestPostingUpToDate = interestPostingUpToDate(postingDate);
- super.postInterest(mc, interestPostingUpToDate, isInterestTransfer);
+ super.postInterest(mc, interestPostingUpToDate, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
}
@Override
- public List calculateInterestUsing(final MathContext mc, final LocalDate postingDate, boolean isInterestTransfer) {
+ public List calculateInterestUsing(final MathContext mc, final LocalDate postingDate,
+ boolean isInterestTransfer, final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
+ final Integer financialYearBeginningMonth) {
final LocalDate interestPostingUpToDate = interestPostingUpToDate(postingDate);
- return super.calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer);
+ return super.calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
}
private LocalDate interestPostingUpToDate(final LocalDate interestPostingDate) {
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java
index 07f818b73..438060f3e 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java
@@ -417,9 +417,14 @@ public class SavingsAccount extends AbstractPersistable {
return SavingsAccountStatusType.fromInt(this.status).isClosed();
}
- public void postInterest(final MathContext mc, final LocalDate interestPostingUpToDate, final boolean isInterestTransfer) {
+ public void postInterest(final MathContext mc,
+ final LocalDate interestPostingUpToDate,
+ final boolean isInterestTransfer,
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
+ final Integer financialYearBeginningMonth) {
- final List postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer);
+ final List postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
Money interestPostedToDate = Money.zero(this.currency);
@@ -514,7 +519,8 @@ public class SavingsAccount extends AbstractPersistable {
* TODO
*/
public List calculateInterestUsing(final MathContext mc, final LocalDate upToInterestCalculationDate,
- boolean isInterestTransfer) {
+ boolean isInterestTransfer, final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
+ final Integer financialYearBeginningMonth) {
// no openingBalance concept supported yet but probably will to allow
// for migrations.
@@ -538,7 +544,8 @@ public class SavingsAccount extends AbstractPersistable {
.fromInt(this.interestCalculationDaysInYearType);
final List postingPeriodIntervals = this.savingsHelper.determineInterestPostingPeriods(
- getStartInterestCalculationDate(), upToInterestCalculationDate, postingPeriodType);
+ getStartInterestCalculationDate(), upToInterestCalculationDate, postingPeriodType,
+ financialYearBeginningMonth);
final List allPostingPeriods = new ArrayList<>();
@@ -576,7 +583,7 @@ public class SavingsAccount extends AbstractPersistable {
final PostingPeriod postingPeriod = PostingPeriod.createFrom(periodInterval, periodStartingBalance,
retreiveOrderedNonInterestPostingTransactions(), this.currency, compoundingPeriodType, interestCalculationType,
interestRateAsFraction, daysInYearType.getValue(), upToInterestCalculationDate, interestPostTransactions,
- isInterestTransfer, minBalanceForInterestCalculation);
+ isInterestTransfer, minBalanceForInterestCalculation, isSavingsInterestPostingAtCurrentPeriodEnd);
periodStartingBalance = postingPeriod.closingBalance();
@@ -1825,7 +1832,9 @@ public class SavingsAccount extends AbstractPersistable {
return actualChanges;
}
- public void processAccountUponActivation() {
+ public void processAccountUponActivation(
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
+ final Integer financialYearBeginningMonth) {
// update annual fee due date
for (SavingsAccountCharge charge : this.charges()) {
@@ -1833,7 +1842,8 @@ public class SavingsAccount extends AbstractPersistable {
}
// auto pay the activation time charges
- this.payActivationCharges();
+ this.payActivationCharges(isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
// TODO : AA add activation charges to actual changes list
}
@@ -1856,7 +1866,8 @@ public class SavingsAccount extends AbstractPersistable {
this.lockedInUntilDate = calculateDateAccountIsLockedUntil(getActivationLocalDate());
}
- private void payActivationCharges() {
+ private void payActivationCharges(final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
+ final Integer financialYearBeginningMonth) {
boolean isSavingsChargeApplied = false;
for (SavingsAccountCharge savingsAccountCharge : this.charges()) {
if (savingsAccountCharge.isSavingsActivation()) {
@@ -1870,10 +1881,12 @@ public class SavingsAccount extends AbstractPersistable {
boolean isInterestTransfer = false;
if (this.isBeforeLastPostingPeriod(getActivationLocalDate())) {
final LocalDate today = DateUtils.getLocalDateOfTenant();
- this.postInterest(mc, today, isInterestTransfer);
+ this.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
} else {
final LocalDate today = DateUtils.getLocalDateOfTenant();
- this.calculateInterestUsing(mc, today, isInterestTransfer);
+ this.calculateInterestUsing(mc, today, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
}
}
}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java
index 894deae32..321154b9b 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java
@@ -15,6 +15,7 @@ import java.util.Set;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormatter;
import org.mifosplatform.accounting.journalentry.service.JournalEntryWritePlatformService;
+import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
import org.mifosplatform.infrastructure.core.service.DateUtils;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
@@ -34,16 +35,19 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
private final SavingsAccountTransactionRepository savingsAccountTransactionRepository;
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper;
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
+ private final ConfigurationDomainService configurationDomainService;
@Autowired
public SavingsAccountDomainServiceJpa(final SavingsAccountRepositoryWrapper savingsAccountRepository,
final SavingsAccountTransactionRepository savingsAccountTransactionRepository,
final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper,
- final JournalEntryWritePlatformService journalEntryWritePlatformService) {
+ final JournalEntryWritePlatformService journalEntryWritePlatformService,
+ final ConfigurationDomainService configurationDomainService) {
this.savingsAccountRepository = savingsAccountRepository;
this.savingsAccountTransactionRepository = savingsAccountTransactionRepository;
this.applicationCurrencyRepositoryWrapper = applicationCurrencyRepositoryWrapper;
this.journalEntryWritePlatformService = journalEntryWritePlatformService;
+ this.configurationDomainService = configurationDomainService;
}
@Transactional
@@ -51,6 +55,11 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
public SavingsAccountTransaction handleWithdrawal(final SavingsAccount account, final DateTimeFormatter fmt,
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail,
final SavingsTransactionBooleanValues transactionBooleanValues) {
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
if (transactionBooleanValues.isRegularTransaction() && !account.allowWithdrawal()) { throw new DepositAccountTransactionNotAllowedException(
account.getId(), "withdraw", account.depositAccountType()); }
@@ -64,10 +73,14 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
final MathContext mc = MathContext.DECIMAL64;
if (account.isBeforeLastPostingPeriod(transactionDate)) {
final LocalDate today = DateUtils.getLocalDateOfTenant();
- account.postInterest(mc, today, transactionBooleanValues.isInterestTransfer());
+ account.postInterest(mc, today, transactionBooleanValues.isInterestTransfer(),
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
} else {
final LocalDate today = DateUtils.getLocalDateOfTenant();
- account.calculateInterestUsing(mc, today, transactionBooleanValues.isInterestTransfer());
+ account.calculateInterestUsing(mc, today, transactionBooleanValues.isInterestTransfer(),
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
}
account.validateAccountBalanceDoesNotBecomeNegative(transactionAmount, transactionBooleanValues.isWithdrawBalance());
saveTransactionToGenerateTransactionId(withdrawal);
@@ -83,6 +96,11 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
public SavingsAccountTransaction handleDeposit(final SavingsAccount account, final DateTimeFormatter fmt,
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail,
final boolean isAccountTransfer, final boolean isRegularTransaction) {
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
if (isRegularTransaction && !account.allowDeposit()) { throw new DepositAccountTransactionNotAllowedException(account.getId(),
"deposit", account.depositAccountType()); }
@@ -98,10 +116,13 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
final MathContext mc = MathContext.DECIMAL64;
if (account.isBeforeLastPostingPeriod(transactionDate)) {
final LocalDate today = DateUtils.getLocalDateOfTenant();
- account.postInterest(mc, today, isInterestTransfer);
+ account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
} else {
final LocalDate today = DateUtils.getLocalDateOfTenant();
- account.calculateInterestUsing(mc, today, isInterestTransfer);
+ account.calculateInterestUsing(mc, today, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
}
saveTransactionToGenerateTransactionId(deposit);
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsHelper.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsHelper.java
index 1701477af..df2d493c0 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsHelper.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsHelper.java
@@ -7,9 +7,9 @@ package org.mifosplatform.portfolio.savings.domain;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
-import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.domain.LocalDateInterval;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
@@ -30,7 +30,8 @@ public final class SavingsHelper {
private final CompoundInterestHelper compoundInterestHelper = new CompoundInterestHelper();
public List determineInterestPostingPeriods(final LocalDate startInterestCalculationLocalDate,
- final LocalDate interestPostingUpToDate, final SavingsPostingInterestPeriodType postingPeriodType) {
+ final LocalDate interestPostingUpToDate, final SavingsPostingInterestPeriodType postingPeriodType,
+ final Integer financialYearBeginningMonth) {
final List postingPeriods = new ArrayList<>();
@@ -40,14 +41,10 @@ public final class SavingsHelper {
while (!periodStartDate.isAfter(interestPostingUpToDate) && !periodEndDate.isAfter(interestPostingUpToDate)) {
final LocalDate interestPostingLocalDate = determineInterestPostingPeriodEndDateFrom(periodStartDate, postingPeriodType,
- interestPostingUpToDate);
+ interestPostingUpToDate, financialYearBeginningMonth);
periodEndDate = interestPostingLocalDate.minusDays(1);
- if (!interestPostingLocalDate.isAfter(interestPostingUpToDate)) {
- postingPeriods.add(LocalDateInterval.create(periodStartDate, periodEndDate));
- } else {
- postingPeriods.add(LocalDateInterval.create(periodStartDate, periodEndDate));
- }
+ postingPeriods.add(LocalDateInterval.create(periodStartDate, periodEndDate));
periodEndDate = interestPostingLocalDate;
periodStartDate = interestPostingLocalDate;
@@ -57,46 +54,76 @@ public final class SavingsHelper {
}
private LocalDate determineInterestPostingPeriodEndDateFrom(final LocalDate periodStartDate,
- final SavingsPostingInterestPeriodType interestPostingPeriodType, final LocalDate interestPostingUpToDate) {
+ final SavingsPostingInterestPeriodType interestPostingPeriodType, final LocalDate interestPostingUpToDate,
+ Integer financialYearBeginningMonth) {
LocalDate periodEndDate = interestPostingUpToDate;
-
- switch (interestPostingPeriodType) {
- case INVALID:
- break;
- case MONTHLY:
- // produce period end date on last day of current month
- periodEndDate = periodStartDate.dayOfMonth().withMaximumValue();
- break;
- case QUATERLY:
- // jan 1st to mar 31st, 1st apr to jun 30, jul 1st to sept 30,
- // oct 1st to dec 31
- final int year = periodStartDate.getYearOfEra();
- final int monthofYear = periodStartDate.getMonthOfYear();
- if (monthofYear <= 3) {
- periodEndDate = new DateTime().withDate(year, 3, 31).toLocalDate();
- } else if (monthofYear <= 6) {
- periodEndDate = new DateTime().withDate(year, 6, 30).toLocalDate();
- } else if (monthofYear <= 9) {
- periodEndDate = new DateTime().withDate(year, 9, 30).toLocalDate();
- } else if (monthofYear <= 12) {
- periodEndDate = new DateTime().withDate(year, 12, 31).toLocalDate();
- }
- break;
- case BIANNUAL:
- final int byear = periodStartDate.getYearOfEra();
- final int bmonthofYear = periodStartDate.getMonthOfYear();
- if (bmonthofYear <= 6) {
- periodEndDate = new DateTime().withDate(byear, 6, 30).toLocalDate();
- } else if (bmonthofYear <= 12) {
- periodEndDate = new DateTime().withDate(byear, 12, 31).toLocalDate();
- }
- break;
- case ANNUAL:
- periodEndDate = periodStartDate.monthOfYear().withMaximumValue();
- periodEndDate = periodEndDate.dayOfMonth().withMaximumValue();
- break;
- }
+ final Integer monthOfYear = periodStartDate.getMonthOfYear();
+ financialYearBeginningMonth--;
+ if(financialYearBeginningMonth == 0)
+ financialYearBeginningMonth = 12;
+
+ final ArrayList quarterlyDates = new ArrayList<>();
+ quarterlyDates.add(periodStartDate.withMonthOfYear(financialYearBeginningMonth).dayOfMonth().withMaximumValue());
+ quarterlyDates.add(periodStartDate.withMonthOfYear(financialYearBeginningMonth)
+ .plusMonths(3).withYear(periodStartDate.getYear()).dayOfMonth().withMaximumValue());
+ quarterlyDates.add(periodStartDate.withMonthOfYear(financialYearBeginningMonth)
+ .plusMonths(6).withYear(periodStartDate.getYear()).dayOfMonth().withMaximumValue());
+ quarterlyDates.add(periodStartDate.withMonthOfYear(financialYearBeginningMonth)
+ .plusMonths(9).withYear(periodStartDate.getYear()).dayOfMonth().withMaximumValue());
+ Collections.sort(quarterlyDates);
+
+ final ArrayList biannualDates = new ArrayList<>();
+ biannualDates.add(periodStartDate.withMonthOfYear(financialYearBeginningMonth).dayOfMonth().withMaximumValue());
+ biannualDates.add(periodStartDate.withMonthOfYear(financialYearBeginningMonth).plusMonths(6)
+ .withYear(periodStartDate.getYear()).dayOfMonth().withMaximumValue());
+ Collections.sort(biannualDates);
+
+ boolean isEndDateSet = false;
+
+ switch (interestPostingPeriodType) {
+ case INVALID:
+ break;
+ case MONTHLY:
+ // produce period end date on last day of current month
+ periodEndDate = periodStartDate.dayOfMonth().withMaximumValue();
+ break;
+ case QUATERLY:
+ for(LocalDate quarterlyDate : quarterlyDates) {
+ if(quarterlyDate.isAfter(periodStartDate)) {
+ periodEndDate = quarterlyDate;
+ isEndDateSet = true;
+ break;
+ }
+ }
+
+ if(!isEndDateSet)
+ periodEndDate = quarterlyDates.get(0).plusYears(1).dayOfMonth().withMaximumValue();
+ break;
+ case BIANNUAL:
+ for(LocalDate biannualDate : biannualDates) {
+ if(biannualDate.isAfter(periodStartDate)) {
+ periodEndDate = biannualDate;
+ isEndDateSet = true;
+ break;
+ }
+ }
+
+ if(!isEndDateSet)
+ periodEndDate = biannualDates.get(0).plusYears(1).dayOfMonth().withMaximumValue();
+ break;
+ case ANNUAL:
+ if (financialYearBeginningMonth < monthOfYear) {
+ periodEndDate = periodStartDate
+ .withMonthOfYear(financialYearBeginningMonth);
+ periodEndDate = periodEndDate.plusYears(1);
+ } else {
+ periodEndDate = periodStartDate
+ .withMonthOfYear(financialYearBeginningMonth);
+ }
+ periodEndDate = periodEndDate.dayOfMonth().withMaximumValue();
+ break;
+ }
// interest posting always occurs on next day after the period end date.
periodEndDate = periodEndDate.plusDays(1);
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/interest/PostingPeriod.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/interest/PostingPeriod.java
index 6c531c6aa..92e6027c0 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/interest/PostingPeriod.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/interest/PostingPeriod.java
@@ -52,7 +52,7 @@ public class PostingPeriod {
final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType,
final SavingsInterestCalculationType interestCalculationType, final BigDecimal interestRateAsFraction, final long daysInYear,
final LocalDate upToInterestCalculationDate, Collection interestPostTransactions, boolean isInterestTransfer,
- final Money minBalanceForInterestCalculation) {
+ final Money minBalanceForInterestCalculation, final boolean isSavingsInterestPostingAtCurrentPeriodEnd) {
final List accountEndOfDayBalances = new ArrayList<>();
boolean interestTransfered = false;
@@ -113,13 +113,14 @@ public class PostingPeriod {
return new PostingPeriod(periodInterval, currency, periodStartingBalance, openingDayBalance, interestCompoundingPeriodType,
interestCalculationType, interestRateAsFraction, daysInYear, compoundingPeriods, interestTransfered,
- minBalanceForInterestCalculation);
+ minBalanceForInterestCalculation, isSavingsInterestPostingAtCurrentPeriodEnd);
}
private PostingPeriod(final LocalDateInterval periodInterval, final MonetaryCurrency currency, final Money openingBalance,
final Money closingBalance, final SavingsCompoundingInterestPeriodType interestCompoundingType,
final SavingsInterestCalculationType interestCalculationType, final BigDecimal interestRateAsFraction, final long daysInYear,
- final List compoundingPeriods, boolean interestTransfered, final Money minBalanceForInterestCalculation) {
+ final List compoundingPeriods, boolean interestTransfered, final Money minBalanceForInterestCalculation,
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd) {
this.periodInterval = periodInterval;
this.currency = currency;
this.openingBalance = openingBalance;
@@ -129,8 +130,11 @@ public class PostingPeriod {
this.interestRateAsFraction = interestRateAsFraction;
this.daysInYear = daysInYear;
this.compoundingPeriods = compoundingPeriods;
-
- this.dateOfPostingTransaction = periodInterval.endDate().plusDays(1);
+
+ if(isSavingsInterestPostingAtCurrentPeriodEnd)
+ this.dateOfPostingTransaction = periodInterval.endDate();
+ else
+ this.dateOfPostingTransaction = periodInterval.endDate().plusDays(1);
this.interestTransfered = interestTransfered;
this.minBalanceForInterestCalculation = minBalanceForInterestCalculation;
}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositAccountPreMatureCalculationPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositAccountPreMatureCalculationPlatformServiceImpl.java
index f0f2d3d1b..2eceba125 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositAccountPreMatureCalculationPlatformServiceImpl.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositAccountPreMatureCalculationPlatformServiceImpl.java
@@ -12,6 +12,7 @@ import java.util.Collection;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
import org.mifosplatform.infrastructure.codes.service.CodeValueReadPlatformService;
+import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
import org.mifosplatform.infrastructure.core.api.JsonQuery;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
@@ -41,17 +42,20 @@ public class DepositAccountPreMatureCalculationPlatformServiceImpl implements De
private final DepositAccountAssembler depositAccountAssembler;
private final CodeValueReadPlatformService codeValueReadPlatformService;
private final SavingsAccountReadPlatformService savingsAccountReadPlatformService;
+ private final ConfigurationDomainService configurationDomainService;
@Autowired
public DepositAccountPreMatureCalculationPlatformServiceImpl(final FromJsonHelper fromJsonHelper,
final DepositAccountTransactionDataValidator depositAccountTransactionDataValidator,
final DepositAccountAssembler depositAccountAssembler, final CodeValueReadPlatformService codeValueReadPlatformService,
- final SavingsAccountReadPlatformService savingsAccountReadPlatformService) {
+ final SavingsAccountReadPlatformService savingsAccountReadPlatformService,
+ final ConfigurationDomainService configurationDomainService) {
this.fromJsonHelper = fromJsonHelper;
this.depositAccountTransactionDataValidator = depositAccountTransactionDataValidator;
this.depositAccountAssembler = depositAccountAssembler;
this.codeValueReadPlatformService = codeValueReadPlatformService;
this.savingsAccountReadPlatformService = savingsAccountReadPlatformService;
+ this.configurationDomainService = configurationDomainService;
}
@@ -59,6 +63,12 @@ public class DepositAccountPreMatureCalculationPlatformServiceImpl implements De
@Override
public DepositAccountData calculatePreMatureAmount(final Long accountId, final JsonQuery query,
final DepositAccountType depositAccountType) {
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
+
this.depositAccountTransactionDataValidator.validatePreMatureAmountCalculation(query.json(), depositAccountType);
final SavingsAccount account = this.depositAccountAssembler.assembleFrom(accountId, depositAccountType);
@@ -79,13 +89,15 @@ public class DepositAccountPreMatureCalculationPlatformServiceImpl implements De
if (depositAccountType.isFixedDeposit()) {
final FixedDepositAccount fd = (FixedDepositAccount) account;
accountData = FixedDepositAccountData.preClosureDetails(account.getId(),
- fd.calculatePreMatureAmount(interestCalculatedToDate, isPreMatureClosure), onAccountClosureOptions, paymentTypeOptions,
- savingsAccountDatas);
+ fd.calculatePreMatureAmount(interestCalculatedToDate, isPreMatureClosure,
+ isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth),
+ onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas);
} else if (depositAccountType.isRecurringDeposit()) {
final RecurringDepositAccount rd = (RecurringDepositAccount) account;
accountData = RecurringDepositAccountData.preClosureDetails(account.getId(),
- rd.calculatePreMatureAmount(interestCalculatedToDate, isPreMatureClosure), onAccountClosureOptions, paymentTypeOptions,
- savingsAccountDatas);
+ rd.calculatePreMatureAmount(interestCalculatedToDate, isPreMatureClosure,
+ isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth),
+ onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas);
}
return accountData;
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java
index 9ab59196e..2a2ecb9ee 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java
@@ -27,6 +27,7 @@ import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.mifosplatform.accounting.journalentry.service.JournalEntryWritePlatformService;
+import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
@@ -121,6 +122,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
private final AccountTransfersWritePlatformService accountTransfersWritePlatformService;
private final DepositAccountReadPlatformService depositAccountReadPlatformService;
private final CalendarInstanceRepository calendarInstanceRepository;
+ private final ConfigurationDomainService configurationDomainService;
@Autowired
public DepositAccountWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
@@ -140,7 +142,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService,
final AccountTransfersWritePlatformService accountTransfersWritePlatformService,
final DepositAccountReadPlatformService depositAccountReadPlatformService,
- final CalendarInstanceRepository calendarInstanceRepository) {
+ final CalendarInstanceRepository calendarInstanceRepository,
+ final ConfigurationDomainService configurationDomainService) {
this.context = context;
this.savingAccountRepository = savingAccountRepository;
@@ -162,6 +165,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
this.accountTransfersWritePlatformService = accountTransfersWritePlatformService;
this.depositAccountReadPlatformService = depositAccountReadPlatformService;
this.calendarInstanceRepository = calendarInstanceRepository;
+ this.configurationDomainService = configurationDomainService;
}
@Transactional
@@ -169,6 +173,11 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
public CommandProcessingResult activateFDAccount(final Long savingsId, final JsonCommand command) {
final AppUser user = this.context.authenticatedUser();
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
this.depositAccountTransactionDataValidator.validateActivation(command);
final MathContext mc = MathContext.DECIMAL64;
@@ -208,17 +217,20 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final boolean isInterestTransfer = false;
if (account.isBeforeLastPostingPeriod(account.getActivationLocalDate())) {
final LocalDate today = DateUtils.getLocalDateOfTenant();
- account.postInterest(mc, today, isInterestTransfer);
+ account.postInterest(mc, today, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
} else {
final LocalDate today = DateUtils.getLocalDateOfTenant();
- account.calculateInterestUsing(mc, today, isInterestTransfer);
+ account.calculateInterestUsing(mc, today, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
}
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
}
final boolean isPreMatureClosure = false;
- account.updateMaturityDateAndAmount(mc, isPreMatureClosure);
+ account.updateMaturityDateAndAmount(mc, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
account.validateAccountBalanceDoesNotBecomeNegative(SavingsAccountTransactionType.PAY_CHARGE.name());
this.savingAccountRepository.save(account);
}
@@ -241,6 +253,11 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
boolean isRegularTransaction = false;
final AppUser user = this.context.authenticatedUser();
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
this.depositAccountTransactionDataValidator.validateActivation(command);
@@ -290,7 +307,9 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
Integer frequency = CalendarUtils.getInterval(calendar.getRecurrence());
frequency = frequency == -1 ? 1 : frequency;
account.generateSchedule(frequencyType, frequency, calendar);
- account.updateMaturityDateAndAmount(mc, isPreMatureClosure);
+ account.updateMaturityDateAndAmount(mc, isPreMatureClosure,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
}
final LocalDate overdueUptoDate = account.maturityDate().isAfter(DateUtils.getLocalDateOfTenant()) ? DateUtils
@@ -299,10 +318,14 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final boolean isInterestTransfer = false;
if (account.isBeforeLastPostingPeriod(account.getActivationLocalDate())) {
final LocalDate today = DateUtils.getLocalDateOfTenant();
- account.postInterest(mc, today, isInterestTransfer);
+ account.postInterest(mc, today, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
} else {
final LocalDate today = DateUtils.getLocalDateOfTenant();
- account.calculateInterestUsing(mc, today, isInterestTransfer);
+ account.calculateInterestUsing(mc, today, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
}
account.validateAccountBalanceDoesNotBecomeNegative(SavingsAccountTransactionType.PAY_CHARGE.name());
@@ -407,6 +430,11 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
@Override
public CommandProcessingResult calculateInterest(final Long savingsId, final DepositAccountType depositAccountType) {
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
+
final SavingsAccount account = this.depositAccountAssembler.assembleFrom(savingsId, depositAccountType);
checkClientOrGroupActive(account);
@@ -414,7 +442,9 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final MathContext mc = new MathContext(15, RoundingMode.HALF_EVEN);
boolean isInterestTransfer = false;
- account.calculateInterestUsing(mc, today, isInterestTransfer);
+ account.calculateInterestUsing(mc, today, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
this.savingAccountRepository.save(account);
@@ -445,13 +475,21 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
@Transactional
private void postInterest(final SavingsAccount account) {
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
+
final Set existingTransactionIds = new HashSet<>();
final Set existingReversedTransactionIds = new HashSet<>();
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
final LocalDate today = DateUtils.getLocalDateOfTenant();
final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN);
boolean isInterestTransfer = false;
- account.postInterest(mc, today, isInterestTransfer);
+ account.postInterest(mc, today, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
this.savingAccountRepository.save(account);
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
@@ -487,6 +525,11 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
@Override
public CommandProcessingResult undoRDTransaction(final Long savingsId, final Long transactionId,
final boolean allowAccountTransferModification) {
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
final RecurringDepositAccount account = (RecurringDepositAccount) this.depositAccountAssembler.assembleFrom(savingsId,
DepositAccountType.RECURRING_DEPOSIT);
@@ -514,14 +557,20 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
checkClientOrGroupActive(account);
if (savingsAccountTransaction.isPostInterestCalculationRequired()
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate())) {
- account.postInterest(mc, today, isInterestTransfer);
+ account.postInterest(mc, today, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
} else {
- account.calculateInterestUsing(mc, today, isInterestTransfer);
+ account.calculateInterestUsing(mc, today, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
}
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.undoTransactionAction);
// account.activateAccountBasedOnBalance();
final boolean isPreMatureClosure = false;
- account.updateMaturityDateAndAmount(mc, isPreMatureClosure);
+ account.updateMaturityDateAndAmount(mc, isPreMatureClosure,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
final LocalDate overdueUptoDate = account.maturityDate().isAfter(DateUtils.getLocalDateOfTenant()) ? DateUtils
.getLocalDateOfTenant() : account.maturityDate();
@@ -553,6 +602,11 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
@Override
public CommandProcessingResult adjustRDTransaction(final Long savingsId, final Long transactionId, final JsonCommand command) {
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
+
this.depositAccountTransactionDataValidator.validate(command, DepositAccountType.RECURRING_DEPOSIT);
final SavingsAccountTransaction savingsAccountTransaction = this.savingsAccountTransactionRepository
@@ -601,9 +655,13 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
boolean isInterestTransfer = false;
if (account.isBeforeLastPostingPeriod(transactionDate)
|| account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate())) {
- account.postInterest(mc, today, isInterestTransfer);
+ account.postInterest(mc, today, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
} else {
- account.calculateInterestUsing(mc, today, isInterestTransfer);
+ account.calculateInterestUsing(mc, today, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
}
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.adjustTransactionAction);
@@ -788,6 +846,12 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
@Override
public SavingsAccountTransaction initiateSavingsTransfer(final Long accountId, final LocalDate transferDate,
final DepositAccountType depositAccountType) {
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
+
final SavingsAccount savingsAccount = this.depositAccountAssembler.assembleFrom(accountId, depositAccountType);
final Set existingTransactionIds = new HashSet<>();
@@ -800,7 +864,9 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
savingsAccount.setStatus(SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue());
final MathContext mc = MathContext.DECIMAL64;
boolean isInterestTransfer = false;
- savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer);
+ savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
this.savingsAccountTransactionRepository.save(newTransferTransaction);
this.savingAccountRepository.save(savingsAccount);
@@ -813,6 +879,12 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
@Override
public SavingsAccountTransaction withdrawSavingsTransfer(final Long accountId, final LocalDate transferDate,
final DepositAccountType depositAccountType) {
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
+
final SavingsAccount savingsAccount = this.depositAccountAssembler.assembleFrom(accountId, depositAccountType);
final Set existingTransactionIds = new HashSet<>();
@@ -825,7 +897,9 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue());
final MathContext mc = MathContext.DECIMAL64;
boolean isInterestTransfer = false;
- savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer);
+ savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
this.savingsAccountTransactionRepository.save(withdrawtransferTransaction);
this.savingAccountRepository.save(savingsAccount);
@@ -845,7 +919,13 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
@Override
public SavingsAccountTransaction acceptSavingsTransfer(final Long accountId, final LocalDate transferDate,
final Office acceptedInOffice, final Staff fieldOfficer, final DepositAccountType depositAccountType) {
- final SavingsAccount savingsAccount = this.depositAccountAssembler.assembleFrom(accountId, depositAccountType);
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
+
+ final SavingsAccount savingsAccount = this.depositAccountAssembler.assembleFrom(accountId, depositAccountType);
final Set existingTransactionIds = new HashSet<>();
final Set existingReversedTransactionIds = new HashSet<>();
@@ -860,7 +940,9 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
}
boolean isInterestTransfer = false;
final MathContext mc = MathContext.DECIMAL64;
- savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer);
+ savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
this.savingsAccountTransactionRepository.save(acceptTransferTransaction);
this.savingAccountRepository.save(savingsAccount);
@@ -985,6 +1067,11 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
@SuppressWarnings("unused") final DepositAccountType depositAccountType) {
this.context.authenticatedUser();
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection(
savingsAccountChargeId, savingsAccountId);
@@ -1002,10 +1089,14 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final MathContext mc = MathContext.DECIMAL64;
if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) {
final LocalDate today = DateUtils.getLocalDateOfTenant();
- account.postInterest(mc, today, isInterestTransfer);
+ account.postInterest(mc, today, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
} else {
final LocalDate today = DateUtils.getLocalDateOfTenant();
- account.calculateInterestUsing(mc, today, isInterestTransfer);
+ account.calculateInterestUsing(mc, today, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
}
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.waiveChargeTransactionAction);
@@ -1109,6 +1200,12 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
@Transactional
private void payCharge(final SavingsAccountCharge savingsAccountCharge, final LocalDate transactionDate, final BigDecimal amountPaid,
final DateTimeFormatter formatter) {
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
+
// Get Savings account from savings charge
final SavingsAccount account = savingsAccountCharge.savingsAccount();
this.depositAccountAssembler.assignSavingAccountHelpers(account);
@@ -1120,10 +1217,14 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final MathContext mc = MathContext.DECIMAL64;
if (account.isBeforeLastPostingPeriod(transactionDate)) {
final LocalDate today = DateUtils.getLocalDateOfTenant();
- account.postInterest(mc, today, isInterestTransfer);
+ account.postInterest(mc, today, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
} else {
final LocalDate today = DateUtils.getLocalDateOfTenant();
- account.calculateInterestUsing(mc, today, isInterestTransfer);
+ account.calculateInterestUsing(mc, today, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
}
account.validateAccountBalanceDoesNotBecomeNegative("." + SavingsAccountTransactionType.PAY_CHARGE.getCode());
@@ -1136,15 +1237,23 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
@Transactional
@Override
public void updateMaturityDetails(Long depositAccountId, DepositAccountType depositAccountType) {
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
+
final SavingsAccount account = this.depositAccountAssembler.assembleFrom(depositAccountId, depositAccountType);
final Set existingTransactionIds = new HashSet<>();
final Set existingReversedTransactionIds = new HashSet<>();
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
if (depositAccountType.isFixedDeposit()) {
- ((FixedDepositAccount) account).updateMaturityStatus();
+ ((FixedDepositAccount) account).updateMaturityStatus(isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
} else if (depositAccountType.isRecurringDeposit()) {
- ((RecurringDepositAccount) account).updateMaturityStatus();
+ ((RecurringDepositAccount) account).updateMaturityStatus(isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
}
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl.java
index 0209cf64b..0143392a9 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl.java
@@ -19,6 +19,7 @@ import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
+import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
@@ -100,6 +101,7 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
private final AccountAssociationsRepository accountAssociationsRepository;
private final FromJsonHelper fromJsonHelper;
private final CalendarInstanceRepository calendarInstanceRepository;
+ private final ConfigurationDomainService configurationDomainService;
@Autowired
public DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
@@ -113,7 +115,8 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
final FixedDepositAccountRepository fixedDepositAccountRepository,
final RecurringDepositAccountRepository recurringDepositAccountRepository,
final AccountAssociationsRepository accountAssociationsRepository, final FromJsonHelper fromJsonHelper,
- final CalendarInstanceRepository calendarInstanceRepository) {
+ final CalendarInstanceRepository calendarInstanceRepository,
+ final ConfigurationDomainService configurationDomainService) {
this.context = context;
this.savingAccountRepository = savingAccountRepository;
this.depositAccountAssembler = depositAccountAssembler;
@@ -131,6 +134,7 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
this.accountAssociationsRepository = accountAssociationsRepository;
this.fromJsonHelper = fromJsonHelper;
this.calendarInstanceRepository = calendarInstanceRepository;
+ this.configurationDomainService = configurationDomainService;
}
/*
@@ -167,6 +171,11 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
try {
this.depositAccountDataValidator.validateFixedDepositForSubmit(command.json());
final AppUser submittedBy = this.context.authenticatedUser();
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
final FixedDepositAccount account = (FixedDepositAccount) this.depositAccountAssembler.assembleFrom(command, submittedBy,
DepositAccountType.FIXED_DEPOSIT);
@@ -174,7 +183,8 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
final MathContext mc = MathContext.DECIMAL64;
final boolean isPreMatureClosure = false;
- account.updateMaturityDateAndAmountBeforeAccountActivation(mc, isPreMatureClosure);
+ account.updateMaturityDateAndAmountBeforeAccountActivation(mc, isPreMatureClosure,
+ isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
this.fixedDepositAccountRepository.save(account);
if (account.isAccountNumberRequiresAutoGeneration()) {
@@ -217,6 +227,11 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
try {
this.depositAccountDataValidator.validateRecurringDepositForSubmit(command.json());
final AppUser submittedBy = this.context.authenticatedUser();
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
final RecurringDepositAccount account = (RecurringDepositAccount) this.depositAccountAssembler.assembleFrom(command,
submittedBy, DepositAccountType.RECURRING_DEPOSIT);
@@ -242,7 +257,8 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
frequency = frequency == -1 ? 1 : frequency;
account.generateSchedule(frequencyType, frequency, calendar);
final boolean isPreMatureClosure = false;
- account.updateMaturityDateAndAmount(mc, isPreMatureClosure);
+ account.updateMaturityDateAndAmount(mc, isPreMatureClosure,
+ isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
account.validateApplicableInterestRate();
this.savingAccountRepository.save(account);
@@ -318,6 +334,11 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
public CommandProcessingResult modifyFDApplication(final Long accountId, final JsonCommand command) {
try {
this.depositAccountDataValidator.validateFixedDepositForUpdate(command.json());
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
final Map changes = new LinkedHashMap<>(20);
@@ -331,7 +352,8 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
updateFDAndRDCommonChanges(changes, command, account);
final MathContext mc = MathContext.DECIMAL64;
final boolean isPreMatureClosure = false;
- account.updateMaturityDateAndAmountBeforeAccountActivation(mc, isPreMatureClosure);
+ account.updateMaturityDateAndAmountBeforeAccountActivation(mc, isPreMatureClosure,
+ isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
this.savingAccountRepository.save(account);
}
@@ -355,6 +377,11 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
public CommandProcessingResult modifyRDApplication(final Long accountId, final JsonCommand command) {
try {
this.depositAccountDataValidator.validateRecurringDepositForUpdate(command.json());
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
final Map changes = new LinkedHashMap<>(20);
@@ -375,7 +402,9 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
frequency = frequency == -1 ? 1 : frequency;
account.generateSchedule(frequencyType, frequency, calendar);
final boolean isPreMatureClosure = false;
- account.updateMaturityDateAndAmount(mc, isPreMatureClosure);
+ account.updateMaturityDateAndAmount(mc, isPreMatureClosure,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
account.validateApplicableInterestRate();
this.savingAccountRepository.save(account);
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java
index 821dadddb..3b81af00a 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java
@@ -28,6 +28,7 @@ import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.mifosplatform.accounting.journalentry.service.JournalEntryWritePlatformService;
+import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
@@ -113,6 +114,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
private final SavingsAccountChargeRepositoryWrapper savingsAccountChargeRepository;
private final HolidayWritePlatformService holidayWritePlatformService;
private final WorkingDaysWritePlatformService workingDaysWritePlatformService;
+ private final ConfigurationDomainService configurationDomainService;
@Autowired
public SavingsAccountWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
@@ -131,7 +133,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final HolidayWritePlatformService holidayWritePlatformService,
final WorkingDaysWritePlatformService workingDaysWritePlatformService,
final SavingsAccountDataValidator fromApiJsonDeserializer, final SavingsAccountRepositoryWrapper savingsRepository,
- final StaffRepositoryWrapper staffRepository) {
+ final StaffRepositoryWrapper staffRepository,
+ final ConfigurationDomainService configurationDomainService) {
this.context = context;
this.savingAccountRepository = savingAccountRepository;
this.savingsAccountTransactionRepository = savingsAccountTransactionRepository;
@@ -152,6 +155,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
this.savingsRepository = savingsRepository;
this.staffRepository = staffRepository;
+ this.configurationDomainService = configurationDomainService;
}
@Transactional
@@ -192,6 +196,12 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override
public void processPostActiveActions(final SavingsAccount account, final DateTimeFormatter fmt, final Set existingTransactionIds,
final Set existingReversedTransactionIds) {
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
+
Money amountForDeposit = account.activateWithBalance();
boolean isRegularTransaction = false;
if (amountForDeposit.isGreaterThanZero()) {
@@ -200,7 +210,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
null, isAccountTransfer, isRegularTransaction);
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
}
- account.processAccountUponActivation();
+ account.processAccountUponActivation(isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
account.validateAccountBalanceDoesNotBecomeNegative(SavingsAccountTransactionType.PAY_CHARGE.name());
}
@@ -304,6 +315,11 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Transactional
@Override
public CommandProcessingResult calculateInterest(final Long savingsId) {
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
checkClientOrGroupActive(account);
@@ -311,7 +327,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final LocalDate today = DateUtils.getLocalDateOfTenant();
final MathContext mc = new MathContext(15, RoundingMode.HALF_EVEN);
boolean isInterestTransfer = false;
- account.calculateInterestUsing(mc, today, isInterestTransfer);
+ account.calculateInterestUsing(mc, today, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
this.savingAccountRepository.save(account);
@@ -342,6 +360,12 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Transactional
private void postInterest(final SavingsAccount account) {
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
+
if (account.getNominalAnnualInterestRate().compareTo(BigDecimal.ZERO) == 1) {
final Set existingTransactionIds = new HashSet<>();
final Set existingReversedTransactionIds = new HashSet<>();
@@ -349,7 +373,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final LocalDate today = DateUtils.getLocalDateOfTenant();
final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN);
boolean isInterestTransfer = false;
- account.postInterest(mc, today, isInterestTransfer);
+ account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
// for generating transaction id's
List transactions = account.getTransactions();
@@ -379,7 +404,12 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override
public CommandProcessingResult undoTransaction(final Long savingsId, final Long transactionId,
final boolean allowAccountTransferModification) {
-
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
+
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
final Set existingTransactionIds = new HashSet<>();
final Set existingReversedTransactionIds = new HashSet<>();
@@ -419,9 +449,12 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
checkClientOrGroupActive(account);
if (savingsAccountTransaction.isPostInterestCalculationRequired()
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate())) {
- account.postInterest(mc, today, isInterestTransfer);
+ account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
} else {
- account.calculateInterestUsing(mc, today, isInterestTransfer);
+ account.calculateInterestUsing(mc, today, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
}
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.undoTransactionAction);
account.activateAccountBasedOnBalance();
@@ -438,6 +471,11 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override
public CommandProcessingResult adjustSavingsTransaction(final Long savingsId, final Long transactionId, final JsonCommand command) {
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
final SavingsAccountTransaction savingsAccountTransaction = this.savingsAccountTransactionRepository
.findOneByIdAndSavingsAccountId(transactionId, savingsId);
@@ -495,9 +533,12 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
if (account.isBeforeLastPostingPeriod(transactionDate)
|| account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate())) {
- account.postInterest(mc, today, isInterestTransfer);
+ account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
} else {
- account.calculateInterestUsing(mc, today, isInterestTransfer);
+ account.calculateInterestUsing(mc, today, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
}
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.adjustTransactionAction);
account.activateAccountBasedOnBalance();
@@ -597,6 +638,12 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override
public SavingsAccountTransaction initiateSavingsTransfer(final Long accountId, final LocalDate transferDate) {
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
+
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(accountId);
final Set existingTransactionIds = new HashSet<>();
@@ -609,7 +656,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
savingsAccount.setStatus(SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue());
final MathContext mc = MathContext.DECIMAL64;
boolean isInterestTransfer = false;
- savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer);
+ savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
this.savingsAccountTransactionRepository.save(newTransferTransaction);
this.savingAccountRepository.save(savingsAccount);
@@ -621,6 +670,12 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override
public SavingsAccountTransaction withdrawSavingsTransfer(final Long accountId, final LocalDate transferDate) {
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
+
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(accountId);
final Set existingTransactionIds = new HashSet<>();
@@ -633,7 +688,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue());
final MathContext mc = MathContext.DECIMAL64;
boolean isInterestTransfer = false;
- savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer);
+ savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
this.savingsAccountTransactionRepository.save(withdrawtransferTransaction);
this.savingAccountRepository.save(savingsAccount);
@@ -653,6 +710,12 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override
public SavingsAccountTransaction acceptSavingsTransfer(final Long accountId, final LocalDate transferDate,
final Office acceptedInOffice, final Staff fieldOfficer) {
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
+
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(accountId);
final Set existingTransactionIds = new HashSet<>();
@@ -668,7 +731,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
}
boolean isInterestTransfer = false;
final MathContext mc = MathContext.DECIMAL64;
- savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer);
+ savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
this.savingsAccountTransactionRepository.save(acceptTransferTransaction);
this.savingAccountRepository.save(savingsAccount);
@@ -792,6 +857,11 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
public CommandProcessingResult waiveCharge(final Long savingsAccountId, final Long savingsAccountChargeId) {
this.context.authenticatedUser();
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection(
savingsAccountChargeId, savingsAccountId);
@@ -809,10 +879,13 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final MathContext mc = MathContext.DECIMAL64;
if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) {
final LocalDate today = DateUtils.getLocalDateOfTenant();
- account.postInterest(mc, today, isInterestTransfer);
+ account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
} else {
final LocalDate today = DateUtils.getLocalDateOfTenant();
- account.calculateInterestUsing(mc, today, isInterestTransfer);
+ account.calculateInterestUsing(mc, today, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
}
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.waiveChargeTransactionAction);
@@ -914,6 +987,12 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Transactional
private void payCharge(final SavingsAccountCharge savingsAccountCharge, final LocalDate transactionDate, final BigDecimal amountPaid,
final DateTimeFormatter formatter) {
+
+ final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
+ .isSavingsInterestPostingAtCurrentPeriodEnd();
+ final Integer financialYearBeginningMonth = this.configurationDomainService
+ .retrieveFinancialYearBeginningMonth();
+
// Get Savings account from savings charge
final SavingsAccount account = savingsAccountCharge.savingsAccount();
this.savingAccountAssembler.assignSavingAccountHelpers(account);
@@ -925,10 +1004,13 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final MathContext mc = MathContext.DECIMAL64;
if (account.isBeforeLastPostingPeriod(transactionDate)) {
final LocalDate today = DateUtils.getLocalDateOfTenant();
- account.postInterest(mc, today, isInterestTransfer);
+ account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
} else {
final LocalDate today = DateUtils.getLocalDateOfTenant();
- account.calculateInterestUsing(mc, today, isInterestTransfer);
+ account.calculateInterestUsing(mc, today, isInterestTransfer,
+ isSavingsInterestPostingAtCurrentPeriodEnd,
+ financialYearBeginningMonth);
}
account.validateAccountBalanceDoesNotBecomeNegative("." + SavingsAccountTransactionType.PAY_CHARGE.getCode());
diff --git a/mifosng-provider/src/main/resources/sql/migrations/core_db/V206__interest_posting_configuration.sql b/mifosng-provider/src/main/resources/sql/migrations/core_db/V206__interest_posting_configuration.sql
new file mode 100644
index 000000000..7ea69a78a
--- /dev/null
+++ b/mifosng-provider/src/main/resources/sql/migrations/core_db/V206__interest_posting_configuration.sql
@@ -0,0 +1,7 @@
+ALTER TABLE c_configuration ADD `description` varchar(300) DEFAULT NULL;
+
+INSERT INTO `c_configuration` (`id`, `name`, `enabled`, `description`)
+VALUES (NULL, 'savings-interest-posting-current-period-end', '0', "Recommended to be changed only once during start of production. When set as false(default), interest will be posted on the first date of next period. If set as true, interest will be posted on last date of current period. There is no difference in the interest amount posted.");
+
+INSERT INTO `c_configuration` (`id`, `name`, `value`, `enabled`, `description`)
+VALUES (NULL, 'financial-year-beginning-month', '1', '1', "Recommended to be changed only once during start of production. Allowed values 1 - 12 (January - December). Interest posting periods are evaluated based on this configuration.");