From 38c6702cae452331717b0d5d8b9d7eff732ebab0 Mon Sep 17 00:00:00 2001 From: Pramod Nuthakki Date: Wed, 11 Jun 2014 02:47:28 +0530 Subject: [PATCH] MIFOSX-1270 : corrected accounting for activation charge --- ...ashBasedAccountingProcessorForSavings.java | 48 ++++++++++++++++- .../savings/domain/SavingsAccount.java | 54 ++++++++++++------- 2 files changed, 81 insertions(+), 21 deletions(-) diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/CashBasedAccountingProcessorForSavings.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/CashBasedAccountingProcessorForSavings.java index 0c07187f2..4d7dffa82 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/CashBasedAccountingProcessorForSavings.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/CashBasedAccountingProcessorForSavings.java @@ -77,7 +77,7 @@ public class CashBasedAccountingProcessorForSavings implements AccountingProcess this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, ORGANIZATION_ACCOUNTS.LIABILITY_TRANSFER_SUSPENSE.getValue(), CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId, - transactionId, transactionDate, amount, isReversal); + transactionId, transactionDate, overdraftAmount, isReversal); if (amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) == 1) { this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, ORGANIZATION_ACCOUNTS.LIABILITY_TRANSFER_SUSPENSE.getValue(), @@ -88,7 +88,7 @@ public class CashBasedAccountingProcessorForSavings implements AccountingProcess this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.getValue(), CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId, - transactionId, transactionDate, amount, isReversal); + transactionId, transactionDate, overdraftAmount, isReversal); if (amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) == 1) { this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.getValue(), @@ -130,6 +130,23 @@ public class CashBasedAccountingProcessorForSavings implements AccountingProcess * Handle Interest Applications and reversals of Interest * Applications **/ + else if (savingsTransactionDTO.getTransactionType().isInterestPosting() && savingsTransactionDTO.isOverdraftTransaction()) { + // Post journal entry if earned interest amount is greater than + // zero + if (savingsTransactionDTO.getAmount().compareTo(BigDecimal.ZERO) == 1) { + this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, + CASH_ACCOUNTS_FOR_SAVINGS.INTEREST_ON_SAVINGS.getValue(), + CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId, + transactionId, transactionDate, overdraftAmount, isReversal); + if (amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) == 1) { + this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, + CASH_ACCOUNTS_FOR_SAVINGS.INTEREST_ON_SAVINGS.getValue(), + CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId, + transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal); + } + } + } + else if (savingsTransactionDTO.getTransactionType().isInterestPosting()) { // Post journal entry if earned interest amount is greater than // zero @@ -141,6 +158,33 @@ public class CashBasedAccountingProcessorForSavings implements AccountingProcess } /** Handle Fees Deductions and reversals of Fees Deductions **/ + else if (savingsTransactionDTO.getTransactionType().isFeeDeduction() && savingsTransactionDTO.isOverdraftTransaction()) { + // Is the Charge a penalty? + if (penaltyPayments.size() > 0) { + this.helper.createCashBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode, + CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL, CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_PENALTIES, + savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, overdraftAmount, isReversal, + penaltyPayments); + if (amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) == 1) { + this.helper.createCashBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode, + CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL, CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_PENALTIES, + savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, + amount.subtract(overdraftAmount), isReversal, penaltyPayments); + } + } else { + this.helper.createCashBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode, + CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL, CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_FEES, + savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, overdraftAmount, isReversal, + feePayments); + if (amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) == 1) { + this.helper.createCashBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode, + CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL, CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_FEES, savingsProductId, + paymentTypeId, savingsId, transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal, + feePayments); + } + } + } + else if (savingsTransactionDTO.getTransactionType().isFeeDeduction()) { // Is the Charge a penalty? if (penaltyPayments.size() > 0) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java index 8701a3ecc..ac86abb85 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java @@ -449,9 +449,12 @@ public class SavingsAccount extends AbstractPersistable { * calculate the amount of interest due at the end of each 'crediting' * period check if an existing 'interest posting' transaction exists for * date and matches the amount posted - * @param isInterestTransfer TODO + * + * @param isInterestTransfer + * TODO */ - public List calculateInterestUsing(final MathContext mc, final LocalDate upToInterestCalculationDate, boolean isInterestTransfer) { + public List calculateInterestUsing(final MathContext mc, final LocalDate upToInterestCalculationDate, + boolean isInterestTransfer) { // no openingBalance concept supported yet but probably will to allow // for migrations. @@ -488,7 +491,8 @@ public class SavingsAccount extends AbstractPersistable { final PostingPeriod postingPeriod = PostingPeriod.createFrom(periodInterval, periodStartingBalance, retreiveOrderedNonInterestPostingTransactions(), this.currency, compoundingPeriodType, interestCalculationType, - interestRateAsFraction, daysInYearType.getValue(), upToInterestCalculationDate, interestPostTransactions, isInterestTransfer); + interestRateAsFraction, daysInYearType.getValue(), upToInterestCalculationDate, interestPostTransactions, + isInterestTransfer); periodStartingBalance = postingPeriod.closingBalance(); @@ -587,9 +591,10 @@ public class SavingsAccount extends AbstractPersistable { } resetAccountTransactionsEndOfDayBalances(accountTransactionsSorted, interestPostingUpToDate); } - - protected void resetAccountTransactionsEndOfDayBalances(final List accountTransactionsSorted, final LocalDate interestPostingUpToDate) { - // loop over transactions in reverse + + protected void resetAccountTransactionsEndOfDayBalances(final List accountTransactionsSorted, + final LocalDate interestPostingUpToDate) { + // loop over transactions in reverse LocalDate endOfBalanceDate = interestPostingUpToDate; for (int i = accountTransactionsSorted.size() - 1; i >= 0; i--) { final SavingsAccountTransaction transaction = accountTransactionsSorted.get(i); @@ -618,8 +623,9 @@ public class SavingsAccount extends AbstractPersistable { if (isDateInTheFuture(transactionDTO.getTransactionDate())) { final String defaultUserMessage = "Transaction date cannot be in the future."; - final ApiParameterError error = ApiParameterError.parameterError("error.msg." + resourceTypeName + ".transaction.in.the.future", - defaultUserMessage, "transactionDate", transactionDTO.getTransactionDate().toString(transactionDTO.getFormatter())); + final ApiParameterError error = ApiParameterError.parameterError( + "error.msg." + resourceTypeName + ".transaction.in.the.future", defaultUserMessage, "transactionDate", transactionDTO + .getTransactionDate().toString(transactionDTO.getFormatter())); final List dataValidationErrors = new ArrayList(); dataValidationErrors.add(error); @@ -790,8 +796,8 @@ public class SavingsAccount extends AbstractPersistable { if (runningBalance.isLessThanZero()) { // final List dataValidationErrors = new ArrayList(); - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) - .resource(depositAccountType().resourceName() + transactionAction); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(depositAccountType() + .resourceName() + transactionAction); if (this.allowOverdraft) { Money limit = runningBalance.zero(); @@ -1316,7 +1322,7 @@ public class SavingsAccount extends AbstractPersistable { } if (transactionToUndo == null) { throw new SavingsAccountTransactionNotFoundException(this.getId(), transactionId); } - + validateAttemptToUndoTransferRelatedTransactions(transactionToUndo); validateActivityNotBeforeClientOrGroupTransferDate(SavingsEvent.SAVINGS_UNDO_TRANSACTION, transactionToUndo.transactionLocalDate()); transactionToUndo.reverse(); @@ -1480,8 +1486,8 @@ public class SavingsAccount extends AbstractPersistable { final Map actualChanges = new LinkedHashMap(); final List dataValidationErrors = new ArrayList(); - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) - .resource(depositAccountType().resourceName() + SavingsApiConstants.activateAction); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(depositAccountType() + .resourceName() + SavingsApiConstants.activateAction); final SavingsAccountStatusType currentStatus = SavingsAccountStatusType.fromInt(this.status); if (!SavingsAccountStatusType.APPROVED.hasStateOf(currentStatus)) { @@ -1553,10 +1559,6 @@ public class SavingsAccount extends AbstractPersistable { } validateActivityNotBeforeClientOrGroupTransferDate(SavingsEvent.SAVINGS_ACTIVATE, activationDate); - // auto enter deposit for minimum required opening balance when - // activating account. - processAccountUponActivation(); - return actualChanges; } @@ -1592,11 +1594,25 @@ public class SavingsAccount extends AbstractPersistable { } private void payActivationCharges() { + boolean isSavingsChargeApplied = false; for (SavingsAccountCharge savingsAccountCharge : this.charges()) { if (savingsAccountCharge.isSavingsActivation()) { + isSavingsChargeApplied = true; payCharge(savingsAccountCharge, savingsAccountCharge.getAmountOutstanding(getCurrency()), getActivationLocalDate()); } } + + if (isSavingsChargeApplied) { + final MathContext mc = MathContext.DECIMAL64; + boolean isInterestTransfer = false; + if (this.isBeforeLastPostingPeriod(getActivationLocalDate())) { + final LocalDate today = DateUtils.getLocalDateOfTenant(); + this.postInterest(mc, today, isInterestTransfer); + } else { + final LocalDate today = DateUtils.getLocalDateOfTenant(); + this.calculateInterestUsing(mc, today, isInterestTransfer); + } + } } public Map close(final AppUser currentUser, final JsonCommand command, final LocalDate tenantsTodayDate) { @@ -2027,7 +2043,7 @@ public class SavingsAccount extends AbstractPersistable { baseDataValidator.reset().parameter(SavingsApiConstants.overdraftLimitParamName).value(this.overdraftLimit) .failWithCode("cannot.exceed.product.value"); } - + validateInterestPostingAndCompoundingPeriodTypes(baseDataValidator); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } @@ -2054,7 +2070,7 @@ public class SavingsAccount extends AbstractPersistable { return getActivationLocalDate().isEqual(getSubmittedOnLocalDate()); } - + public void validateInterestPostingAndCompoundingPeriodTypes(final DataValidatorBuilder baseDataValidator) { Map> postingtoCompoundMap = new HashMap>(); postingtoCompoundMap.put(