Merge pull request #937 from pramodn02/MIFOSX-1270
MIFOSX-1270 : corrected accounting for activation charge
This commit is contained in:
+46
-2
@@ -77,7 +77,7 @@ public class CashBasedAccountingProcessorForSavings implements AccountingProcess
|
|||||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||||
ORGANIZATION_ACCOUNTS.LIABILITY_TRANSFER_SUSPENSE.getValue(),
|
ORGANIZATION_ACCOUNTS.LIABILITY_TRANSFER_SUSPENSE.getValue(),
|
||||||
CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
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) {
|
if (amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) == 1) {
|
||||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||||
ORGANIZATION_ACCOUNTS.LIABILITY_TRANSFER_SUSPENSE.getValue(),
|
ORGANIZATION_ACCOUNTS.LIABILITY_TRANSFER_SUSPENSE.getValue(),
|
||||||
@@ -88,7 +88,7 @@ public class CashBasedAccountingProcessorForSavings implements AccountingProcess
|
|||||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||||
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.getValue(),
|
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.getValue(),
|
||||||
CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
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) {
|
if (amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) == 1) {
|
||||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||||
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.getValue(),
|
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.getValue(),
|
||||||
@@ -130,6 +130,23 @@ public class CashBasedAccountingProcessorForSavings implements AccountingProcess
|
|||||||
* Handle Interest Applications and reversals of Interest
|
* Handle Interest Applications and reversals of Interest
|
||||||
* Applications
|
* 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()) {
|
else if (savingsTransactionDTO.getTransactionType().isInterestPosting()) {
|
||||||
// Post journal entry if earned interest amount is greater than
|
// Post journal entry if earned interest amount is greater than
|
||||||
// zero
|
// zero
|
||||||
@@ -141,6 +158,33 @@ public class CashBasedAccountingProcessorForSavings implements AccountingProcess
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Handle Fees Deductions and reversals of Fees Deductions **/
|
/** 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()) {
|
else if (savingsTransactionDTO.getTransactionType().isFeeDeduction()) {
|
||||||
// Is the Charge a penalty?
|
// Is the Charge a penalty?
|
||||||
if (penaltyPayments.size() > 0) {
|
if (penaltyPayments.size() > 0) {
|
||||||
|
|||||||
+35
-19
@@ -449,9 +449,12 @@ 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
|
*
|
||||||
|
* @param isInterestTransfer
|
||||||
|
* TODO
|
||||||
*/
|
*/
|
||||||
public List<PostingPeriod> calculateInterestUsing(final MathContext mc, final LocalDate upToInterestCalculationDate, boolean isInterestTransfer) {
|
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.
|
||||||
@@ -488,7 +491,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
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, interestPostTransactions, isInterestTransfer);
|
interestRateAsFraction, daysInYearType.getValue(), upToInterestCalculationDate, interestPostTransactions,
|
||||||
|
isInterestTransfer);
|
||||||
|
|
||||||
periodStartingBalance = postingPeriod.closingBalance();
|
periodStartingBalance = postingPeriod.closingBalance();
|
||||||
|
|
||||||
@@ -587,9 +591,10 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
resetAccountTransactionsEndOfDayBalances(accountTransactionsSorted, interestPostingUpToDate);
|
resetAccountTransactionsEndOfDayBalances(accountTransactionsSorted, interestPostingUpToDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void resetAccountTransactionsEndOfDayBalances(final List<SavingsAccountTransaction> accountTransactionsSorted, final LocalDate interestPostingUpToDate) {
|
protected void resetAccountTransactionsEndOfDayBalances(final List<SavingsAccountTransaction> accountTransactionsSorted,
|
||||||
// loop over transactions in reverse
|
final LocalDate interestPostingUpToDate) {
|
||||||
|
// loop over transactions in reverse
|
||||||
LocalDate endOfBalanceDate = interestPostingUpToDate;
|
LocalDate endOfBalanceDate = interestPostingUpToDate;
|
||||||
for (int i = accountTransactionsSorted.size() - 1; i >= 0; i--) {
|
for (int i = accountTransactionsSorted.size() - 1; i >= 0; i--) {
|
||||||
final SavingsAccountTransaction transaction = accountTransactionsSorted.get(i);
|
final SavingsAccountTransaction transaction = accountTransactionsSorted.get(i);
|
||||||
@@ -618,8 +623,9 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
if (isDateInTheFuture(transactionDTO.getTransactionDate())) {
|
if (isDateInTheFuture(transactionDTO.getTransactionDate())) {
|
||||||
final String defaultUserMessage = "Transaction date cannot be in the future.";
|
final String defaultUserMessage = "Transaction date cannot be in the future.";
|
||||||
final ApiParameterError error = ApiParameterError.parameterError("error.msg." + resourceTypeName + ".transaction.in.the.future",
|
final ApiParameterError error = ApiParameterError.parameterError(
|
||||||
defaultUserMessage, "transactionDate", transactionDTO.getTransactionDate().toString(transactionDTO.getFormatter()));
|
"error.msg." + resourceTypeName + ".transaction.in.the.future", defaultUserMessage, "transactionDate", transactionDTO
|
||||||
|
.getTransactionDate().toString(transactionDTO.getFormatter()));
|
||||||
|
|
||||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
dataValidationErrors.add(error);
|
dataValidationErrors.add(error);
|
||||||
@@ -790,8 +796,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
if (runningBalance.isLessThanZero()) {
|
if (runningBalance.isLessThanZero()) {
|
||||||
//
|
//
|
||||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(depositAccountType()
|
||||||
.resource(depositAccountType().resourceName() + transactionAction);
|
.resourceName() + transactionAction);
|
||||||
|
|
||||||
if (this.allowOverdraft) {
|
if (this.allowOverdraft) {
|
||||||
Money limit = runningBalance.zero();
|
Money limit = runningBalance.zero();
|
||||||
@@ -1316,7 +1322,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (transactionToUndo == null) { throw new SavingsAccountTransactionNotFoundException(this.getId(), transactionId); }
|
if (transactionToUndo == null) { throw new SavingsAccountTransactionNotFoundException(this.getId(), transactionId); }
|
||||||
|
|
||||||
validateAttemptToUndoTransferRelatedTransactions(transactionToUndo);
|
validateAttemptToUndoTransferRelatedTransactions(transactionToUndo);
|
||||||
validateActivityNotBeforeClientOrGroupTransferDate(SavingsEvent.SAVINGS_UNDO_TRANSACTION, transactionToUndo.transactionLocalDate());
|
validateActivityNotBeforeClientOrGroupTransferDate(SavingsEvent.SAVINGS_UNDO_TRANSACTION, transactionToUndo.transactionLocalDate());
|
||||||
transactionToUndo.reverse();
|
transactionToUndo.reverse();
|
||||||
@@ -1480,8 +1486,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
|
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
|
||||||
|
|
||||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(depositAccountType()
|
||||||
.resource(depositAccountType().resourceName() + SavingsApiConstants.activateAction);
|
.resourceName() + SavingsApiConstants.activateAction);
|
||||||
|
|
||||||
final SavingsAccountStatusType currentStatus = SavingsAccountStatusType.fromInt(this.status);
|
final SavingsAccountStatusType currentStatus = SavingsAccountStatusType.fromInt(this.status);
|
||||||
if (!SavingsAccountStatusType.APPROVED.hasStateOf(currentStatus)) {
|
if (!SavingsAccountStatusType.APPROVED.hasStateOf(currentStatus)) {
|
||||||
@@ -1553,10 +1559,6 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
validateActivityNotBeforeClientOrGroupTransferDate(SavingsEvent.SAVINGS_ACTIVATE, activationDate);
|
validateActivityNotBeforeClientOrGroupTransferDate(SavingsEvent.SAVINGS_ACTIVATE, activationDate);
|
||||||
|
|
||||||
// auto enter deposit for minimum required opening balance when
|
|
||||||
// activating account.
|
|
||||||
processAccountUponActivation();
|
|
||||||
|
|
||||||
return actualChanges;
|
return actualChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1592,11 +1594,25 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void payActivationCharges() {
|
private void payActivationCharges() {
|
||||||
|
boolean isSavingsChargeApplied = false;
|
||||||
for (SavingsAccountCharge savingsAccountCharge : this.charges()) {
|
for (SavingsAccountCharge savingsAccountCharge : this.charges()) {
|
||||||
if (savingsAccountCharge.isSavingsActivation()) {
|
if (savingsAccountCharge.isSavingsActivation()) {
|
||||||
|
isSavingsChargeApplied = true;
|
||||||
payCharge(savingsAccountCharge, savingsAccountCharge.getAmountOutstanding(getCurrency()), getActivationLocalDate());
|
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<String, Object> close(final AppUser currentUser, final JsonCommand command, final LocalDate tenantsTodayDate) {
|
public Map<String, Object> close(final AppUser currentUser, final JsonCommand command, final LocalDate tenantsTodayDate) {
|
||||||
@@ -2027,7 +2043,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
baseDataValidator.reset().parameter(SavingsApiConstants.overdraftLimitParamName).value(this.overdraftLimit)
|
baseDataValidator.reset().parameter(SavingsApiConstants.overdraftLimitParamName).value(this.overdraftLimit)
|
||||||
.failWithCode("cannot.exceed.product.value");
|
.failWithCode("cannot.exceed.product.value");
|
||||||
}
|
}
|
||||||
|
|
||||||
validateInterestPostingAndCompoundingPeriodTypes(baseDataValidator);
|
validateInterestPostingAndCompoundingPeriodTypes(baseDataValidator);
|
||||||
|
|
||||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||||
@@ -2054,7 +2070,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
return getActivationLocalDate().isEqual(getSubmittedOnLocalDate());
|
return getActivationLocalDate().isEqual(getSubmittedOnLocalDate());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validateInterestPostingAndCompoundingPeriodTypes(final DataValidatorBuilder baseDataValidator) {
|
public void validateInterestPostingAndCompoundingPeriodTypes(final DataValidatorBuilder baseDataValidator) {
|
||||||
Map<SavingsPostingInterestPeriodType, List<SavingsCompoundingInterestPeriodType>> postingtoCompoundMap = new HashMap<SavingsPostingInterestPeriodType, List<SavingsCompoundingInterestPeriodType>>();
|
Map<SavingsPostingInterestPeriodType, List<SavingsCompoundingInterestPeriodType>> postingtoCompoundMap = new HashMap<SavingsPostingInterestPeriodType, List<SavingsCompoundingInterestPeriodType>>();
|
||||||
postingtoCompoundMap.put(
|
postingtoCompoundMap.put(
|
||||||
|
|||||||
Reference in New Issue
Block a user