Merge branch 'develop' of git://github.com/pramodn02/mifosx into pramodn02-develop

This commit is contained in:
Vishwas Babu A J
2014-05-09 19:16:06 +05:30
32 changed files with 582 additions and 165 deletions
+1 -1
View File
@@ -19297,7 +19297,7 @@ No Request Body:
<br/> <br/>
<table class=matrixHeading> <table class=matrixHeading>
<tr class="matrixHeadingBG"><td><div class="mifosXHeading2">Optional Fields</div></td></tr> <tr class="matrixHeadingBG"><td><div class="mifosXHeading2">Optional Fields</div></td></tr>
<tr class=alt><td>accountNo, externalId, fieldOfficerId,linkAccountId</td></tr> <tr class=alt><td>accountNo, externalId, fieldOfficerId,linkAccountId(if provided initial deposit amount will be collected from this account),transferInterestToSavings(By enabling this flag all interest postings will be transferred to linked saving account )</td></tr>
</table> </table>
<br/> <br/>
<table class=matrixHeading> <table class=matrixHeading>
@@ -0,0 +1,9 @@
ALTER TABLE `job_run_history`
CHANGE COLUMN `error_message` `error_message` TEXT NULL DEFAULT NULL AFTER `status`;
ALTER TABLE `m_deposit_account_term_and_preclosure`
ADD COLUMN `transfer_interest_to_linked_account` TINYINT(1) NOT NULL DEFAULT '0' AFTER `expected_firstdepositon_date`;
UPDATE `job` SET `scheduler_group`=1 WHERE `name`='Post Interest For Savings';
INSERT INTO `job` (`name`, `display_name`, `cron_expression`, `create_time`, `task_priority`, `group_name`, `previous_run_start_time`, `next_run_time`, `job_key`, `initializing_errorlog`, `is_active`, `currently_running`, `updates_allowed`, `scheduler_group`, `is_misfired`) VALUES ('Transfer Interest To Savings', 'Transfer Interest To Savings', '0 2 0 1/1 * ? *', now(), 4, NULL, NULL, NULL, NULL, NULL, 1, 0, 1, 1, 0);
@@ -506,9 +506,6 @@ public class FixedDepositTest {
this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec); this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec);
this.fixedDepositAccountHelper = new FixedDepositAccountHelper(this.requestSpec, this.responseSpec); this.fixedDepositAccountHelper = new FixedDepositAccountHelper(this.requestSpec, this.responseSpec);
FixedDepositAccountHelper fixedDepositAccountHelperValidationError = new FixedDepositAccountHelper(this.requestSpec,
new ResponseSpecBuilder().build());
DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy"); DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy");
DateFormat monthDayFormat = new SimpleDateFormat("dd MMM"); DateFormat monthDayFormat = new SimpleDateFormat("dd MMM");
@@ -1,6 +1,9 @@
package org.mifosplatform.integrationtests; package org.mifosplatform.integrationtests;
import static org.junit.Assert.assertEquals;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
@@ -22,6 +25,9 @@ import org.mifosplatform.integrationtests.common.accounting.GLAccountBuilder;
import org.mifosplatform.integrationtests.common.accounting.JournalEntry; import org.mifosplatform.integrationtests.common.accounting.JournalEntry;
import org.mifosplatform.integrationtests.common.accounting.JournalEntryHelper; import org.mifosplatform.integrationtests.common.accounting.JournalEntryHelper;
import org.mifosplatform.integrationtests.common.charges.ChargesHelper; import org.mifosplatform.integrationtests.common.charges.ChargesHelper;
import org.mifosplatform.integrationtests.common.fixeddeposit.FixedDepositAccountHelper;
import org.mifosplatform.integrationtests.common.fixeddeposit.FixedDepositAccountStatusChecker;
import org.mifosplatform.integrationtests.common.fixeddeposit.FixedDepositProductHelper;
import org.mifosplatform.integrationtests.common.loans.LoanApplicationTestBuilder; import org.mifosplatform.integrationtests.common.loans.LoanApplicationTestBuilder;
import org.mifosplatform.integrationtests.common.loans.LoanProductTestBuilder; import org.mifosplatform.integrationtests.common.loans.LoanProductTestBuilder;
import org.mifosplatform.integrationtests.common.loans.LoanStatusChecker; import org.mifosplatform.integrationtests.common.loans.LoanStatusChecker;
@@ -708,6 +714,88 @@ public class SchedulerJobsTestResults {
Assert.assertTrue(isNPAAfter); Assert.assertTrue(isNPAAfter);
} }
@Test
public void testInterestTransferForSavings() throws InterruptedException {
this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec);
this.schedulerJobHelper = new SchedulerJobHelper(this.requestSpec, this.responseSpec);
FixedDepositProductHelper fixedDepositProductHelper = new FixedDepositProductHelper(this.requestSpec, this.responseSpec);
AccountHelper accountHelper = new AccountHelper(this.requestSpec, this.responseSpec);
FixedDepositAccountHelper fixedDepositAccountHelper = new FixedDepositAccountHelper(this.requestSpec, this.responseSpec);
DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy");
DateFormat monthDayFormat = new SimpleDateFormat("dd MMM");
Calendar todaysDate = Calendar.getInstance();
todaysDate.add(Calendar.MONTH, -3);
final String VALID_FROM = dateFormat.format(todaysDate.getTime());
todaysDate.add(Calendar.YEAR, 10);
final String VALID_TO = dateFormat.format(todaysDate.getTime());
todaysDate = Calendar.getInstance();
todaysDate.add(Calendar.MONTH, -2);
final String SUBMITTED_ON_DATE = dateFormat.format(todaysDate.getTime());
final String APPROVED_ON_DATE = dateFormat.format(todaysDate.getTime());
final String ACTIVATION_DATE = dateFormat.format(todaysDate.getTime());
todaysDate.add(Calendar.MONTH, 1);
final String WHOLE_TERM = "1";
Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec);
Assert.assertNotNull(clientId);
Float balance = new Float(MINIMUM_OPENING_BALANCE) + new Float(FixedDepositAccountHelper.depositAmount);
final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, String.valueOf(balance));
Assert.assertNotNull(savingsProductID);
final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(clientId, savingsProductID,
ClientSavingsIntegrationTest.ACCOUNT_TYPE_INDIVIDUAL);
Assert.assertNotNull(savingsId);
HashMap savingsStatusHashMap = SavingsStatusChecker.getStatusOfSavings(this.requestSpec, this.responseSpec, savingsId);
SavingsStatusChecker.verifySavingsIsPending(savingsStatusHashMap);
savingsStatusHashMap = this.savingsAccountHelper.approveSavings(savingsId);
SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap);
savingsStatusHashMap = this.savingsAccountHelper.activateSavings(savingsId);
SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap);
HashMap summary = savingsAccountHelper.getSavingsSummary(savingsId);
assertEquals("Verifying opening Balance", balance, summary.get("accountBalance"));
Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO);
Assert.assertNotNull(fixedDepositProductId);
Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), VALID_FROM,
VALID_TO, SUBMITTED_ON_DATE, WHOLE_TERM, savingsId.toString(), true, fixedDepositAccountHelper);
Assert.assertNotNull(fixedDepositAccountId);
HashMap fixedDepositAccountStatusHashMap = FixedDepositAccountStatusChecker.getStatusOfFixedDepositAccount(this.requestSpec,
this.responseSpec, fixedDepositAccountId.toString());
FixedDepositAccountStatusChecker.verifyFixedDepositIsPending(fixedDepositAccountStatusHashMap);
fixedDepositAccountStatusHashMap = fixedDepositAccountHelper.approveFixedDeposit(fixedDepositAccountId, APPROVED_ON_DATE);
FixedDepositAccountStatusChecker.verifyFixedDepositIsApproved(fixedDepositAccountStatusHashMap);
fixedDepositAccountStatusHashMap = fixedDepositAccountHelper.activateFixedDeposit(fixedDepositAccountId, ACTIVATION_DATE);
FixedDepositAccountStatusChecker.verifyFixedDepositIsActive(fixedDepositAccountStatusHashMap);
summary = savingsAccountHelper.getSavingsSummary(savingsId);
balance = new Float(MINIMUM_OPENING_BALANCE);
assertEquals("Verifying Balance", balance, summary.get("accountBalance"));
fixedDepositAccountHelper.postInterestForFixedDeposit(fixedDepositAccountId);
HashMap fixedDepositSummary = savingsAccountHelper.getSavingsSummary(fixedDepositAccountId);
Float interestPosted = (Float) fixedDepositSummary.get("accountBalance") - new Float(FixedDepositAccountHelper.depositAmount);
String JobName = "Transfer Interest To Savings";
excuteJob(JobName);
fixedDepositSummary = savingsAccountHelper.getSavingsSummary(fixedDepositAccountId);
assertEquals("Verifying opening Balance", new Float(FixedDepositAccountHelper.depositAmount),
fixedDepositSummary.get("accountBalance"));
summary = savingsAccountHelper.getSavingsSummary(savingsId);
balance = new Float(MINIMUM_OPENING_BALANCE) + interestPosted;
validateNumberForEqualExcludePrecission(String.valueOf(balance), String.valueOf(summary.get("accountBalance")));
}
private void excuteJob(String JobName) throws InterruptedException { private void excuteJob(String JobName) throws InterruptedException {
ArrayList<HashMap> allSchedulerJobsData = this.schedulerJobHelper.getAllSchedulerJobs(this.requestSpec, this.responseSpec); ArrayList<HashMap> allSchedulerJobsData = this.schedulerJobHelper.getAllSchedulerJobs(this.requestSpec, this.responseSpec);
Assert.assertNotNull(allSchedulerJobsData); Assert.assertNotNull(allSchedulerJobsData);
@@ -797,4 +885,30 @@ public class SchedulerJobsTestResults {
.build(clientID, loanProductID, savingsID); .build(clientID, loanProductID, savingsID);
return this.loanTransactionHelper.getLoanId(loanApplicationJSON); return this.loanTransactionHelper.getLoanId(loanApplicationJSON);
} }
private Integer createFixedDepositProduct(final String validFrom, final String validTo, Account... accounts) {
System.out.println("------------------------------CREATING NEW FIXED DEPOSIT PRODUCT ---------------------------------------");
FixedDepositProductHelper fixedDepositProductHelper = new FixedDepositProductHelper(this.requestSpec, this.responseSpec);
final String fixedDepositProductJSON = fixedDepositProductHelper //
// .withAccountingRuleAsCashBased(accounts)
.build(validFrom, validTo);
return FixedDepositProductHelper.createFixedDepositProduct(fixedDepositProductJSON, requestSpec, responseSpec);
}
private Integer applyForFixedDepositApplication(final String clientID, final String productID, final String validFrom,
final String validTo, final String submittedOnDate, final String penalInterestType, String savingsId,
final boolean transferInterest, final FixedDepositAccountHelper fixedDepositAccountHelper) {
System.out.println("--------------------------------APPLYING FOR FIXED DEPOSIT ACCOUNT --------------------------------");
final String fixedDepositApplicationJSON = new FixedDepositAccountHelper(this.requestSpec, this.responseSpec)
//
.withSubmittedOnDate(submittedOnDate).withSavings(savingsId).transferInterest(true)
.withLockinPeriodFrequency("1", FixedDepositAccountHelper.DAYS)
.build(clientID, productID, validFrom, validTo, penalInterestType);
return fixedDepositAccountHelper.applyFixedDepositApplication(fixedDepositApplicationJSON, this.requestSpec, this.responseSpec);
}
public void validateNumberForEqualExcludePrecission(String val, String val2) {
DecimalFormat twoDForm = new DecimalFormat("#");
Assert.assertTrue(new Float(twoDForm.format(new Float(val))).compareTo(new Float(twoDForm.format(new Float(val2)))) == 0);
}
} }
@@ -49,7 +49,7 @@ public class FixedDepositAccountHelper {
private static final String DIGITS_AFTER_DECIMAL = "4"; private static final String DIGITS_AFTER_DECIMAL = "4";
private static final String IN_MULTIPLES_OF = "100"; private static final String IN_MULTIPLES_OF = "100";
private static final String USD = "USD"; private static final String USD = "USD";
private static final String DAYS = "0"; public static final String DAYS = "0";
private static final String WEEKS = "1"; private static final String WEEKS = "1";
private static final String MONTHS = "2"; private static final String MONTHS = "2";
private static final String YEARS = "3"; private static final String YEARS = "3";
@@ -83,6 +83,7 @@ public class FixedDepositAccountHelper {
private final String depositPeriodFrequencyId = MONTHS; private final String depositPeriodFrequencyId = MONTHS;
private String submittedOnDate = ""; private String submittedOnDate = "";
private String savingsId = null; private String savingsId = null;
private boolean transferInterest = false;
public String build(final String clientId, final String productId, final String validFrom, final String validTo, public String build(final String clientId, final String productId, final String validFrom, final String validTo,
final String penalInterestType) { final String penalInterestType) {
@@ -162,6 +163,7 @@ public class FixedDepositAccountHelper {
map.put("depositPeriodFrequencyId", this.depositPeriodFrequencyId); map.put("depositPeriodFrequencyId", this.depositPeriodFrequencyId);
map.put("submittedOnDate", this.submittedOnDate); map.put("submittedOnDate", this.submittedOnDate);
map.put("linkAccountId", savingsId); map.put("linkAccountId", savingsId);
map.put("transferInterestToSavings", transferInterest);
String fixedDepositAccountJson = new Gson().toJson(map); String fixedDepositAccountJson = new Gson().toJson(map);
System.out.println(fixedDepositAccountJson); System.out.println(fixedDepositAccountJson);
@@ -432,4 +434,15 @@ public class FixedDepositAccountHelper {
this.savingsId = savingsId; this.savingsId = savingsId;
return this; return this;
} }
public FixedDepositAccountHelper transferInterest(final boolean transferInterest) {
this.transferInterest = transferInterest;
return this;
}
public FixedDepositAccountHelper withLockinPeriodFrequency(final String lockingPeriodFrequencyType, final String lockinPeriodFrequency) {
this.lockingPeriodFrequencyType = lockingPeriodFrequencyType;
this.lockinPeriodFrequency = lockinPeriodFrequency;
return this;
}
} }
@@ -15,7 +15,8 @@ public enum JobName {
EXECUTE_STANDING_INSTRUCTIONS("Execute Standing Instruction"), EXECUTE_STANDING_INSTRUCTIONS("Execute Standing Instruction"),
ADD_ACCRUAL_ENTRIES("Add Accrual Transactions"), ADD_ACCRUAL_ENTRIES("Add Accrual Transactions"),
UPDATE_NPA("Update Non Performing Assets"), UPDATE_NPA("Update Non Performing Assets"),
UPDATE_DEPOSITS_ACCOUNT_MATURITY_DETAILS("Update Deposit Accounts Maturity details"); UPDATE_DEPOSITS_ACCOUNT_MATURITY_DETAILS("Update Deposit Accounts Maturity details"),
TRANSFER_INTEREST_TO_SAVINGS("Transfer Interest To Savings");
private final String name; private final String name;
@@ -13,7 +13,8 @@ public enum AccountTransferType {
INVALID(0, "accountTransferType.invalid"), // INVALID(0, "accountTransferType.invalid"), //
ACCOUNT_TRANSFER(1, "accountTransferType.account.transfer"), // ACCOUNT_TRANSFER(1, "accountTransferType.account.transfer"), //
LOAN_REPAYMENT(2, "accountTransferType.loan.repayment"), // LOAN_REPAYMENT(2, "accountTransferType.loan.repayment"), //
CHARGE_PAYMENT(3, "accountTransferType.charge.payment"); // CHARGE_PAYMENT(3, "accountTransferType.charge.payment"), //
INTEREST_TRANSFER(4, "accountTransferType.interest.transfer"); //
private final Integer value; private final Integer value;
private final String code; private final String code;
@@ -31,6 +32,9 @@ public enum AccountTransferType {
case 3: case 3:
enumeration = AccountTransferType.CHARGE_PAYMENT; enumeration = AccountTransferType.CHARGE_PAYMENT;
break; break;
case 4:
enumeration = AccountTransferType.INTEREST_TRANSFER;
break;
} }
return enumeration; return enumeration;
} }
@@ -63,4 +67,8 @@ public enum AccountTransferType {
public boolean isChargePayment() { public boolean isChargePayment() {
return this.value.equals(AccountTransferType.CHARGE_PAYMENT.getValue()); return this.value.equals(AccountTransferType.CHARGE_PAYMENT.getValue());
} }
public boolean isInterestTransfer() {
return this.value.equals(AccountTransferType.INTEREST_TRANSFER.getValue());
}
} }
@@ -5,6 +5,8 @@
*/ */
package org.mifosplatform.portfolio.account.service; package org.mifosplatform.portfolio.account.service;
import java.util.Collection;
import org.mifosplatform.infrastructure.core.service.Page; import org.mifosplatform.infrastructure.core.service.Page;
import org.mifosplatform.portfolio.account.PortfolioAccountType; import org.mifosplatform.portfolio.account.PortfolioAccountType;
import org.mifosplatform.portfolio.account.data.AccountTransferData; import org.mifosplatform.portfolio.account.data.AccountTransferData;
@@ -22,4 +24,6 @@ public interface AccountTransfersReadPlatformService {
boolean isAccountTransfer(Long transactionId, PortfolioAccountType accountType); boolean isAccountTransfer(Long transactionId, PortfolioAccountType accountType);
Page<AccountTransferData> retrieveByStandingInstruction(Long id, SearchParameters searchParameters); Page<AccountTransferData> retrieveByStandingInstruction(Long id, SearchParameters searchParameters);
Collection<Long> fetchPostInterestTransactionIds(Long accountId);
} }
@@ -11,6 +11,7 @@ import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.infrastructure.core.data.EnumOptionData;
@@ -25,6 +26,7 @@ import org.mifosplatform.organisation.office.service.OfficeReadPlatformService;
import org.mifosplatform.portfolio.account.PortfolioAccountType; import org.mifosplatform.portfolio.account.PortfolioAccountType;
import org.mifosplatform.portfolio.account.data.AccountTransferData; import org.mifosplatform.portfolio.account.data.AccountTransferData;
import org.mifosplatform.portfolio.account.data.PortfolioAccountData; import org.mifosplatform.portfolio.account.data.PortfolioAccountData;
import org.mifosplatform.portfolio.account.domain.AccountTransferType;
import org.mifosplatform.portfolio.account.exception.AccountTransferNotFoundException; import org.mifosplatform.portfolio.account.exception.AccountTransferNotFoundException;
import org.mifosplatform.portfolio.client.data.ClientData; import org.mifosplatform.portfolio.client.data.ClientData;
import org.mifosplatform.portfolio.client.service.ClientReadPlatformService; import org.mifosplatform.portfolio.client.service.ClientReadPlatformService;
@@ -188,15 +190,15 @@ public class AccountTransfersReadPlatformServiceImpl implements AccountTransfers
} }
@Override @Override
public Page<AccountTransferData> retrieveAll(final SearchParameters searchParameters,final Long accountDetailId) { public Page<AccountTransferData> retrieveAll(final SearchParameters searchParameters, final Long accountDetailId) {
final StringBuilder sqlBuilder = new StringBuilder(200); final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS "); sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append(this.accountTransfersMapper.schema()); sqlBuilder.append(this.accountTransfersMapper.schema());
Object[] finalObjectArray = {}; Object[] finalObjectArray = {};
if(accountDetailId != null){ if (accountDetailId != null) {
sqlBuilder.append(" where att.account_transfer_details_id=?"); sqlBuilder.append(" where att.account_transfer_details_id=?");
finalObjectArray = new Object[]{ accountDetailId }; finalObjectArray = new Object[] { accountDetailId };
} }
if (searchParameters.isOrderByRequested()) { if (searchParameters.isOrderByRequested()) {
@@ -231,6 +233,16 @@ public class AccountTransfersReadPlatformServiceImpl implements AccountTransfers
} }
} }
@Override
public Collection<Long> fetchPostInterestTransactionIds(final Long accountId) {
final String sql = "select att.from_savings_transaction_id from m_account_transfer_transaction att inner join m_account_transfer_details atd on atd.id = att.account_transfer_details_id where atd.from_savings_account_id=? and att.is_reversed =0 and atd.transfer_type = ?";
final List<Long> transactionId = this.jdbcTemplate.queryForList(sql, Long.class, accountId,
AccountTransferType.INTEREST_TRANSFER.getValue());
return transactionId;
}
private static final class AccountTransfersMapper implements RowMapper<AccountTransferData> { private static final class AccountTransfersMapper implements RowMapper<AccountTransferData> {
private final String schemaSql; private final String schemaSql;
@@ -98,13 +98,15 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
final PaymentDetail paymentDetail = null; final PaymentDetail paymentDetail = null;
Long fromSavingsAccountId = null; Long fromSavingsAccountId = null;
Long transferDetailId = null; Long transferDetailId = null;
boolean isInterestTransfer = false;
if (isSavingsToSavingsAccountTransfer(fromAccountType, toAccountType)) { if (isSavingsToSavingsAccountTransfer(fromAccountType, toAccountType)) {
fromSavingsAccountId = command.longValueOfParameterNamed(fromAccountIdParamName); fromSavingsAccountId = command.longValueOfParameterNamed(fromAccountIdParamName);
final SavingsAccount fromSavingsAccount = this.savingsAccountAssembler.assembleFrom(fromSavingsAccountId); final SavingsAccount fromSavingsAccount = this.savingsAccountAssembler.assembleFrom(fromSavingsAccountId);
final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount, fmt, final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount, fmt,
transactionDate, transactionAmount, paymentDetail, fromSavingsAccount.isWithdrawalFeeApplicableForTransfer()); transactionDate, transactionAmount, paymentDetail, fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(),
isInterestTransfer);
final Long toSavingsId = command.longValueOfParameterNamed(toAccountIdParamName); final Long toSavingsId = command.longValueOfParameterNamed(toAccountIdParamName);
final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsId); final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsId);
@@ -123,7 +125,8 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
final SavingsAccount fromSavingsAccount = this.savingsAccountAssembler.assembleFrom(fromSavingsAccountId); final SavingsAccount fromSavingsAccount = this.savingsAccountAssembler.assembleFrom(fromSavingsAccountId);
final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount, fmt, final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount, fmt,
transactionDate, transactionAmount, paymentDetail, fromSavingsAccount.isWithdrawalFeeApplicableForTransfer()); transactionDate, transactionAmount, paymentDetail, fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(),
isInterestTransfer);
final Long toLoanAccountId = command.longValueOfParameterNamed(toAccountIdParamName); final Long toLoanAccountId = command.longValueOfParameterNamed(toAccountIdParamName);
final Loan toLoanAccount = this.loanAccountAssembler.assembleFrom(toLoanAccountId); final Loan toLoanAccount = this.loanAccountAssembler.assembleFrom(toLoanAccountId);
@@ -244,7 +247,8 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount, final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount,
accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(), accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(),
accountTransferDTO.getPaymentDetail(), fromSavingsAccount.isWithdrawalFeeApplicableForTransfer()); accountTransferDTO.getPaymentDetail(), fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(), AccountTransferType
.fromInt(accountTransferDTO.getTransferType()).isInterestTransfer());
LoanTransaction loanTransaction = null; LoanTransaction loanTransaction = null;
@@ -284,7 +288,8 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
} }
final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount, final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount,
accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(), accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(),
accountTransferDTO.getPaymentDetail(), fromSavingsAccount.isWithdrawalFeeApplicableForTransfer()); accountTransferDTO.getPaymentDetail(), fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(), AccountTransferType
.fromInt(accountTransferDTO.getTransferType()).isInterestTransfer());
final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount, final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount,
accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(), accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(),
@@ -179,6 +179,7 @@ public class DepositsApiConstants {
public static final String preMatureCloseOnDateParamName = "preMatureCloseOnDate"; public static final String preMatureCloseOnDateParamName = "preMatureCloseOnDate";
public static final String linkedAccountParamName = "linkAccountId"; public static final String linkedAccountParamName = "linkAccountId";
public static final String transferInterestToSavingsParamName = "transferInterestToSavings";
// template // template
public static final String chartTemplate = "chartTemplate"; public static final String chartTemplate = "chartTemplate";
@@ -216,13 +217,11 @@ public class DepositsApiConstants {
private static final Set<String> DEPOSIT_TERM_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(minDepositTermParamName, private static final Set<String> DEPOSIT_TERM_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(minDepositTermParamName,
maxDepositTermParamName, minDepositTermTypeIdParamName, maxDepositTermTypeIdParamName, inMultiplesOfDepositTermParamName, maxDepositTermParamName, minDepositTermTypeIdParamName, maxDepositTermTypeIdParamName, inMultiplesOfDepositTermParamName,
inMultiplesOfDepositTermTypeIdParamName, depositAmountParamName, inMultiplesOfDepositTermTypeIdParamName, depositAmountParamName, depositMinAmountParamName, depositMaxAmountParamName));
depositMinAmountParamName, depositMaxAmountParamName));
private static final Set<String> DEPOSIT_TERM_RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(minDepositTermParamName, private static final Set<String> DEPOSIT_TERM_RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(minDepositTermParamName,
maxDepositTermParamName, minDepositTermType, maxDepositTermType, inMultiplesOfDepositTermParamName, maxDepositTermParamName, minDepositTermType, maxDepositTermType, inMultiplesOfDepositTermParamName,
inMultiplesOfDepositTermType, depositAmountParamName, inMultiplesOfDepositTermType, depositAmountParamName, depositMinAmountParamName, depositMaxAmountParamName));
depositMinAmountParamName, depositMaxAmountParamName));
private static final Set<String> RECURRING_DETAILS_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList( private static final Set<String> RECURRING_DETAILS_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(
recurringDepositAmountParamName, recurringDepositTypeIdParamName, recurringDepositFrequencyTypeIdParamName, recurringDepositAmountParamName, recurringDepositTypeIdParamName, recurringDepositFrequencyTypeIdParamName,
@@ -298,6 +297,7 @@ public class DepositsApiConstants {
fixedDepositRequestData.addAll(PRECLOSURE_REQUEST_DATA_PARAMETERS); fixedDepositRequestData.addAll(PRECLOSURE_REQUEST_DATA_PARAMETERS);
fixedDepositRequestData.addAll(DEPOSIT_TERM_REQUEST_DATA_PARAMETERS); fixedDepositRequestData.addAll(DEPOSIT_TERM_REQUEST_DATA_PARAMETERS);
fixedDepositRequestData.add(linkedAccountParamName); fixedDepositRequestData.add(linkedAccountParamName);
fixedDepositRequestData.add(transferInterestToSavingsParamName);
return fixedDepositRequestData; return fixedDepositRequestData;
} }
@@ -307,6 +307,7 @@ public class DepositsApiConstants {
fixedDepositResponseData.addAll(PRECLOSURE_RESPONSE_DATA_PARAMETERS); fixedDepositResponseData.addAll(PRECLOSURE_RESPONSE_DATA_PARAMETERS);
fixedDepositResponseData.addAll(DEPOSIT_TERM_RESPONSE_DATA_PARAMETERS); fixedDepositResponseData.addAll(DEPOSIT_TERM_RESPONSE_DATA_PARAMETERS);
fixedDepositResponseData.add(linkedAccountParamName); fixedDepositResponseData.add(linkedAccountParamName);
fixedDepositResponseData.add(transferInterestToSavingsParamName);
return fixedDepositResponseData; return fixedDepositResponseData;
} }
@@ -45,6 +45,7 @@ import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minRequire
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.productIdParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.productIdParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.submittedOnDateParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.submittedOnDateParamName;
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.transferInterestToSavingsParamName;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.math.BigDecimal; import java.math.BigDecimal;
@@ -279,8 +280,15 @@ public class DepositAccountDataValidator {
} }
} }
if (this.fromApiJsonHelper.parameterExists(linkedAccountParamName, element)) { boolean isLinkedAccRequired = false;
final Long linkAccountId = this.fromApiJsonHelper.extractLongNamed(linkedAccountParamName, element); if (fromApiJsonHelper.parameterExists(transferInterestToSavingsParamName, element)) {
isLinkedAccRequired = fromApiJsonHelper.extractBooleanNamed(transferInterestToSavingsParamName, element);
}
final Long linkAccountId = this.fromApiJsonHelper.extractLongNamed(linkedAccountParamName, element);
if (isLinkedAccRequired) {
baseDataValidator.reset().parameter(linkedAccountParamName).value(linkAccountId).notNull().longGreaterThanZero();
} else {
baseDataValidator.reset().parameter(linkedAccountParamName).value(linkAccountId).ignoreIfNull().longGreaterThanZero(); baseDataValidator.reset().parameter(linkedAccountParamName).value(linkAccountId).ignoreIfNull().longGreaterThanZero();
} }
} }
@@ -400,9 +408,18 @@ public class DepositAccountDataValidator {
baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(lockinPeriodFrequencyType).inMinMaxRange(0, 3); baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(lockinPeriodFrequencyType).inMinMaxRange(0, 3);
} }
boolean isLinkedAccRequired = false;
if (fromApiJsonHelper.parameterExists(transferInterestToSavingsParamName, element)) {
isLinkedAccRequired = fromApiJsonHelper.extractBooleanNamed(transferInterestToSavingsParamName, element);
}
if (this.fromApiJsonHelper.parameterExists(linkedAccountParamName, element)) { if (this.fromApiJsonHelper.parameterExists(linkedAccountParamName, element)) {
final Long linkAccountId = this.fromApiJsonHelper.extractLongNamed(linkedAccountParamName, element); final Long linkAccountId = this.fromApiJsonHelper.extractLongNamed(linkedAccountParamName, element);
baseDataValidator.reset().parameter(linkedAccountParamName).value(linkAccountId).ignoreIfNull().longGreaterThanZero(); if (isLinkedAccRequired) {
baseDataValidator.reset().parameter(linkedAccountParamName).value(linkAccountId).notNull().longGreaterThanZero();
} else {
baseDataValidator.reset().parameter(linkedAccountParamName).value(linkAccountId).ignoreIfNull().longGreaterThanZero();
}
} }
} }
@@ -585,6 +602,15 @@ public class DepositAccountDataValidator {
"Validation errors exist.", dataValidationErrors); } "Validation errors exist.", dataValidationErrors); }
} }
public void throwLinkedAccountRequiredError() {
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final ApiParameterError error = ApiParameterError.parameterError(
"validation.msg.fixeddepositaccount.linkAccountId.cannot.be.blank", "Linked Savings account required", "linkAccountId");
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors);
}
private void validateSavingsCharges(final JsonElement element, final DataValidatorBuilder baseDataValidator) { private void validateSavingsCharges(final JsonElement element, final DataValidatorBuilder baseDataValidator) {
if (element.isJsonObject()) { if (element.isJsonObject()) {
@@ -49,6 +49,7 @@ public class FixedDepositAccountData extends DepositAccountData {
private EnumOptionData onAccountClosure; private EnumOptionData onAccountClosure;
private final PortfolioAccountData linkedAccount; private final PortfolioAccountData linkedAccount;
private final Boolean transferInterestToSavings;
private Collection<EnumOptionData> interestFreePeriodTypeOptions; private Collection<EnumOptionData> interestFreePeriodTypeOptions;
private Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions; private Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions;
@@ -68,7 +69,7 @@ public class FixedDepositAccountData extends DepositAccountData {
final EnumOptionData minDepositTermType, final EnumOptionData maxDepositTermType, final Integer inMultiplesOfDepositTerm, final EnumOptionData minDepositTermType, final EnumOptionData maxDepositTermType, final Integer inMultiplesOfDepositTerm,
final EnumOptionData inMultiplesOfDepositTermType, final BigDecimal depositAmount, final BigDecimal maturityAmount, final EnumOptionData inMultiplesOfDepositTermType, final BigDecimal depositAmount, final BigDecimal maturityAmount,
final LocalDate maturityDate, final Integer depositPeriod, final EnumOptionData depositPeriodFrequency, final LocalDate maturityDate, final Integer depositPeriod, final EnumOptionData depositPeriodFrequency,
final EnumOptionData onAccountClosure) { final EnumOptionData onAccountClosure, final Boolean transferInterestToSavings) {
final PortfolioAccountData linkedAccount = null; final PortfolioAccountData linkedAccount = null;
final Collection<EnumOptionData> interestFreePeriodTypeOptions = null; final Collection<EnumOptionData> interestFreePeriodTypeOptions = null;
@@ -101,7 +102,7 @@ public class FixedDepositAccountData extends DepositAccountData {
maxDepositTermType, inMultiplesOfDepositTerm, inMultiplesOfDepositTermType, depositAmount, maturityAmount, maturityDate, maxDepositTermType, inMultiplesOfDepositTerm, inMultiplesOfDepositTermType, depositAmount, maturityAmount, maturityDate,
depositPeriod, depositPeriodFrequency, depositTermTypeOptions, inMultiplesOfDepositTermTypeOptions, depositPeriod, depositPeriodFrequency, depositTermTypeOptions, inMultiplesOfDepositTermTypeOptions,
depositPeriodFrequencyOptions, depositType, onAccountClosure, onAccountClosureOptions, paymentTypeOptions, depositPeriodFrequencyOptions, depositType, onAccountClosure, onAccountClosureOptions, paymentTypeOptions,
savingsAccountDatas, linkedAccount); savingsAccountDatas, linkedAccount, transferInterestToSavings);
} }
public static FixedDepositAccountData withInterestChart(final FixedDepositAccountData account, public static FixedDepositAccountData withInterestChart(final FixedDepositAccountData account,
@@ -123,7 +124,8 @@ public class FixedDepositAccountData extends DepositAccountData {
account.inMultiplesOfDepositTerm, account.inMultiplesOfDepositTermType, account.depositAmount, account.maturityAmount, account.inMultiplesOfDepositTerm, account.inMultiplesOfDepositTermType, account.depositAmount, account.maturityAmount,
account.maturityDate, account.depositPeriod, account.depositPeriodFrequency, account.depositTermTypeOptions, account.maturityDate, account.depositPeriod, account.depositPeriodFrequency, account.depositTermTypeOptions,
account.inMultiplesOfDepositTermTypeOptions, account.depositTermTypeOptions, account.depositType, account.onAccountClosure, account.inMultiplesOfDepositTermTypeOptions, account.depositTermTypeOptions, account.depositType, account.onAccountClosure,
account.onAccountClosureOptions, account.paymentTypeOptions, account.savingsAccounts, account.linkedAccount); account.onAccountClosureOptions, account.paymentTypeOptions, account.savingsAccounts, account.linkedAccount,
account.transferInterestToSavings);
} }
public static FixedDepositAccountData associationsAndTemplate(final FixedDepositAccountData account, FixedDepositAccountData template, public static FixedDepositAccountData associationsAndTemplate(final FixedDepositAccountData account, FixedDepositAccountData template,
@@ -152,7 +154,7 @@ public class FixedDepositAccountData extends DepositAccountData {
account.maturityAmount, account.maturityDate, account.depositPeriod, account.depositPeriodFrequency, account.maturityAmount, account.maturityDate, account.depositPeriod, account.depositPeriodFrequency,
template.depositTermTypeOptions, template.inMultiplesOfDepositTermTypeOptions, template.depositPeriodFrequencyOptions, template.depositTermTypeOptions, template.inMultiplesOfDepositTermTypeOptions, template.depositPeriodFrequencyOptions,
account.depositType, account.onAccountClosure, account.onAccountClosureOptions, account.paymentTypeOptions, account.depositType, account.onAccountClosure, account.onAccountClosureOptions, account.paymentTypeOptions,
template.savingsAccounts, linkedAccount); template.savingsAccounts, linkedAccount, account.transferInterestToSavings);
} }
public static FixedDepositAccountData withTemplateOptions(final FixedDepositAccountData account, public static FixedDepositAccountData withTemplateOptions(final FixedDepositAccountData account,
@@ -184,7 +186,8 @@ public class FixedDepositAccountData extends DepositAccountData {
account.inMultiplesOfDepositTerm, account.inMultiplesOfDepositTermType, account.depositAmount, account.maturityAmount, account.inMultiplesOfDepositTerm, account.inMultiplesOfDepositTermType, account.depositAmount, account.maturityAmount,
account.maturityDate, account.depositPeriod, account.depositPeriodFrequency, depositTermTypeOptions, account.maturityDate, account.depositPeriod, account.depositPeriodFrequency, depositTermTypeOptions,
inMultiplesOfDepositTermTypeOptions, depositPeriodFrequencyOptions, account.depositType, account.onAccountClosure, inMultiplesOfDepositTermTypeOptions, depositPeriodFrequencyOptions, account.depositType, account.onAccountClosure,
account.onAccountClosureOptions, account.paymentTypeOptions, savingsAccounts, account.linkedAccount); account.onAccountClosureOptions, account.paymentTypeOptions, savingsAccounts, account.linkedAccount,
account.transferInterestToSavings);
} }
public static FixedDepositAccountData withClientTemplate(final Long clientId, final String clientName, final Long groupId, public static FixedDepositAccountData withClientTemplate(final Long clientId, final String clientName, final Long groupId,
@@ -246,6 +249,7 @@ public class FixedDepositAccountData extends DepositAccountData {
final EnumOptionData depositPeriodFrequency = null; final EnumOptionData depositPeriodFrequency = null;
final EnumOptionData onAccountClosure = null; final EnumOptionData onAccountClosure = null;
final PortfolioAccountData linkedAccount = null; final PortfolioAccountData linkedAccount = null;
final Boolean transferInterestToSavings = null;
final Collection<EnumOptionData> interestFreePeriodTypeOptions = null; final Collection<EnumOptionData> interestFreePeriodTypeOptions = null;
final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions = null; final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions = null;
@@ -269,7 +273,8 @@ public class FixedDepositAccountData extends DepositAccountData {
preClosurePenalInterestOnTypeOptions, minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType, preClosurePenalInterestOnTypeOptions, minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType,
inMultiplesOfDepositTerm, inMultiplesOfDepositTermType, depositAmount, maturityAmount, maturityDate, depositPeriod, inMultiplesOfDepositTerm, inMultiplesOfDepositTermType, depositAmount, maturityAmount, maturityDate, depositPeriod,
depositPeriodFrequency, depositTermTypeOptions, inMultiplesOfDepositTermTypeOptions, depositPeriodFrequencyOptions, depositPeriodFrequency, depositTermTypeOptions, inMultiplesOfDepositTermTypeOptions, depositPeriodFrequencyOptions,
depositType, onAccountClosure, onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas, linkedAccount); depositType, onAccountClosure, onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas, linkedAccount,
transferInterestToSavings);
} }
public static FixedDepositAccountData preClosureDetails(final Long accountId, BigDecimal maturityAmount, public static FixedDepositAccountData preClosureDetails(final Long accountId, BigDecimal maturityAmount,
@@ -333,6 +338,7 @@ public class FixedDepositAccountData extends DepositAccountData {
final Integer depositPeriod = null; final Integer depositPeriod = null;
final EnumOptionData depositPeriodFrequency = null; final EnumOptionData depositPeriodFrequency = null;
final EnumOptionData onAccountClosure = null; final EnumOptionData onAccountClosure = null;
final Boolean transferInterestToSavings = null;
final Collection<EnumOptionData> interestFreePeriodTypeOptions = null; final Collection<EnumOptionData> interestFreePeriodTypeOptions = null;
final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions = null; final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions = null;
@@ -354,7 +360,8 @@ public class FixedDepositAccountData extends DepositAccountData {
preClosurePenalInterestOnTypeOptions, minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType, preClosurePenalInterestOnTypeOptions, minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType,
inMultiplesOfDepositTerm, inMultiplesOfDepositTermType, depositAmount, maturityAmount, maturityDate, depositPeriod, inMultiplesOfDepositTerm, inMultiplesOfDepositTermType, depositAmount, maturityAmount, maturityDate, depositPeriod,
depositPeriodFrequency, depositTermTypeOptions, inMultiplesOfDepositTermTypeOptions, depositPeriodFrequencyOptions, depositPeriodFrequency, depositTermTypeOptions, inMultiplesOfDepositTermTypeOptions, depositPeriodFrequencyOptions,
depositType, onAccountClosure, onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas, linkedAccount); depositType, onAccountClosure, onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas, linkedAccount,
transferInterestToSavings);
} }
public static FixedDepositAccountData withClosureTemplateDetails(final FixedDepositAccountData account, public static FixedDepositAccountData withClosureTemplateDetails(final FixedDepositAccountData account,
@@ -378,7 +385,8 @@ public class FixedDepositAccountData extends DepositAccountData {
account.inMultiplesOfDepositTerm, account.inMultiplesOfDepositTermType, account.depositAmount, account.maturityAmount, account.inMultiplesOfDepositTerm, account.inMultiplesOfDepositTermType, account.depositAmount, account.maturityAmount,
account.maturityDate, account.depositPeriod, account.depositPeriodFrequency, account.depositTermTypeOptions, account.maturityDate, account.depositPeriod, account.depositPeriodFrequency, account.depositTermTypeOptions,
account.inMultiplesOfDepositTermTypeOptions, account.depositPeriodFrequencyOptions, account.depositType, account.inMultiplesOfDepositTermTypeOptions, account.depositPeriodFrequencyOptions, account.depositType,
account.onAccountClosure, onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas, account.linkedAccount); account.onAccountClosure, onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas, account.linkedAccount,
account.transferInterestToSavings);
} }
private FixedDepositAccountData(final Long id, final String accountNo, final String externalId, final Long groupId, private FixedDepositAccountData(final Long id, final String accountNo, final String externalId, final Long groupId,
@@ -411,7 +419,7 @@ public class FixedDepositAccountData extends DepositAccountData {
final Collection<EnumOptionData> depositPeriodFrequencyOptions, final EnumOptionData depositType, final Collection<EnumOptionData> depositPeriodFrequencyOptions, final EnumOptionData depositType,
final EnumOptionData onAccountClosure, final Collection<EnumOptionData> onAccountClosureOptions, final EnumOptionData onAccountClosure, final Collection<EnumOptionData> onAccountClosureOptions,
final Collection<CodeValueData> paymentTypeOptions, final Collection<SavingsAccountData> savingsAccountDatas, final Collection<CodeValueData> paymentTypeOptions, final Collection<SavingsAccountData> savingsAccountDatas,
final PortfolioAccountData linkedAccount) { final PortfolioAccountData linkedAccount, final Boolean transferInterestToSavings) {
super(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName, fieldofficerId, super(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName, fieldofficerId,
fieldofficerName, status, timeline, currency, nominalAnnualInterestRate, interestPeriodType, interestPostingPeriodType, fieldofficerName, status, timeline, currency, nominalAnnualInterestRate, interestPeriodType, interestPostingPeriodType,
@@ -442,6 +450,7 @@ public class FixedDepositAccountData extends DepositAccountData {
this.depositPeriodFrequency = depositPeriodFrequency; this.depositPeriodFrequency = depositPeriodFrequency;
this.onAccountClosure = onAccountClosure; this.onAccountClosure = onAccountClosure;
this.linkedAccount = linkedAccount; this.linkedAccount = linkedAccount;
this.transferInterestToSavings = transferInterestToSavings;
// template // template
this.interestFreePeriodTypeOptions = interestFreePeriodTypeOptions; this.interestFreePeriodTypeOptions = interestFreePeriodTypeOptions;
@@ -9,11 +9,12 @@ import static org.mifosplatform.portfolio.savings.DepositsApiConstants.chartIdPa
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.depositAmountParamName; import static org.mifosplatform.portfolio.savings.DepositsApiConstants.depositAmountParamName;
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.depositPeriodFrequencyIdParamName; import static org.mifosplatform.portfolio.savings.DepositsApiConstants.depositPeriodFrequencyIdParamName;
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.depositPeriodParamName; import static org.mifosplatform.portfolio.savings.DepositsApiConstants.depositPeriodParamName;
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.expectedFirstDepositOnDateParamName;
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.recurringDepositAmountParamName; import static org.mifosplatform.portfolio.savings.DepositsApiConstants.recurringDepositAmountParamName;
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.recurringDepositFrequencyParamName; import static org.mifosplatform.portfolio.savings.DepositsApiConstants.recurringDepositFrequencyParamName;
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.recurringDepositFrequencyTypeIdParamName; import static org.mifosplatform.portfolio.savings.DepositsApiConstants.recurringDepositFrequencyTypeIdParamName;
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.recurringDepositTypeIdParamName; import static org.mifosplatform.portfolio.savings.DepositsApiConstants.recurringDepositTypeIdParamName;
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.expectedFirstDepositOnDateParamName; import static org.mifosplatform.portfolio.savings.DepositsApiConstants.transferInterestToSavingsParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.accountNoParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.accountNoParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.clientIdParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.clientIdParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.externalIdParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.externalIdParamName;
@@ -40,6 +41,7 @@ import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.infrastructure.core.service.DateUtils; import org.mifosplatform.infrastructure.core.service.DateUtils;
import org.mifosplatform.organisation.staff.domain.Staff; import org.mifosplatform.organisation.staff.domain.Staff;
import org.mifosplatform.organisation.staff.domain.StaffRepositoryWrapper; import org.mifosplatform.organisation.staff.domain.StaffRepositoryWrapper;
import org.mifosplatform.portfolio.account.service.AccountTransfersReadPlatformService;
import org.mifosplatform.portfolio.accountdetails.domain.AccountType; import org.mifosplatform.portfolio.accountdetails.domain.AccountType;
import org.mifosplatform.portfolio.client.domain.Client; import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper; import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper;
@@ -71,7 +73,7 @@ import com.google.gson.JsonElement;
public class DepositAccountAssembler { public class DepositAccountAssembler {
private final SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper; private final SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper;
private final SavingsHelper savingsHelper = new SavingsHelper(); private final SavingsHelper savingsHelper;
private final ClientRepositoryWrapper clientRepository; private final ClientRepositoryWrapper clientRepository;
private final GroupRepositoryWrapper groupRepository; private final GroupRepositoryWrapper groupRepository;
private final StaffRepositoryWrapper staffRepository; private final StaffRepositoryWrapper staffRepository;
@@ -88,7 +90,9 @@ public class DepositAccountAssembler {
final StaffRepositoryWrapper staffRepository, final FixedDepositProductRepository fixedDepositProductRepository, final StaffRepositoryWrapper staffRepository, final FixedDepositProductRepository fixedDepositProductRepository,
final SavingsAccountRepositoryWrapper savingsAccountRepository, final SavingsAccountRepositoryWrapper savingsAccountRepository,
final SavingsAccountChargeAssembler savingsAccountChargeAssembler, final FromJsonHelper fromApiJsonHelper, final SavingsAccountChargeAssembler savingsAccountChargeAssembler, final FromJsonHelper fromApiJsonHelper,
final DepositProductAssembler depositProductAssembler, final RecurringDepositProductRepository recurringDepositProductRepository) { final DepositProductAssembler depositProductAssembler,
final RecurringDepositProductRepository recurringDepositProductRepository,
final AccountTransfersReadPlatformService accountTransfersReadPlatformService) {
this.savingsAccountTransactionSummaryWrapper = savingsAccountTransactionSummaryWrapper; this.savingsAccountTransactionSummaryWrapper = savingsAccountTransactionSummaryWrapper;
this.clientRepository = clientRepository; this.clientRepository = clientRepository;
this.groupRepository = groupRepository; this.groupRepository = groupRepository;
@@ -99,6 +103,7 @@ public class DepositAccountAssembler {
this.fromApiJsonHelper = fromApiJsonHelper; this.fromApiJsonHelper = fromApiJsonHelper;
this.depositProductAssembler = depositProductAssembler; this.depositProductAssembler = depositProductAssembler;
this.recurringDepositProductRepository = recurringDepositProductRepository; this.recurringDepositProductRepository = recurringDepositProductRepository;
this.savingsHelper = new SavingsHelper(accountTransfersReadPlatformService);
} }
/** /**
@@ -314,6 +319,7 @@ public class DepositAccountAssembler {
final SavingsPeriodFrequencyType depositPeriodFrequency = SavingsPeriodFrequencyType.fromInt(depositPeriodFrequencyId); final SavingsPeriodFrequencyType depositPeriodFrequency = SavingsPeriodFrequencyType.fromInt(depositPeriodFrequencyId);
final SavingsAccount account = null; final SavingsAccount account = null;
final LocalDate expectedFirstDepositOnDate = command.localDateValueOfParameterNamed(expectedFirstDepositOnDateParamName); final LocalDate expectedFirstDepositOnDate = command.localDateValueOfParameterNamed(expectedFirstDepositOnDateParamName);
final Boolean trasferInterest = command.booleanPrimitiveValueOfParameterNamed(transferInterestToSavingsParamName);
// calculate maturity amount // calculate maturity amount
final BigDecimal maturityAmount = null;// calculated and updated in final BigDecimal maturityAmount = null;// calculated and updated in
@@ -321,7 +327,8 @@ public class DepositAccountAssembler {
final LocalDate maturityDate = null;// calculated and updated in account final LocalDate maturityDate = null;// calculated and updated in account
final DepositAccountOnClosureType accountOnClosureType = null; final DepositAccountOnClosureType accountOnClosureType = null;
return DepositAccountTermAndPreClosure.createNew(updatedProductPreClosure, updatedProductTerm, account, depositAmount, return DepositAccountTermAndPreClosure.createNew(updatedProductPreClosure, updatedProductTerm, account, depositAmount,
maturityAmount, maturityDate, depositPeriod, depositPeriodFrequency, expectedFirstDepositOnDate, accountOnClosureType); maturityAmount, maturityDate, depositPeriod, depositPeriodFrequency, expectedFirstDepositOnDate, accountOnClosureType,
trasferInterest);
} }
public DepositAccountRecurringDetail assembleAccountRecurringDetail(final JsonCommand command, public DepositAccountRecurringDetail assembleAccountRecurringDetail(final JsonCommand command,
@@ -82,14 +82,14 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount, final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
paymentDetail, new Date()); paymentDetail, new Date());
final SavingsAccountTransaction withdrawal = account.withdraw(transactionDTO, applyWithdrawFee); final SavingsAccountTransaction withdrawal = account.withdraw(transactionDTO, applyWithdrawFee);
boolean isInterestTransfer = false;
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
if (account.isBeforeLastPostingPeriod(transactionDate)) { if (account.isBeforeLastPostingPeriod(transactionDate)) {
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
account.postInterest(mc, today); account.postInterest(mc, today, isInterestTransfer);
} else { } else {
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
account.calculateInterestUsing(mc, today); account.calculateInterestUsing(mc, today, isInterestTransfer);
} }
account.validateAccountBalanceDoesNotBecomeNegative(transactionAmount); account.validateAccountBalanceDoesNotBecomeNegative(transactionAmount);
saveTransactionToGenerateTransactionId(withdrawal); saveTransactionToGenerateTransactionId(withdrawal);
@@ -111,14 +111,14 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount, final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
paymentDetail, new Date()); paymentDetail, new Date());
final SavingsAccountTransaction deposit = account.deposit(transactionDTO); final SavingsAccountTransaction deposit = account.deposit(transactionDTO);
boolean isInterestTransfer = false;
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
if (account.isBeforeLastPostingPeriod(transactionDate)) { if (account.isBeforeLastPostingPeriod(transactionDate)) {
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
account.postInterest(mc, today); account.postInterest(mc, today, isInterestTransfer);
} else { } else {
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
account.calculateInterestUsing(mc, today); account.calculateInterestUsing(mc, today, isInterestTransfer);
} }
saveTransactionToGenerateTransactionId(deposit); saveTransactionToGenerateTransactionId(deposit);
@@ -9,6 +9,7 @@ import static org.mifosplatform.portfolio.savings.DepositsApiConstants.depositAm
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.depositPeriodFrequencyIdParamName; import static org.mifosplatform.portfolio.savings.DepositsApiConstants.depositPeriodFrequencyIdParamName;
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.depositPeriodParamName; import static org.mifosplatform.portfolio.savings.DepositsApiConstants.depositPeriodParamName;
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.expectedFirstDepositOnDateParamName; import static org.mifosplatform.portfolio.savings.DepositsApiConstants.expectedFirstDepositOnDateParamName;
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.transferInterestToSavingsParamName;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
@@ -75,6 +76,9 @@ public class DepositAccountTermAndPreClosure extends AbstractPersistable<Long> {
@JoinColumn(name = "savings_account_id", nullable = false) @JoinColumn(name = "savings_account_id", nullable = false)
private SavingsAccount account; private SavingsAccount account;
@Column(name = "transfer_interest_to_linked_account", nullable = false)
private boolean transferInterestToLinkedAccount;
protected DepositAccountTermAndPreClosure() { protected DepositAccountTermAndPreClosure() {
super(); super();
} }
@@ -82,16 +86,16 @@ public class DepositAccountTermAndPreClosure extends AbstractPersistable<Long> {
public static DepositAccountTermAndPreClosure createNew(DepositPreClosureDetail preClosureDetail, DepositTermDetail depositTermDetail, public static DepositAccountTermAndPreClosure createNew(DepositPreClosureDetail preClosureDetail, DepositTermDetail depositTermDetail,
SavingsAccount account, BigDecimal depositAmount, BigDecimal maturityAmount, final LocalDate maturityDate, SavingsAccount account, BigDecimal depositAmount, BigDecimal maturityAmount, final LocalDate maturityDate,
Integer depositPeriod, final SavingsPeriodFrequencyType depositPeriodFrequency, final LocalDate expectedFirstDepositOnDate, Integer depositPeriod, final SavingsPeriodFrequencyType depositPeriodFrequency, final LocalDate expectedFirstDepositOnDate,
final DepositAccountOnClosureType accountOnClosureType) { final DepositAccountOnClosureType accountOnClosureType, Boolean trasferInterest) {
return new DepositAccountTermAndPreClosure(preClosureDetail, depositTermDetail, account, depositAmount, maturityAmount, return new DepositAccountTermAndPreClosure(preClosureDetail, depositTermDetail, account, depositAmount, maturityAmount,
maturityDate, depositPeriod, depositPeriodFrequency, expectedFirstDepositOnDate, accountOnClosureType); maturityDate, depositPeriod, depositPeriodFrequency, expectedFirstDepositOnDate, accountOnClosureType, trasferInterest);
} }
private DepositAccountTermAndPreClosure(DepositPreClosureDetail preClosureDetail, DepositTermDetail depositTermDetail, private DepositAccountTermAndPreClosure(DepositPreClosureDetail preClosureDetail, DepositTermDetail depositTermDetail,
SavingsAccount account, BigDecimal depositAmount, BigDecimal maturityAmount, final LocalDate maturityDate, SavingsAccount account, BigDecimal depositAmount, BigDecimal maturityAmount, final LocalDate maturityDate,
Integer depositPeriod, final SavingsPeriodFrequencyType depositPeriodFrequency, final LocalDate expectedFirstDepositOnDate, Integer depositPeriod, final SavingsPeriodFrequencyType depositPeriodFrequency, final LocalDate expectedFirstDepositOnDate,
final DepositAccountOnClosureType accountOnClosureType) { final DepositAccountOnClosureType accountOnClosureType, Boolean transferInterest) {
this.depositAmount = depositAmount; this.depositAmount = depositAmount;
this.maturityAmount = maturityAmount; this.maturityAmount = maturityAmount;
this.maturityDate = (maturityDate == null) ? null : maturityDate.toDate(); this.maturityDate = (maturityDate == null) ? null : maturityDate.toDate();
@@ -102,6 +106,7 @@ public class DepositAccountTermAndPreClosure extends AbstractPersistable<Long> {
this.account = account; this.account = account;
this.expectedFirstDepositOnDate = expectedFirstDepositOnDate == null ? null : expectedFirstDepositOnDate.toDate(); this.expectedFirstDepositOnDate = expectedFirstDepositOnDate == null ? null : expectedFirstDepositOnDate.toDate();
this.onAccountClosureType = (accountOnClosureType == null) ? null : accountOnClosureType.getValue(); this.onAccountClosureType = (accountOnClosureType == null) ? null : accountOnClosureType.getValue();
this.transferInterestToLinkedAccount = transferInterest;
} }
public Map<String, Object> update(final JsonCommand command, final DataValidatorBuilder baseDataValidator) { public Map<String, Object> update(final JsonCommand command, final DataValidatorBuilder baseDataValidator) {
@@ -137,6 +142,12 @@ public class DepositAccountTermAndPreClosure extends AbstractPersistable<Long> {
this.expectedFirstDepositOnDate = newValue.toDate(); this.expectedFirstDepositOnDate = newValue.toDate();
} }
if (command.isChangeInBooleanParameterNamed(transferInterestToSavingsParamName, this.transferInterestToLinkedAccount)) {
final Boolean newValue = command.booleanPrimitiveValueOfParameterNamed(transferInterestToSavingsParamName);
actualChanges.put(transferInterestToSavingsParamName, newValue);
this.transferInterestToLinkedAccount = newValue;
}
if (this.preClosureDetail != null) { if (this.preClosureDetail != null) {
actualChanges.putAll(this.preClosureDetail.update(command, baseDataValidator)); actualChanges.putAll(this.preClosureDetail.update(command, baseDataValidator));
} }
@@ -262,13 +273,20 @@ public class DepositAccountTermAndPreClosure extends AbstractPersistable<Long> {
final DepositPreClosureDetail preClosureDetail = this.preClosureDetail.copy(); final DepositPreClosureDetail preClosureDetail = this.preClosureDetail.copy();
final DepositTermDetail depositTermDetail = this.depositTermDetail.copy(); final DepositTermDetail depositTermDetail = this.depositTermDetail.copy();
final LocalDate expectedFirstDepositOnDate = null; final LocalDate expectedFirstDepositOnDate = null;
final Boolean transferInterestToLinkedAccount = null;
final DepositAccountOnClosureType accountOnClosureType = null; final DepositAccountOnClosureType accountOnClosureType = null;
return DepositAccountTermAndPreClosure.createNew(preClosureDetail, depositTermDetail, account, actualDepositAmount, maturityAmount, return DepositAccountTermAndPreClosure.createNew(preClosureDetail, depositTermDetail, account, actualDepositAmount, maturityAmount,
maturityDate, depositPeriod, depositPeriodFrequency, expectedFirstDepositOnDate, accountOnClosureType); maturityDate, depositPeriod, depositPeriodFrequency, expectedFirstDepositOnDate, accountOnClosureType,
transferInterestToLinkedAccount);
} }
public void updateExpectedFirstDepositDate(final LocalDate expectedFirstDepositOnDate) { public void updateExpectedFirstDepositDate(final LocalDate expectedFirstDepositOnDate) {
this.expectedFirstDepositOnDate = expectedFirstDepositOnDate.toDate(); this.expectedFirstDepositOnDate = expectedFirstDepositOnDate.toDate();
} }
public boolean isTransferInterestToLinkedAccount() {
return this.transferInterestToLinkedAccount;
}
} }
@@ -13,6 +13,7 @@ import static org.mifosplatform.portfolio.savings.DepositsApiConstants.onAccount
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.MathContext; import java.math.MathContext;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@@ -259,11 +260,13 @@ public class FixedDepositAccount extends SavingsAccount {
final SavingsInterestCalculationType interestCalculationType = SavingsInterestCalculationType.fromInt(this.interestCalculationType); final SavingsInterestCalculationType interestCalculationType = SavingsInterestCalculationType.fromInt(this.interestCalculationType);
final BigDecimal interestRateAsFraction = getEffectiveInterestRateAsFraction(mc, maturityDate); final BigDecimal interestRateAsFraction = getEffectiveInterestRateAsFraction(mc, maturityDate);
final Collection<Long> interestPostTransactions = this.savingsHelper.fetchPostInterestTransactionIds(getId());
boolean isInterestTransfer = false;
for (final LocalDateInterval periodInterval : postingPeriodIntervals) { for (final LocalDateInterval periodInterval : postingPeriodIntervals) {
final PostingPeriod postingPeriod = PostingPeriod.createFrom(periodInterval, periodStartingBalance, transactions, final PostingPeriod postingPeriod = PostingPeriod.createFrom(periodInterval, periodStartingBalance, transactions,
this.currency, compoundingPeriodType, interestCalculationType, interestRateAsFraction, daysInYearType.getValue(), this.currency, compoundingPeriodType, interestCalculationType, interestRateAsFraction, daysInYearType.getValue(),
maturityDate); maturityDate, interestPostTransactions, isInterestTransfer);
periodStartingBalance = postingPeriod.closingBalance(); periodStartingBalance = postingPeriod.closingBalance();
@@ -271,7 +274,8 @@ public class FixedDepositAccount extends SavingsAccount {
} }
this.summary.updateFromInterestPeriodSummaries(this.currency, allPostingPeriods); this.summary.updateFromInterestPeriodSummaries(this.currency, allPostingPeriods);
this.savingsHelper.calculateInterestForAllPostingPeriods(this.currency, allPostingPeriods); this.savingsHelper.calculateInterestForAllPostingPeriods(this.currency, allPostingPeriods, this.getLockedInUntilLocalDate(),
isTransferInterestToOtherAccount());
return allPostingPeriods; return allPostingPeriods;
} }
@@ -429,8 +433,8 @@ public class FixedDepositAccount extends SavingsAccount {
public void postMaturityInterest(final LocalDate interestPostingUpToDate) { public void postMaturityInterest(final LocalDate interestPostingUpToDate) {
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
final boolean isInterestTransfer = false;
final List<PostingPeriod> postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate); final List<PostingPeriod> postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer);
Money interestPostedToDate = Money.zero(this.currency); Money interestPostedToDate = Money.zero(this.currency);
@@ -526,15 +530,15 @@ public class FixedDepositAccount extends SavingsAccount {
} }
@Override @Override
public void postInterest(final MathContext mc, final LocalDate postingDate) { public void postInterest(final MathContext mc, final LocalDate postingDate, boolean isInterestTransfer) {
final LocalDate interestPostingUpToDate = interestPostingUpToDate(postingDate); final LocalDate interestPostingUpToDate = interestPostingUpToDate(postingDate);
super.postInterest(mc, interestPostingUpToDate); super.postInterest(mc, interestPostingUpToDate, isInterestTransfer);
} }
@Override @Override
public List<PostingPeriod> calculateInterestUsing(final MathContext mc, final LocalDate postingDate) { public List<PostingPeriod> calculateInterestUsing(final MathContext mc, final LocalDate postingDate, boolean isInterestTransfer) {
final LocalDate interestPostingUpToDate = interestPostingUpToDate(postingDate); final LocalDate interestPostingUpToDate = interestPostingUpToDate(postingDate);
return super.calculateInterestUsing(mc, interestPostingUpToDate); return super.calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer);
} }
private LocalDate interestPostingUpToDate(final LocalDate interestPostingDate) { private LocalDate interestPostingUpToDate(final LocalDate interestPostingDate) {
@@ -680,4 +684,9 @@ public class FixedDepositAccount extends SavingsAccount {
return reInvestedAccount; return reInvestedAccount;
} }
@Override
protected boolean isTransferInterestToOtherAccount() {
return this.accountTermAndPreClosure.isTransferInterestToLinkedAccount();
}
} }
@@ -13,6 +13,7 @@ import static org.mifosplatform.portfolio.savings.DepositsApiConstants.onAccount
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.MathContext; import java.math.MathContext;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@@ -281,18 +282,20 @@ public class RecurringDepositAccount extends SavingsAccount {
final SavingsInterestCalculationType interestCalculationType = SavingsInterestCalculationType.fromInt(this.interestCalculationType); final SavingsInterestCalculationType interestCalculationType = SavingsInterestCalculationType.fromInt(this.interestCalculationType);
final BigDecimal interestRateAsFraction = getEffectiveInterestRateAsFraction(mc, maturityDate); final BigDecimal interestRateAsFraction = getEffectiveInterestRateAsFraction(mc, maturityDate);
final Collection<Long> interestPostTransactions = this.savingsHelper.fetchPostInterestTransactionIds(getId());
boolean isInterestTransfer = false;
for (final LocalDateInterval periodInterval : postingPeriodIntervals) { for (final LocalDateInterval periodInterval : postingPeriodIntervals) {
final PostingPeriod postingPeriod = PostingPeriod.createFrom(periodInterval, periodStartingBalance, transactions, final PostingPeriod postingPeriod = PostingPeriod.createFrom(periodInterval, periodStartingBalance, transactions,
this.currency, compoundingPeriodType, interestCalculationType, interestRateAsFraction, daysInYearType.getValue(), this.currency, compoundingPeriodType, interestCalculationType, interestRateAsFraction, daysInYearType.getValue(),
maturityDate); maturityDate, interestPostTransactions, isInterestTransfer);
periodStartingBalance = postingPeriod.closingBalance(); periodStartingBalance = postingPeriod.closingBalance();
allPostingPeriods.add(postingPeriod); allPostingPeriods.add(postingPeriod);
} }
this.savingsHelper.calculateInterestForAllPostingPeriods(this.currency, allPostingPeriods); this.savingsHelper.calculateInterestForAllPostingPeriods(this.currency, allPostingPeriods, this.getLockedInUntilLocalDate(),
isTransferInterestToOtherAccount());
// this.summary.updateFromInterestPeriodSummaries(this.currency, // this.summary.updateFromInterestPeriodSummaries(this.currency,
// allPostingPeriods); // allPostingPeriods);
return allPostingPeriods; return allPostingPeriods;
@@ -538,8 +541,8 @@ public class RecurringDepositAccount extends SavingsAccount {
public void postMaturityInterest(final LocalDate interestPostingUpToDate) { public void postMaturityInterest(final LocalDate interestPostingUpToDate) {
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
boolean isInterestTransfer = false;
final List<PostingPeriod> postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate); final List<PostingPeriod> postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate,isInterestTransfer);
Money interestPostedToDate = Money.zero(this.currency); Money interestPostedToDate = Money.zero(this.currency);
@@ -634,15 +637,15 @@ public class RecurringDepositAccount extends SavingsAccount {
} }
@Override @Override
public void postInterest(final MathContext mc, final LocalDate postingDate) { public void postInterest(final MathContext mc, final LocalDate postingDate,final boolean isInterestTransfer) {
final LocalDate interestPostingUpToDate = interestPostingUpToDate(postingDate); final LocalDate interestPostingUpToDate = interestPostingUpToDate(postingDate);
super.postInterest(mc, interestPostingUpToDate); super.postInterest(mc, interestPostingUpToDate, isInterestTransfer);
} }
@Override @Override
public List<PostingPeriod> calculateInterestUsing(final MathContext mc, final LocalDate postingDate) { public List<PostingPeriod> calculateInterestUsing(final MathContext mc, final LocalDate postingDate, boolean isInterestTransfer) {
final LocalDate interestPostingUpToDate = interestPostingUpToDate(postingDate); final LocalDate interestPostingUpToDate = interestPostingUpToDate(postingDate);
return super.calculateInterestUsing(mc, interestPostingUpToDate); return super.calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer);
} }
private LocalDate interestPostingUpToDate(final LocalDate interestPostingDate) { private LocalDate interestPostingUpToDate(final LocalDate interestPostingDate) {
@@ -891,4 +894,8 @@ public class RecurringDepositAccount extends SavingsAccount {
this.activatedOnDate = now.toDate(); this.activatedOnDate = now.toDate();
} }
@Override
protected boolean isTransferInterestToOtherAccount() {
return this.accountTermAndPreClosure.isTransferInterestToLinkedAccount();
}
} }
@@ -370,9 +370,9 @@ public class SavingsAccount extends AbstractPersistable<Long> {
return SavingsAccountStatusType.fromInt(this.status).isClosed(); return SavingsAccountStatusType.fromInt(this.status).isClosed();
} }
public void postInterest(final MathContext mc, final LocalDate interestPostingUpToDate) { public void postInterest(final MathContext mc, final LocalDate interestPostingUpToDate, final boolean isInterestTransfer) {
final List<PostingPeriod> postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate); final List<PostingPeriod> postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer);
Money interestPostedToDate = Money.zero(this.currency); Money interestPostedToDate = Money.zero(this.currency);
@@ -447,8 +447,9 @@ public class SavingsAccount extends AbstractPersistable<Long> {
* calculate the amount of interest due at the end of each 'crediting' * calculate the amount of interest due at the end of each 'crediting'
* period check if an existing 'interest posting' transaction exists for * period check if an existing 'interest posting' transaction exists for
* date and matches the amount posted * date and matches the amount posted
* @param isInterestTransfer TODO
*/ */
public List<PostingPeriod> calculateInterestUsing(final MathContext mc, final LocalDate upToInterestCalculationDate) { public List<PostingPeriod> calculateInterestUsing(final MathContext mc, final LocalDate upToInterestCalculationDate, boolean isInterestTransfer) {
// no openingBalance concept supported yet but probably will to allow // no openingBalance concept supported yet but probably will to allow
// for migrations. // for migrations.
@@ -480,18 +481,20 @@ public class SavingsAccount extends AbstractPersistable<Long> {
final SavingsInterestCalculationType interestCalculationType = SavingsInterestCalculationType.fromInt(this.interestCalculationType); final SavingsInterestCalculationType interestCalculationType = SavingsInterestCalculationType.fromInt(this.interestCalculationType);
final BigDecimal interestRateAsFraction = getEffectiveInterestRateAsFraction(mc, upToInterestCalculationDate); final BigDecimal interestRateAsFraction = getEffectiveInterestRateAsFraction(mc, upToInterestCalculationDate);
final Collection<Long> interestPostTransactions = this.savingsHelper.fetchPostInterestTransactionIds(getId());
for (final LocalDateInterval periodInterval : postingPeriodIntervals) { for (final LocalDateInterval periodInterval : postingPeriodIntervals) {
final PostingPeriod postingPeriod = PostingPeriod.createFrom(periodInterval, periodStartingBalance, final PostingPeriod postingPeriod = PostingPeriod.createFrom(periodInterval, periodStartingBalance,
retreiveOrderedNonInterestPostingTransactions(), this.currency, compoundingPeriodType, interestCalculationType, retreiveOrderedNonInterestPostingTransactions(), this.currency, compoundingPeriodType, interestCalculationType,
interestRateAsFraction, daysInYearType.getValue(), upToInterestCalculationDate); interestRateAsFraction, daysInYearType.getValue(), upToInterestCalculationDate, interestPostTransactions, isInterestTransfer);
periodStartingBalance = postingPeriod.closingBalance(); periodStartingBalance = postingPeriod.closingBalance();
allPostingPeriods.add(postingPeriod); allPostingPeriods.add(postingPeriod);
} }
this.savingsHelper.calculateInterestForAllPostingPeriods(this.currency, allPostingPeriods); this.savingsHelper.calculateInterestForAllPostingPeriods(this.currency, allPostingPeriods, getLockedInUntilLocalDate(),
isTransferInterestToOtherAccount());
this.summary.updateFromInterestPeriodSummaries(this.currency, allPostingPeriods); this.summary.updateFromInterestPeriodSummaries(this.currency, allPostingPeriods);
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions); this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
@@ -809,7 +812,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
return isLocked; return isLocked;
} }
private LocalDate getLockedInUntilLocalDate() { protected LocalDate getLockedInUntilLocalDate() {
LocalDate lockedInUntilLocalDate = null; LocalDate lockedInUntilLocalDate = null;
if (this.lockedInUntilDate != null) { if (this.lockedInUntilDate != null) {
lockedInUntilLocalDate = new LocalDate(this.lockedInUntilDate); lockedInUntilLocalDate = new LocalDate(this.lockedInUntilDate);
@@ -2036,4 +2039,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
public DepositAccountType depositAccountType() { public DepositAccountType depositAccountType() {
return DepositAccountType.fromInt(depositType); return DepositAccountType.fromInt(depositType);
} }
protected boolean isTransferInterestToOtherAccount() {
return false;
}
} }
@@ -34,6 +34,7 @@ import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.infrastructure.core.service.DateUtils; import org.mifosplatform.infrastructure.core.service.DateUtils;
import org.mifosplatform.organisation.staff.domain.Staff; import org.mifosplatform.organisation.staff.domain.Staff;
import org.mifosplatform.organisation.staff.domain.StaffRepositoryWrapper; import org.mifosplatform.organisation.staff.domain.StaffRepositoryWrapper;
import org.mifosplatform.portfolio.account.service.AccountTransfersReadPlatformService;
import org.mifosplatform.portfolio.accountdetails.domain.AccountType; import org.mifosplatform.portfolio.accountdetails.domain.AccountType;
import org.mifosplatform.portfolio.client.domain.Client; import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper; import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper;
@@ -59,7 +60,7 @@ import com.google.gson.JsonElement;
public class SavingsAccountAssembler { public class SavingsAccountAssembler {
private final SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper; private final SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper;
private final SavingsHelper savingsHelper = new SavingsHelper(); private final SavingsHelper savingsHelper;
private final ClientRepositoryWrapper clientRepository; private final ClientRepositoryWrapper clientRepository;
private final GroupRepositoryWrapper groupRepository; private final GroupRepositoryWrapper groupRepository;
private final StaffRepositoryWrapper staffRepository; private final StaffRepositoryWrapper staffRepository;
@@ -73,7 +74,8 @@ public class SavingsAccountAssembler {
final ClientRepositoryWrapper clientRepository, final GroupRepositoryWrapper groupRepository, final ClientRepositoryWrapper clientRepository, final GroupRepositoryWrapper groupRepository,
final StaffRepositoryWrapper staffRepository, final SavingsProductRepository savingProductRepository, final StaffRepositoryWrapper staffRepository, final SavingsProductRepository savingProductRepository,
final SavingsAccountRepositoryWrapper savingsAccountRepository, final SavingsAccountRepositoryWrapper savingsAccountRepository,
final SavingsAccountChargeAssembler savingsAccountChargeAssembler, final FromJsonHelper fromApiJsonHelper) { final SavingsAccountChargeAssembler savingsAccountChargeAssembler, final FromJsonHelper fromApiJsonHelper,
final AccountTransfersReadPlatformService accountTransfersReadPlatformService) {
this.savingsAccountTransactionSummaryWrapper = savingsAccountTransactionSummaryWrapper; this.savingsAccountTransactionSummaryWrapper = savingsAccountTransactionSummaryWrapper;
this.clientRepository = clientRepository; this.clientRepository = clientRepository;
this.groupRepository = groupRepository; this.groupRepository = groupRepository;
@@ -82,6 +84,7 @@ public class SavingsAccountAssembler {
this.savingsAccountRepository = savingsAccountRepository; this.savingsAccountRepository = savingsAccountRepository;
this.savingsAccountChargeAssembler = savingsAccountChargeAssembler; this.savingsAccountChargeAssembler = savingsAccountChargeAssembler;
this.fromApiJsonHelper = fromApiJsonHelper; this.fromApiJsonHelper = fromApiJsonHelper;
savingsHelper = new SavingsHelper(accountTransfersReadPlatformService);
} }
/** /**
@@ -14,7 +14,7 @@ import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
public interface SavingsAccountDomainService { public interface SavingsAccountDomainService {
SavingsAccountTransaction handleWithdrawal(SavingsAccount account, DateTimeFormatter fmt, LocalDate transactionDate, SavingsAccountTransaction handleWithdrawal(SavingsAccount account, DateTimeFormatter fmt, LocalDate transactionDate,
BigDecimal transactionAmount, PaymentDetail paymentDetail, boolean applyWithdrawFee); BigDecimal transactionAmount, PaymentDetail paymentDetail, boolean applyWithdrawFee, boolean isInterestTransfer);
SavingsAccountTransaction handleDeposit(SavingsAccount account, DateTimeFormatter fmt, LocalDate transactionDate, SavingsAccountTransaction handleDeposit(SavingsAccount account, DateTimeFormatter fmt, LocalDate transactionDate,
BigDecimal transactionAmount, PaymentDetail paymentDetail); BigDecimal transactionAmount, PaymentDetail paymentDetail);
@@ -48,7 +48,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
@Override @Override
public SavingsAccountTransaction handleWithdrawal(final SavingsAccount account, final DateTimeFormatter fmt, public SavingsAccountTransaction handleWithdrawal(final SavingsAccount account, final DateTimeFormatter fmt,
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail,
final boolean applyWithdrawFee) { final boolean applyWithdrawFee, boolean isInterestTransfer) {
final Set<Long> existingTransactionIds = new HashSet<Long>(); final Set<Long> existingTransactionIds = new HashSet<Long>();
final Set<Long> existingReversedTransactionIds = new HashSet<Long>(); final Set<Long> existingReversedTransactionIds = new HashSet<Long>();
@@ -60,10 +60,10 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
if (account.isBeforeLastPostingPeriod(transactionDate)) { if (account.isBeforeLastPostingPeriod(transactionDate)) {
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
account.postInterest(mc, today); account.postInterest(mc, today, isInterestTransfer);
} else { } else {
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
account.calculateInterestUsing(mc, today); account.calculateInterestUsing(mc, today, isInterestTransfer);
} }
account.validateAccountBalanceDoesNotBecomeNegative(transactionAmount); account.validateAccountBalanceDoesNotBecomeNegative(transactionAmount);
saveTransactionToGenerateTransactionId(withdrawal); saveTransactionToGenerateTransactionId(withdrawal);
@@ -79,6 +79,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
public SavingsAccountTransaction handleDeposit(final SavingsAccount account, final DateTimeFormatter fmt, public SavingsAccountTransaction handleDeposit(final SavingsAccount account, final DateTimeFormatter fmt,
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail) { final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail) {
boolean isInterestTransfer = false;
final Set<Long> existingTransactionIds = new HashSet<Long>(); final Set<Long> existingTransactionIds = new HashSet<Long>();
final Set<Long> existingReversedTransactionIds = new HashSet<Long>(); final Set<Long> existingReversedTransactionIds = new HashSet<Long>();
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
@@ -89,10 +90,10 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
if (account.isBeforeLastPostingPeriod(transactionDate)) { if (account.isBeforeLastPostingPeriod(transactionDate)) {
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
account.postInterest(mc, today); account.postInterest(mc, today, isInterestTransfer);
} else { } else {
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
account.calculateInterestUsing(mc, today); account.calculateInterestUsing(mc, today, isInterestTransfer);
} }
saveTransactionToGenerateTransactionId(deposit); saveTransactionToGenerateTransactionId(deposit);
@@ -445,13 +445,15 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
if (isDeposit()) { if (isDeposit()) {
// endOfDayBalance = openingBalance.plus(getAmount(currency)); // endOfDayBalance = openingBalance.plus(getAmount(currency));
// if (endOfDayBalance.isLessThanZero()) { // if (endOfDayBalance.isLessThanZero()) {
endOfDayBalance = Money.of(currency, this.runningBalance); endOfDayBalance = endOfDayBalance.plus(getAmount(currency));
// } // }
} else if (isWithdrawal() || isChargeTransactionAndNotReversed()) { } else if (isWithdrawal() || isChargeTransactionAndNotReversed()) {
// endOfDayBalance = openingBalance.minus(getAmount(currency)); // endOfDayBalance = openingBalance.minus(getAmount(currency));
// if (endOfDayBalance.isLessThanZero()) { if (endOfDayBalance.isGreaterThanZero()) {
endOfDayBalance = Money.of(currency, this.runningBalance); endOfDayBalance = endOfDayBalance.minus(getAmount(currency));
// } } else {
endOfDayBalance = Money.of(currency, this.runningBalance);
}
} }
} }
@@ -1,6 +1,7 @@
package org.mifosplatform.portfolio.savings.domain; package org.mifosplatform.portfolio.savings.domain;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import org.joda.time.DateTime; import org.joda.time.DateTime;
@@ -8,12 +9,19 @@ import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.domain.LocalDateInterval; import org.mifosplatform.infrastructure.core.domain.LocalDateInterval;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money; import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.portfolio.account.service.AccountTransfersReadPlatformService;
import org.mifosplatform.portfolio.savings.SavingsPostingInterestPeriodType; import org.mifosplatform.portfolio.savings.SavingsPostingInterestPeriodType;
import org.mifosplatform.portfolio.savings.domain.interest.CompoundInterestHelper; import org.mifosplatform.portfolio.savings.domain.interest.CompoundInterestHelper;
import org.mifosplatform.portfolio.savings.domain.interest.PostingPeriod; import org.mifosplatform.portfolio.savings.domain.interest.PostingPeriod;
public final class SavingsHelper { public final class SavingsHelper {
AccountTransfersReadPlatformService accountTransfersReadPlatformService = null;
public SavingsHelper(AccountTransfersReadPlatformService accountTransfersReadPlatformService) {
this.accountTransfersReadPlatformService = accountTransfersReadPlatformService;
}
private final CompoundInterestHelper compoundInterestHelper = new CompoundInterestHelper(); private final CompoundInterestHelper compoundInterestHelper = new CompoundInterestHelper();
public List<LocalDateInterval> determineInterestPostingPeriods(final LocalDate activationLocalDate, public List<LocalDateInterval> determineInterestPostingPeriods(final LocalDate activationLocalDate,
@@ -26,7 +34,8 @@ public final class SavingsHelper {
while (!periodStartDate.isAfter(interestPostingUpToDate) && !periodEndDate.isAfter(interestPostingUpToDate)) { while (!periodStartDate.isAfter(interestPostingUpToDate) && !periodEndDate.isAfter(interestPostingUpToDate)) {
final LocalDate interestPostingLocalDate = determineInterestPostingPeriodEndDateFrom(periodStartDate, postingPeriodType, interestPostingUpToDate); final LocalDate interestPostingLocalDate = determineInterestPostingPeriodEndDateFrom(periodStartDate, postingPeriodType,
interestPostingUpToDate);
periodEndDate = interestPostingLocalDate.minusDays(1); periodEndDate = interestPostingLocalDate.minusDays(1);
if (!interestPostingLocalDate.isAfter(interestPostingUpToDate)) { if (!interestPostingLocalDate.isAfter(interestPostingUpToDate)) {
@@ -61,7 +70,7 @@ public final class SavingsHelper {
final int monthofYear = periodStartDate.getMonthOfYear(); final int monthofYear = periodStartDate.getMonthOfYear();
if (monthofYear <= 3) { if (monthofYear <= 3) {
periodEndDate = new DateTime().withDate(year, 3, 31).toLocalDate(); periodEndDate = new DateTime().withDate(year, 3, 31).toLocalDate();
} else if (monthofYear <= 6) { } else if (monthofYear <= 6) {
periodEndDate = new DateTime().withDate(year, 6, 30).toLocalDate(); periodEndDate = new DateTime().withDate(year, 6, 30).toLocalDate();
} else if (monthofYear <= 9) { } else if (monthofYear <= 9) {
periodEndDate = new DateTime().withDate(year, 9, 30).toLocalDate(); periodEndDate = new DateTime().withDate(year, 9, 30).toLocalDate();
@@ -70,14 +79,14 @@ public final class SavingsHelper {
} }
break; break;
case BIANNUAL: case BIANNUAL:
final int byear = periodStartDate.getYearOfEra(); final int byear = periodStartDate.getYearOfEra();
final int bmonthofYear = periodStartDate.getMonthOfYear(); final int bmonthofYear = periodStartDate.getMonthOfYear();
if (bmonthofYear <= 6) { if (bmonthofYear <= 6) {
periodEndDate = new DateTime().withDate(byear, 6, 30).toLocalDate(); periodEndDate = new DateTime().withDate(byear, 6, 30).toLocalDate();
} else if (bmonthofYear <= 12) { } else if (bmonthofYear <= 12) {
periodEndDate = new DateTime().withDate(byear, 12, 31).toLocalDate(); periodEndDate = new DateTime().withDate(byear, 12, 31).toLocalDate();
} }
break; break;
case ANNUAL: case ANNUAL:
periodEndDate = periodStartDate.monthOfYear().withMaximumValue(); periodEndDate = periodStartDate.monthOfYear().withMaximumValue();
periodEndDate = periodEndDate.dayOfMonth().withMaximumValue(); periodEndDate = periodEndDate.dayOfMonth().withMaximumValue();
@@ -90,7 +99,13 @@ public final class SavingsHelper {
return periodEndDate; return periodEndDate;
} }
public Money calculateInterestForAllPostingPeriods(final MonetaryCurrency currency, final List<PostingPeriod> allPeriods) { public Money calculateInterestForAllPostingPeriods(final MonetaryCurrency currency, final List<PostingPeriod> allPeriods,
return this.compoundInterestHelper.calculateInterestForAllPostingPeriods(currency, allPeriods); LocalDate accountLockedUntil, Boolean immediateWithdrawalOfInterest) {
return this.compoundInterestHelper.calculateInterestForAllPostingPeriods(currency, allPeriods, accountLockedUntil,
immediateWithdrawalOfInterest);
}
public Collection<Long> fetchPostInterestTransactionIds(Long accountId) {
return this.accountTransfersReadPlatformService.fetchPostInterestTransactionIds(accountId);
} }
} }
@@ -3,12 +3,26 @@ package org.mifosplatform.portfolio.savings.domain.interest;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List; import java.util.List;
import org.joda.time.LocalDate;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money; import org.mifosplatform.organisation.monetary.domain.Money;
public class CompoundInterestHelper { public class CompoundInterestHelper {
public Money calculateInterestForAllPostingPeriods(final MonetaryCurrency currency, final List<PostingPeriod> allPeriods) { /**
* @param currency
* @param allPeriods
* @param lockUntil
* - account locked date used with the combination of
* immediateWithdrawalOfInterest to avoid exclusion of
* interestEarned
* @param interestTransferEnabled
* - boolean flag used to avoid addition of interest to next
* posting period as income while calculating interest
* @return
*/
public Money calculateInterestForAllPostingPeriods(final MonetaryCurrency currency, final List<PostingPeriod> allPeriods,
LocalDate lockUntil, Boolean interestTransferEnabled) {
// sum up the 'rounded' values that are posted each posting period // sum up the 'rounded' values that are posted each posting period
Money interestEarned = Money.zero(currency); Money interestEarned = Money.zero(currency);
@@ -22,8 +36,14 @@ public class CompoundInterestHelper {
final Money moneyToBePostedForPeriod = Money.of(currency, interestEarnedThisPeriod); final Money moneyToBePostedForPeriod = Money.of(currency, interestEarnedThisPeriod);
interestEarned = interestEarned.plus(moneyToBePostedForPeriod); interestEarned = interestEarned.plus(moneyToBePostedForPeriod);
// these checks are for fixed deposit account for not include
interestEarnedButNotPosted = interestEarnedButNotPosted.add(moneyToBePostedForPeriod.getAmount()); // interest for accounts which has post interest to linked savings
// account and if already transfered then it includes in interest
// calculation.
if (postingPeriod.isInterestTransfered() || !interestTransferEnabled
|| (lockUntil != null && !postingPeriod.dateOfPostingTransaction().isAfter(lockUntil))) {
interestEarnedButNotPosted = interestEarnedButNotPosted.add(moneyToBePostedForPeriod.getAmount());
}
} }
return interestEarned; return interestEarned;
@@ -2,6 +2,7 @@ package org.mifosplatform.portfolio.savings.domain.interest;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import org.joda.time.DateTime; import org.joda.time.DateTime;
@@ -33,13 +34,18 @@ public class PostingPeriod {
private final Money closingBalance; private final Money closingBalance;
private final SavingsInterestCalculationType interestCalculationType; private final SavingsInterestCalculationType interestCalculationType;
// include in compounding interest
private boolean interestTransfered = false;
// isInterestTransfer boolean is to identify newly created transaction is interest transfer
public static PostingPeriod createFrom(final LocalDateInterval periodInterval, final Money periodStartingBalance, public static PostingPeriod createFrom(final LocalDateInterval periodInterval, final Money periodStartingBalance,
final List<SavingsAccountTransaction> orderedListOfTransactions, final MonetaryCurrency currency, final List<SavingsAccountTransaction> orderedListOfTransactions, final MonetaryCurrency currency,
final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType, final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType,
final SavingsInterestCalculationType interestCalculationType, final BigDecimal interestRateAsFraction, final long daysInYear, final LocalDate upToInterestCalculationDate) { final SavingsInterestCalculationType interestCalculationType, final BigDecimal interestRateAsFraction, final long daysInYear,
final LocalDate upToInterestCalculationDate, Collection<Long> interestPostTransactions, boolean isInterestTransfer) {
final List<EndOfDayBalance> accountEndOfDayBalances = new ArrayList<EndOfDayBalance>(); final List<EndOfDayBalance> accountEndOfDayBalances = new ArrayList<EndOfDayBalance>();
boolean interestTransfered = false;
Money openingDayBalance = periodStartingBalance; Money openingDayBalance = periodStartingBalance;
Money closeOfDayBalance = openingDayBalance; Money closeOfDayBalance = openingDayBalance;
for (final SavingsAccountTransaction transaction : orderedListOfTransactions) { for (final SavingsAccountTransaction transaction : orderedListOfTransactions) {
@@ -51,6 +57,7 @@ public class PostingPeriod {
accountEndOfDayBalances.add(endOfDayBalance); accountEndOfDayBalances.add(endOfDayBalance);
openingDayBalance = endOfDayBalance.closingBalance(); openingDayBalance = endOfDayBalance.closingBalance();
} else if (transaction.spansAnyPortionOf(periodInterval)) { } else if (transaction.spansAnyPortionOf(periodInterval)) {
final EndOfDayBalance endOfDayBalance = transaction.toEndOfDayBalanceBoundedBy(openingDayBalance, periodInterval); final EndOfDayBalance endOfDayBalance = transaction.toEndOfDayBalanceBoundedBy(openingDayBalance, periodInterval);
accountEndOfDayBalances.add(endOfDayBalance); accountEndOfDayBalances.add(endOfDayBalance);
@@ -58,6 +65,16 @@ public class PostingPeriod {
closeOfDayBalance = endOfDayBalance.closingBalance(); closeOfDayBalance = endOfDayBalance.closingBalance();
openingDayBalance = closeOfDayBalance; openingDayBalance = closeOfDayBalance;
} }
// this check is to make sure to add interest if withdrawal is happened for already
if (transaction.occursOn(periodInterval.endDate().plusDays(1))) {
if (transaction.getId() == null) {
interestTransfered = isInterestTransfer;
} else if (interestPostTransactions.contains(transaction.getId())) {
interestTransfered = true;
}
}
} }
if (accountEndOfDayBalances.isEmpty()) { if (accountEndOfDayBalances.isEmpty()) {
@@ -84,13 +101,13 @@ public class PostingPeriod {
accountEndOfDayBalances, upToInterestCalculationDate); accountEndOfDayBalances, upToInterestCalculationDate);
return new PostingPeriod(periodInterval, currency, periodStartingBalance, openingDayBalance, interestCompoundingPeriodType, return new PostingPeriod(periodInterval, currency, periodStartingBalance, openingDayBalance, interestCompoundingPeriodType,
interestCalculationType, interestRateAsFraction, daysInYear, compoundingPeriods); interestCalculationType, interestRateAsFraction, daysInYear, compoundingPeriods, interestTransfered);
} }
private PostingPeriod(final LocalDateInterval periodInterval, final MonetaryCurrency currency, final Money openingBalance, private PostingPeriod(final LocalDateInterval periodInterval, final MonetaryCurrency currency, final Money openingBalance,
final Money closingBalance, final SavingsCompoundingInterestPeriodType interestCompoundingType, final Money closingBalance, final SavingsCompoundingInterestPeriodType interestCompoundingType,
final SavingsInterestCalculationType interestCalculationType, final BigDecimal interestRateAsFraction, final long daysInYear, final SavingsInterestCalculationType interestCalculationType, final BigDecimal interestRateAsFraction, final long daysInYear,
final List<CompoundingPeriod> compoundingPeriods) { final List<CompoundingPeriod> compoundingPeriods, boolean interestTransfered) {
this.periodInterval = periodInterval; this.periodInterval = periodInterval;
this.currency = currency; this.currency = currency;
this.openingBalance = openingBalance; this.openingBalance = openingBalance;
@@ -102,6 +119,7 @@ public class PostingPeriod {
this.compoundingPeriods = compoundingPeriods; this.compoundingPeriods = compoundingPeriods;
this.dateOfPostingTransaction = periodInterval.endDate().plusDays(1); this.dateOfPostingTransaction = periodInterval.endDate().plusDays(1);
this.interestTransfered = interestTransfered;
} }
public Money interest() { public Money interest() {
@@ -145,7 +163,8 @@ public class PostingPeriod {
} }
private static List<CompoundingPeriod> compoundingPeriodsInPostingPeriod(final LocalDateInterval postingPeriodInterval, private static List<CompoundingPeriod> compoundingPeriodsInPostingPeriod(final LocalDateInterval postingPeriodInterval,
final SavingsCompoundingInterestPeriodType interestPeriodType, final List<EndOfDayBalance> allEndOfDayBalances, final LocalDate upToInterestCalculationDate) { final SavingsCompoundingInterestPeriodType interestPeriodType, final List<EndOfDayBalance> allEndOfDayBalances,
final LocalDate upToInterestCalculationDate) {
final List<CompoundingPeriod> compoundingPeriods = new ArrayList<CompoundingPeriod>(); final List<CompoundingPeriod> compoundingPeriods = new ArrayList<CompoundingPeriod>();
@@ -174,7 +193,8 @@ public class PostingPeriod {
final LocalDateInterval compoundingPeriodInterval = LocalDateInterval.create(periodStartDate, periodEndDate); final LocalDateInterval compoundingPeriodInterval = LocalDateInterval.create(periodStartDate, periodEndDate);
if (postingPeriodInterval.contains(compoundingPeriodInterval)) { if (postingPeriodInterval.contains(compoundingPeriodInterval)) {
compoundingPeriod = MonthlyCompoundingPeriod.create(compoundingPeriodInterval, allEndOfDayBalances, upToInterestCalculationDate); compoundingPeriod = MonthlyCompoundingPeriod.create(compoundingPeriodInterval, allEndOfDayBalances,
upToInterestCalculationDate);
compoundingPeriods.add(compoundingPeriod); compoundingPeriods.add(compoundingPeriod);
} }
@@ -182,11 +202,11 @@ public class PostingPeriod {
periodStartDate = periodEndDate.plusDays(1); periodStartDate = periodEndDate.plusDays(1);
} }
break; break;
// case WEEKLY: // case WEEKLY:
// break; // break;
// case BIWEEKLY: // case BIWEEKLY:
// break; // break;
case QUATERLY: case QUATERLY:
final LocalDate qPostingPeriodEndDate = postingPeriodInterval.endDate(); final LocalDate qPostingPeriodEndDate = postingPeriodInterval.endDate();
periodStartDate = postingPeriodInterval.startDate(); periodStartDate = postingPeriodInterval.startDate();
@@ -210,7 +230,7 @@ public class PostingPeriod {
// move periodStartDate forward to day after this period // move periodStartDate forward to day after this period
periodStartDate = periodEndDate.plusDays(1); periodStartDate = periodEndDate.plusDays(1);
} }
break; break;
case BI_ANNUAL: case BI_ANNUAL:
final LocalDate bPostingPeriodEndDate = postingPeriodInterval.endDate(); final LocalDate bPostingPeriodEndDate = postingPeriodInterval.endDate();
@@ -235,7 +255,7 @@ public class PostingPeriod {
// move periodStartDate forward to day after this period // move periodStartDate forward to day after this period
periodStartDate = periodEndDate.plusDays(1); periodStartDate = periodEndDate.plusDays(1);
} }
break; break;
case ANNUAL: case ANNUAL:
final LocalDate aPostingPeriodEndDate = postingPeriodInterval.endDate(); final LocalDate aPostingPeriodEndDate = postingPeriodInterval.endDate();
@@ -260,9 +280,9 @@ public class PostingPeriod {
// move periodStartDate forward to day after this period // move periodStartDate forward to day after this period
periodStartDate = periodEndDate.plusDays(1); periodStartDate = periodEndDate.plusDays(1);
} }
break; break;
// case NO_COMPOUNDING_SIMPLE_INTEREST: // case NO_COMPOUNDING_SIMPLE_INTEREST:
// break; // break;
} }
return compoundingPeriods; return compoundingPeriods;
@@ -291,7 +311,7 @@ public class PostingPeriod {
// produce period end date on last day of current month // produce period end date on last day of current month
periodEndDate = periodStartDate.dayOfMonth().withMaximumValue(); periodEndDate = periodStartDate.dayOfMonth().withMaximumValue();
break; break;
case QUATERLY: case QUATERLY:
// // jan 1st to mar 31st, 1st apr to jun 30, jul 1st to sept // // jan 1st to mar 31st, 1st apr to jun 30, jul 1st to sept
// 30, // 30,
// // oct 1st to dec 31 // // oct 1st to dec 31
@@ -306,7 +326,7 @@ public class PostingPeriod {
} else if (monthofYear <= 12) { } else if (monthofYear <= 12) {
periodEndDate = new DateTime().withDate(year, 12, 31).toLocalDate(); periodEndDate = new DateTime().withDate(year, 12, 31).toLocalDate();
} }
break; break;
case BI_ANNUAL: case BI_ANNUAL:
// // jan 1st to 30, jul 1st to dec 31 // // jan 1st to 30, jul 1st to dec 31
year = periodStartDate.getYearOfEra(); year = periodStartDate.getYearOfEra();
@@ -316,18 +336,22 @@ public class PostingPeriod {
} else if (monthofYear <= 12) { } else if (monthofYear <= 12) {
periodEndDate = new DateTime().withDate(year, 12, 31).toLocalDate(); periodEndDate = new DateTime().withDate(year, 12, 31).toLocalDate();
} }
break; break;
case ANNUAL: case ANNUAL:
periodEndDate = periodStartDate.monthOfYear().withMaximumValue(); periodEndDate = periodStartDate.monthOfYear().withMaximumValue();
periodEndDate = periodEndDate.dayOfMonth().withMaximumValue(); periodEndDate = periodEndDate.dayOfMonth().withMaximumValue();
break; break;
// case NO_COMPOUNDING_SIMPLE_INTEREST: // case NO_COMPOUNDING_SIMPLE_INTEREST:
// periodEndDate = periodStartDate.monthOfYear().withMaximumValue(); // periodEndDate = periodStartDate.monthOfYear().withMaximumValue();
// periodEndDate = periodEndDate.dayOfMonth().withMaximumValue(); // periodEndDate = periodEndDate.dayOfMonth().withMaximumValue();
// break; // break;
} }
return periodEndDate; return periodEndDate;
} }
public boolean isInterestTransfered() {
return this.interestTransfered;
}
} }
@@ -9,6 +9,7 @@ import java.util.Collection;
import org.mifosplatform.infrastructure.core.data.PaginationParameters; import org.mifosplatform.infrastructure.core.data.PaginationParameters;
import org.mifosplatform.infrastructure.core.service.Page; import org.mifosplatform.infrastructure.core.service.Page;
import org.mifosplatform.portfolio.account.data.AccountTransferDTO;
import org.mifosplatform.portfolio.savings.DepositAccountType; import org.mifosplatform.portfolio.savings.DepositAccountType;
import org.mifosplatform.portfolio.savings.data.DepositAccountData; import org.mifosplatform.portfolio.savings.data.DepositAccountData;
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionData; import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionData;
@@ -34,4 +35,6 @@ public interface DepositAccountReadPlatformService {
Collection<DepositAccountData> retrieveForMaturityUpdate(); Collection<DepositAccountData> retrieveForMaturityUpdate();
SavingsAccountTransactionData retrieveRecurringAccountDepositTransactionTemplate(final Long accountId); SavingsAccountTransactionData retrieveRecurringAccountDepositTransactionTemplate(final Long accountId);
Collection<AccountTransferDTO> retrieveDataForInterestTransfer();
} }
@@ -26,7 +26,10 @@ import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext
import org.mifosplatform.organisation.monetary.data.CurrencyData; import org.mifosplatform.organisation.monetary.data.CurrencyData;
import org.mifosplatform.organisation.staff.data.StaffData; import org.mifosplatform.organisation.staff.data.StaffData;
import org.mifosplatform.organisation.staff.service.StaffReadPlatformService; import org.mifosplatform.organisation.staff.service.StaffReadPlatformService;
import org.mifosplatform.portfolio.account.PortfolioAccountType;
import org.mifosplatform.portfolio.account.data.AccountTransferDTO;
import org.mifosplatform.portfolio.account.data.AccountTransferData; import org.mifosplatform.portfolio.account.data.AccountTransferData;
import org.mifosplatform.portfolio.account.domain.AccountTransferType;
import org.mifosplatform.portfolio.charge.data.ChargeData; import org.mifosplatform.portfolio.charge.data.ChargeData;
import org.mifosplatform.portfolio.charge.service.ChargeReadPlatformService; import org.mifosplatform.portfolio.charge.service.ChargeReadPlatformService;
import org.mifosplatform.portfolio.client.data.ClientData; import org.mifosplatform.portfolio.client.data.ClientData;
@@ -464,6 +467,22 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
} }
} }
@Override
public Collection<AccountTransferDTO> retrieveDataForInterestTransfer() {
final StringBuilder sqlBuilder = new StringBuilder(300);
AccountTransferMapper mapper = new AccountTransferMapper();
sqlBuilder.append("SELECT ");
sqlBuilder.append(mapper.schema());
sqlBuilder.append(" where da.transfer_interest_to_linked_account = 1 and ");
sqlBuilder
.append("st.transaction_date > (select IFNULL(max(sat.transaction_date),sa.activatedon_date) from m_savings_account_transaction sat where sat.transaction_type_enum = ? and sat.savings_account_id = sa.id and sat.is_reversed=0) ");
sqlBuilder
.append("and st.transaction_type_enum = ? and sa.status_enum = ? and st.is_reversed=0 and st.transaction_date > IFNULL(sa.lockedin_until_date_derived,sa.activatedon_date)");
return this.jdbcTemplate.query(sqlBuilder.toString(), mapper, new Object[] { SavingsAccountTransactionType.WITHDRAWAL.getValue(),
SavingsAccountTransactionType.INTEREST_POSTING.getValue(), SavingsAccountStatusType.ACTIVE.getValue() });
}
private static abstract class DepositAccountMapper implements RowMapper<DepositAccountData> { private static abstract class DepositAccountMapper implements RowMapper<DepositAccountData> {
private final String selectFieldsSql; private final String selectFieldsSql;
@@ -697,7 +716,8 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
sqlBuilder.append("datp.maturity_date as maturityDate, "); sqlBuilder.append("datp.maturity_date as maturityDate, ");
sqlBuilder.append("datp.deposit_period as depositPeriod, "); sqlBuilder.append("datp.deposit_period as depositPeriod, ");
sqlBuilder.append("datp.deposit_period_frequency_enum as depositPeriodFrequencyTypeId, "); sqlBuilder.append("datp.deposit_period_frequency_enum as depositPeriodFrequencyTypeId, ");
sqlBuilder.append("datp.on_account_closure_enum as onAccountClosureId "); sqlBuilder.append("datp.on_account_closure_enum as onAccountClosureId, ");
sqlBuilder.append("datp.transfer_interest_to_linked_account as transferInterestToSavings ");
sqlBuilder.append(super.selectTablesSql()); sqlBuilder.append(super.selectTablesSql());
@@ -750,12 +770,13 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
final Integer onAccountClosureId = JdbcSupport.getInteger(rs, "onAccountClosureId"); final Integer onAccountClosureId = JdbcSupport.getInteger(rs, "onAccountClosureId");
final EnumOptionData onAccountClosureType = (onAccountClosureId == null) ? null : SavingsEnumerations final EnumOptionData onAccountClosureType = (onAccountClosureId == null) ? null : SavingsEnumerations
.depositAccountOnClosureType(onAccountClosureId); .depositAccountOnClosureType(onAccountClosureId);
final Boolean transferInterestToSavings = rs.getBoolean("transferInterestToSavings");
return FixedDepositAccountData.instance(depositAccountData, interestFreePeriodApplicable, interestFreeFromPeriod, return FixedDepositAccountData.instance(depositAccountData, interestFreePeriodApplicable, interestFreeFromPeriod,
interestFreeToPeriod, interestFreePeriodFrequencyType, preClosurePenalApplicable, preClosurePenalInterest, interestFreeToPeriod, interestFreePeriodFrequencyType, preClosurePenalApplicable, preClosurePenalInterest,
preClosurePenalInterestOnType, minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType, preClosurePenalInterestOnType, minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType,
inMultiplesOfDepositTerm, inMultiplesOfDepositTermType, depositAmount, maturityAmount, maturityDate, depositPeriod, inMultiplesOfDepositTerm, inMultiplesOfDepositTermType, depositAmount, maturityAmount, maturityDate, depositPeriod,
depositPeriodFrequencyType, onAccountClosureType); depositPeriodFrequencyType, onAccountClosureType, transferInterestToSavings);
} }
} }
@@ -1182,12 +1203,13 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
final Integer depositPeriod = null; final Integer depositPeriod = null;
final EnumOptionData depositPeriodFrequencyType = null; final EnumOptionData depositPeriodFrequencyType = null;
final EnumOptionData onAccountClosureType = null; final EnumOptionData onAccountClosureType = null;
final Boolean transferInterestToSavings = false;
return FixedDepositAccountData.instance(depositAccountData, interestFreePeriodApplicable, interestFreeFromPeriod, return FixedDepositAccountData.instance(depositAccountData, interestFreePeriodApplicable, interestFreeFromPeriod,
interestFreeToPeriod, interestFreePeriodFrequencyType, preClosurePenalApplicable, preClosurePenalInterest, interestFreeToPeriod, interestFreePeriodFrequencyType, preClosurePenalApplicable, preClosurePenalInterest,
preClosurePenalInterestOnType, minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType, preClosurePenalInterestOnType, minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType,
inMultiplesOfDepositTerm, inMultiplesOfDepositTermType, depositAmount, maturityAmount, maturityDate, depositPeriod, inMultiplesOfDepositTerm, inMultiplesOfDepositTermType, depositAmount, maturityAmount, maturityDate, depositPeriod,
depositPeriodFrequencyType, onAccountClosureType); depositPeriodFrequencyType, onAccountClosureType, transferInterestToSavings);
} }
} }
@@ -1375,4 +1397,36 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
DateUtils.getLocalDateOfTenant(), currency, recurringDepositAmount, runningBalance, false, transfer); DateUtils.getLocalDateOfTenant(), currency, recurringDepositAmount, runningBalance, false, transfer);
} }
} }
private class AccountTransferMapper implements RowMapper<AccountTransferDTO> {
private final String schemaSql;
public AccountTransferMapper() {
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder
.append("sa.id as fromAcc ,aa.linked_savings_account_id as toAcc,st.amount as amount, st.transaction_date as transactionDate ")
.append(" from m_deposit_account_term_and_preclosure da ")
.append(" inner join m_savings_account sa on da.savings_account_id = sa.id")
.append(" inner join m_savings_account_transaction st on st.savings_account_id = sa.id")
.append(" inner join m_portfolio_account_associations aa on aa.savings_account_id=sa.id");
schemaSql = sqlBuilder.toString();
}
public String schema() {
return this.schemaSql;
}
@Override
public AccountTransferDTO mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum) throws SQLException {
final Long fromAccountId = rs.getLong("fromAcc");
final Long toAccountId = rs.getLong("toAcc");
final BigDecimal transactionAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "amount");
final LocalDate transactionDate = JdbcSupport.getLocalDate(rs, "transactionDate");
return new AccountTransferDTO(transactionDate, transactionAmount, PortfolioAccountType.SAVINGS, PortfolioAccountType.SAVINGS,
fromAccountId, toAccountId, "trasfer interest to savings", null, null, null, null, null, null, null,
AccountTransferType.INTEREST_TRANSFER.getValue(), null, null, null, null, null);
}
}
} }
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.savings.service;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.jobs.exception.JobExecutionException;
import org.mifosplatform.organisation.office.domain.Office; import org.mifosplatform.organisation.office.domain.Office;
import org.mifosplatform.organisation.staff.domain.Staff; import org.mifosplatform.organisation.staff.domain.Staff;
import org.mifosplatform.portfolio.savings.DepositAccountType; import org.mifosplatform.portfolio.savings.DepositAccountType;
@@ -54,4 +55,6 @@ public interface DepositAccountWritePlatformService {
void applyChargeDue(final Long savingsAccountChargeId, final Long accountId, final DepositAccountType depositAccountType); void applyChargeDue(final Long savingsAccountChargeId, final Long accountId, final DepositAccountType depositAccountType);
void updateMaturityDetails(final Long depositAccountId, final DepositAccountType depositAccountType); void updateMaturityDetails(final Long depositAccountId, final DepositAccountType depositAccountType);
void transferInterestToSavings() throws JobExecutionException;
} }
@@ -14,6 +14,7 @@ import java.math.BigDecimal;
import java.math.MathContext; import java.math.MathContext;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
@@ -34,6 +35,9 @@ import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
import org.mifosplatform.infrastructure.core.exception.PlatformServiceUnavailableException; import org.mifosplatform.infrastructure.core.exception.PlatformServiceUnavailableException;
import org.mifosplatform.infrastructure.core.service.DateUtils; import org.mifosplatform.infrastructure.core.service.DateUtils;
import org.mifosplatform.infrastructure.jobs.annotation.CronTarget;
import org.mifosplatform.infrastructure.jobs.exception.JobExecutionException;
import org.mifosplatform.infrastructure.jobs.service.JobName;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.organisation.holiday.service.HolidayWritePlatformService; import org.mifosplatform.organisation.holiday.service.HolidayWritePlatformService;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
@@ -78,6 +82,7 @@ import org.mifosplatform.portfolio.savings.domain.SavingsAccountStatusType;
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransaction; import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransaction;
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransactionRepository; import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransactionRepository;
import org.mifosplatform.portfolio.savings.exception.DepositAccountTransactionNotAllowedException; import org.mifosplatform.portfolio.savings.exception.DepositAccountTransactionNotAllowedException;
import org.mifosplatform.portfolio.savings.exception.InsufficientAccountBalanceException;
import org.mifosplatform.portfolio.savings.exception.SavingsAccountTransactionNotFoundException; import org.mifosplatform.portfolio.savings.exception.SavingsAccountTransactionNotFoundException;
import org.mifosplatform.portfolio.savings.exception.TransactionUpdateNotAllowedException; import org.mifosplatform.portfolio.savings.exception.TransactionUpdateNotAllowedException;
import org.mifosplatform.useradministration.domain.AppUser; import org.mifosplatform.useradministration.domain.AppUser;
@@ -106,6 +111,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
private final WorkingDaysWritePlatformService workingDaysWritePlatformService; private final WorkingDaysWritePlatformService workingDaysWritePlatformService;
private final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService; private final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService;
private final AccountTransfersWritePlatformService accountTransfersWritePlatformService; private final AccountTransfersWritePlatformService accountTransfersWritePlatformService;
private final DepositAccountReadPlatformService depositAccountReadPlatformService;
@Autowired @Autowired
public DepositAccountWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, public DepositAccountWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
@@ -123,7 +129,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final HolidayWritePlatformService holidayWritePlatformService, final HolidayWritePlatformService holidayWritePlatformService,
final WorkingDaysWritePlatformService workingDaysWritePlatformService, final WorkingDaysWritePlatformService workingDaysWritePlatformService,
final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService, final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService,
final AccountTransfersWritePlatformService accountTransfersWritePlatformService) { final AccountTransfersWritePlatformService accountTransfersWritePlatformService,
final DepositAccountReadPlatformService depositAccountReadPlatformService) {
this.context = context; this.context = context;
this.savingAccountRepository = savingAccountRepository; this.savingAccountRepository = savingAccountRepository;
this.savingsAccountTransactionRepository = savingsAccountTransactionRepository; this.savingsAccountTransactionRepository = savingsAccountTransactionRepository;
@@ -142,6 +149,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
this.workingDaysWritePlatformService = workingDaysWritePlatformService; this.workingDaysWritePlatformService = workingDaysWritePlatformService;
this.accountAssociationsReadPlatformService = accountAssociationsReadPlatformService; this.accountAssociationsReadPlatformService = accountAssociationsReadPlatformService;
this.accountTransfersWritePlatformService = accountTransfersWritePlatformService; this.accountTransfersWritePlatformService = accountTransfersWritePlatformService;
this.depositAccountReadPlatformService = depositAccountReadPlatformService;
} }
@Transactional @Transactional
@@ -282,8 +290,9 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
final MathContext mc = new MathContext(15, RoundingMode.HALF_EVEN); final MathContext mc = new MathContext(15, RoundingMode.HALF_EVEN);
boolean isInterestTransfer = false;
account.calculateInterestUsing(mc, today); account.calculateInterestUsing(mc, today, isInterestTransfer);
this.savingAccountRepository.save(account); this.savingAccountRepository.save(account);
@@ -319,13 +328,33 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN); final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN);
boolean isInterestTransfer = false;
account.postInterest(mc, today); account.postInterest(mc, today, isInterestTransfer);
this.savingAccountRepository.save(account); this.savingAccountRepository.save(account);
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds); postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
} }
@Override
@CronTarget(jobName = JobName.TRANSFER_INTEREST_TO_SAVINGS)
public void transferInterestToSavings() throws JobExecutionException {
Collection<AccountTransferDTO> accountTrasferData = this.depositAccountReadPlatformService.retrieveDataForInterestTransfer();
StringBuilder sb = new StringBuilder(200);
for (AccountTransferDTO accountTransferDTO : accountTrasferData) {
try {
this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO);
} catch (final PlatformApiDataValidationException e) {
sb.append("Validation exception while trasfering Interest form ").append(accountTransferDTO.getFromAccountId())
.append(" to ").append(accountTransferDTO.getToAccountId()).append("--------");
} catch (final InsufficientAccountBalanceException e) {
sb.append("InsufficientAccountBalance Exception while trasfering Interest form ")
.append(accountTransferDTO.getFromAccountId()).append(" to ").append(accountTransferDTO.getToAccountId())
.append("--------");
}
}
if (sb.length() > 0) { throw new JobExecutionException(sb.toString()); }
}
@Override @Override
public CommandProcessingResult undoTransaction(final Long savingsId, final Long transactionId, public CommandProcessingResult undoTransaction(final Long savingsId, final Long transactionId,
final boolean allowAccountTransferModification, final DepositAccountType depositAccountType) { final boolean allowAccountTransferModification, final DepositAccountType depositAccountType) {
@@ -354,13 +383,13 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
throwValidationForActiveStatus(SavingsApiConstants.undoTransactionAction); throwValidationForActiveStatus(SavingsApiConstants.undoTransactionAction);
} }
account.undoTransaction(transactionId); account.undoTransaction(transactionId);
boolean isInterestTransfer = false;
checkClientOrGroupActive(account); checkClientOrGroupActive(account);
if (savingsAccountTransaction.isPostInterestCalculationRequired() if (savingsAccountTransaction.isPostInterestCalculationRequired()
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate())) { && account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate())) {
account.postInterest(mc, today); account.postInterest(mc, today, isInterestTransfer);
} else { } else {
account.calculateInterestUsing(mc, today); account.calculateInterestUsing(mc, today, isInterestTransfer);
} }
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.undoTransactionAction); account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.undoTransactionAction);
account.activateAccountBasedOnBalance(); account.activateAccountBasedOnBalance();
@@ -425,12 +454,12 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
transaction = account.withdraw(transactionDTO, true); transaction = account.withdraw(transactionDTO, true);
} }
final Long newtransactionId = saveTransactionToGenerateTransactionId(transaction); final Long newtransactionId = saveTransactionToGenerateTransactionId(transaction);
boolean isInterestTransfer = false;
if (account.isBeforeLastPostingPeriod(transactionDate) if (account.isBeforeLastPostingPeriod(transactionDate)
|| account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate())) { || account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate())) {
account.postInterest(mc, today); account.postInterest(mc, today, isInterestTransfer);
} else { } else {
account.calculateInterestUsing(mc, today); account.calculateInterestUsing(mc, today, isInterestTransfer);
} }
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.adjustTransactionAction); account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.adjustTransactionAction);
account.activateAccountBasedOnBalance(); account.activateAccountBasedOnBalance();
@@ -548,7 +577,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
savingsAccount.getTransactions().add(newTransferTransaction); savingsAccount.getTransactions().add(newTransferTransaction);
savingsAccount.setStatus(SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue()); savingsAccount.setStatus(SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue());
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
savingsAccount.calculateInterestUsing(mc, transferDate); boolean isInterestTransfer = false;
savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer);
this.savingsAccountTransactionRepository.save(newTransferTransaction); this.savingsAccountTransactionRepository.save(newTransferTransaction);
this.savingAccountRepository.save(savingsAccount); this.savingAccountRepository.save(savingsAccount);
@@ -572,7 +602,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
savingsAccount.getTransactions().add(withdrawtransferTransaction); savingsAccount.getTransactions().add(withdrawtransferTransaction);
savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue()); savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue());
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
savingsAccount.calculateInterestUsing(mc, transferDate); boolean isInterestTransfer = false;
savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer);
this.savingsAccountTransactionRepository.save(withdrawtransferTransaction); this.savingsAccountTransactionRepository.save(withdrawtransferTransaction);
this.savingAccountRepository.save(savingsAccount); this.savingAccountRepository.save(savingsAccount);
@@ -605,9 +636,9 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
if (fieldOfficer != null) { if (fieldOfficer != null) {
savingsAccount.update(fieldOfficer); savingsAccount.update(fieldOfficer);
} }
boolean isInterestTransfer = false;
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
savingsAccount.calculateInterestUsing(mc, transferDate); savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer);
this.savingsAccountTransactionRepository.save(acceptTransferTransaction); this.savingsAccountTransactionRepository.save(acceptTransferTransaction);
this.savingAccountRepository.save(savingsAccount); this.savingAccountRepository.save(savingsAccount);
@@ -745,14 +776,14 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
account.waiveCharge(savingsAccountChargeId); account.waiveCharge(savingsAccountChargeId);
boolean isInterestTransfer = false;
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) { if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) {
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
account.postInterest(mc, today); account.postInterest(mc, today, isInterestTransfer);
} else { } else {
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
account.calculateInterestUsing(mc, today); account.calculateInterestUsing(mc, today, isInterestTransfer);
} }
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.waiveChargeTransactionAction); account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.waiveChargeTransactionAction);
@@ -863,14 +894,14 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final Set<Long> existingReversedTransactionIds = new HashSet<Long>(); final Set<Long> existingReversedTransactionIds = new HashSet<Long>();
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter); account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter);
boolean isInterestTransfer = false;
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
if (account.isBeforeLastPostingPeriod(transactionDate)) { if (account.isBeforeLastPostingPeriod(transactionDate)) {
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
account.postInterest(mc, today); account.postInterest(mc, today, isInterestTransfer);
} else { } else {
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
account.calculateInterestUsing(mc, today); account.calculateInterestUsing(mc, today, isInterestTransfer);
} }
account.validateAccountBalanceDoesNotBecomeNegative("." + SavingsAccountTransactionType.PAY_CHARGE.getCode()); account.validateAccountBalanceDoesNotBecomeNegative("." + SavingsAccountTransactionType.PAY_CHARGE.getCode());
@@ -5,6 +5,9 @@
*/ */
package org.mifosplatform.portfolio.savings.service; package org.mifosplatform.portfolio.savings.service;
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.linkedAccountParamName;
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.transferInterestToSavingsParamName;
import java.math.MathContext; import java.math.MathContext;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@@ -272,13 +275,15 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
if (depositAccountType.isFixedDeposit()) { if (depositAccountType.isFixedDeposit()) {
((FixedDepositAccount) account).updateMaturityDateAndAmountBeforeAccountActivation(mc); ((FixedDepositAccount) account).updateMaturityDateAndAmountBeforeAccountActivation(mc);
} else if (depositAccountType.isRecurringDeposit()) { } else if (depositAccountType.isRecurringDeposit()) {
final LocalDate transactionStartDate = ((RecurringDepositAccount) account).depositStartDate(); final LocalDate transactionStartDate = ((RecurringDepositAccount) account).depositStartDate();
((RecurringDepositAccount) account).updateMaturityDateAndAmount(mc, transactionStartDate); ((RecurringDepositAccount) account).updateMaturityDateAndAmount(mc, transactionStartDate);
} }
this.savingAccountRepository.saveAndFlush(account); this.savingAccountRepository.saveAndFlush(account);
} }
boolean isLinkedAccRequired = command.booleanPrimitiveValueOfParameterNamed(transferInterestToSavingsParamName);
// Save linked account information // Save linked account information
final Long savingsAccountId = command.longValueOfParameterNamed(DepositsApiConstants.linkedAccountParamName); final Long savingsAccountId = command.longValueOfParameterNamed(DepositsApiConstants.linkedAccountParamName);
AccountAssociations accountAssociations = this.accountAssociationsRepository.findBySavingsId(accountId); AccountAssociations accountAssociations = this.accountAssociationsRepository.findBySavingsId(accountId);
@@ -287,7 +292,12 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
if (this.fromJsonHelper.parameterExists(DepositsApiConstants.linkedAccountParamName, command.parsedJson())) { if (this.fromJsonHelper.parameterExists(DepositsApiConstants.linkedAccountParamName, command.parsedJson())) {
this.accountAssociationsRepository.delete(accountAssociations); this.accountAssociationsRepository.delete(accountAssociations);
changes.put(DepositsApiConstants.linkedAccountParamName, null); changes.put(DepositsApiConstants.linkedAccountParamName, null);
if (isLinkedAccRequired) {
this.depositAccountDataValidator.throwLinkedAccountRequiredError();
}
} }
} else if (isLinkedAccRequired) {
this.depositAccountDataValidator.throwLinkedAccountRequiredError();
} }
} else { } else {
boolean isModified = false; boolean isModified = false;
@@ -234,9 +234,10 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId); final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
checkClientOrGroupActive(account); checkClientOrGroupActive(account);
boolean isInterestTransfer = false;
final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(account, fmt, transactionDate, final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(account, fmt, transactionDate,
transactionAmount, paymentDetail, true); transactionAmount, paymentDetail, true, isInterestTransfer);
return new CommandProcessingResultBuilder() // return new CommandProcessingResultBuilder() //
.withEntityId(withdrawal.getId()) // .withEntityId(withdrawal.getId()) //
@@ -277,8 +278,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
final MathContext mc = new MathContext(15, RoundingMode.HALF_EVEN); final MathContext mc = new MathContext(15, RoundingMode.HALF_EVEN);
boolean isInterestTransfer = false;
account.calculateInterestUsing(mc, today); account.calculateInterestUsing(mc, today, isInterestTransfer);
this.savingAccountRepository.save(account); this.savingAccountRepository.save(account);
@@ -315,8 +316,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN); final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN);
boolean isInterestTransfer = false;
account.postInterest(mc, today); account.postInterest(mc, today, isInterestTransfer);
// for generating transaction id's // for generating transaction id's
List<SavingsAccountTransaction> transactions = account.getTransactions(); List<SavingsAccountTransaction> transactions = account.getTransactions();
@@ -378,13 +379,13 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
account.undoTransaction(transactionId + 1); account.undoTransaction(transactionId + 1);
} }
} }
boolean isInterestTransfer = false;
checkClientOrGroupActive(account); checkClientOrGroupActive(account);
if (savingsAccountTransaction.isPostInterestCalculationRequired() if (savingsAccountTransaction.isPostInterestCalculationRequired()
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate())) { && account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate())) {
account.postInterest(mc, today); account.postInterest(mc, today, isInterestTransfer);
} else { } else {
account.calculateInterestUsing(mc, today); account.calculateInterestUsing(mc, today, isInterestTransfer);
} }
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.undoTransactionAction); account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.undoTransactionAction);
account.activateAccountBasedOnBalance(); account.activateAccountBasedOnBalance();
@@ -443,6 +444,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
} }
SavingsAccountTransaction transaction = null; SavingsAccountTransaction transaction = null;
boolean isInterestTransfer = false;
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount, final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
paymentDetail, savingsAccountTransaction.createdDate()); paymentDetail, savingsAccountTransaction.createdDate());
if (savingsAccountTransaction.isDeposit()) { if (savingsAccountTransaction.isDeposit()) {
@@ -454,9 +456,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
if (account.isBeforeLastPostingPeriod(transactionDate) if (account.isBeforeLastPostingPeriod(transactionDate)
|| account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate())) { || account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate())) {
account.postInterest(mc, today); account.postInterest(mc, today, isInterestTransfer);
} else { } else {
account.calculateInterestUsing(mc, today); account.calculateInterestUsing(mc, today, isInterestTransfer);
} }
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.adjustTransactionAction); account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.adjustTransactionAction);
account.activateAccountBasedOnBalance(); account.activateAccountBasedOnBalance();
@@ -541,7 +543,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
savingsAccount.getTransactions().add(newTransferTransaction); savingsAccount.getTransactions().add(newTransferTransaction);
savingsAccount.setStatus(SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue()); savingsAccount.setStatus(SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue());
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
savingsAccount.calculateInterestUsing(mc, transferDate); boolean isInterestTransfer = false;
savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer);
this.savingsAccountTransactionRepository.save(newTransferTransaction); this.savingsAccountTransactionRepository.save(newTransferTransaction);
this.savingAccountRepository.save(savingsAccount); this.savingAccountRepository.save(savingsAccount);
@@ -564,7 +567,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
savingsAccount.getTransactions().add(withdrawtransferTransaction); savingsAccount.getTransactions().add(withdrawtransferTransaction);
savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue()); savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue());
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
savingsAccount.calculateInterestUsing(mc, transferDate); boolean isInterestTransfer = false;
savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer);
this.savingsAccountTransactionRepository.save(withdrawtransferTransaction); this.savingsAccountTransactionRepository.save(withdrawtransferTransaction);
this.savingAccountRepository.save(savingsAccount); this.savingAccountRepository.save(savingsAccount);
@@ -597,9 +601,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
if (fieldOfficer != null) { if (fieldOfficer != null) {
savingsAccount.update(fieldOfficer); savingsAccount.update(fieldOfficer);
} }
boolean isInterestTransfer = false;
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
savingsAccount.calculateInterestUsing(mc, transferDate); savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer);
this.savingsAccountTransactionRepository.save(acceptTransferTransaction); this.savingsAccountTransactionRepository.save(acceptTransferTransaction);
this.savingAccountRepository.save(savingsAccount); this.savingAccountRepository.save(savingsAccount);
@@ -736,14 +740,14 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
account.waiveCharge(savingsAccountChargeId); account.waiveCharge(savingsAccountChargeId);
boolean isInterestTransfer = false;
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) { if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) {
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
account.postInterest(mc, today); account.postInterest(mc, today, isInterestTransfer);
} else { } else {
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
account.calculateInterestUsing(mc, today); account.calculateInterestUsing(mc, today, isInterestTransfer);
} }
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.waiveChargeTransactionAction); account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.waiveChargeTransactionAction);
@@ -852,14 +856,14 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final Set<Long> existingReversedTransactionIds = new HashSet<Long>(); final Set<Long> existingReversedTransactionIds = new HashSet<Long>();
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter); account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter);
boolean isInterestTransfer = false;
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
if (account.isBeforeLastPostingPeriod(transactionDate)) { if (account.isBeforeLastPostingPeriod(transactionDate)) {
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
account.postInterest(mc, today); account.postInterest(mc, today, isInterestTransfer);
} else { } else {
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
account.calculateInterestUsing(mc, today); account.calculateInterestUsing(mc, today, isInterestTransfer);
} }
account.validateAccountBalanceDoesNotBecomeNegative("." + SavingsAccountTransactionType.PAY_CHARGE.getCode()); account.validateAccountBalanceDoesNotBecomeNegative("." + SavingsAccountTransactionType.PAY_CHARGE.getCode());