Repository: incubator-fineract Updated Branches: refs/heads/develop b3c4f75f1 -> 580840c35
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/580840c3/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java index 4c1451c..88e4be9 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java @@ -39,6 +39,8 @@ import java.util.Map; import java.util.Set; import org.apache.commons.lang.StringUtils; +import org.apache.fineract.accounting.journalentry.exception.JournalEntryInvalidException; +import org.apache.fineract.accounting.journalentry.exception.JournalEntryInvalidException.GL_JOURNAL_ENTRY_INVALID_REASON; import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService; import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; import org.apache.fineract.infrastructure.core.api.JsonCommand; @@ -95,11 +97,14 @@ import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepositoryWrap import org.apache.fineract.portfolio.savings.domain.SavingsAccountStatusType; import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction; import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransactionRepository; +import org.apache.fineract.portfolio.savings.exception.PostInterestAsOnDateException; +import org.apache.fineract.portfolio.savings.exception.PostInterestClosingDateException; import org.apache.fineract.portfolio.savings.exception.SavingsAccountClosingNotAllowedException; import org.apache.fineract.portfolio.savings.exception.SavingsAccountTransactionNotFoundException; import org.apache.fineract.portfolio.savings.exception.SavingsOfficerAssignmentException; import org.apache.fineract.portfolio.savings.exception.SavingsOfficerUnassignmentException; import org.apache.fineract.portfolio.savings.exception.TransactionUpdateNotAllowedException; +import org.apache.fineract.portfolio.savings.exception.PostInterestAsOnDateException.PostInterestAsOnException_TYPE; import org.apache.fineract.useradministration.domain.AppUser; import org.apache.fineract.useradministration.domain.AppUserRepositoryWrapper; import org.joda.time.LocalDate; @@ -255,7 +260,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId); checkClientOrGroupActive(account); - final Locale locale = command.extractLocale(); final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); @@ -268,7 +272,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi boolean isRegularTransaction = true; final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(account, fmt, transactionDate, transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction); - return new CommandProcessingResultBuilder() // .withEntityId(deposit.getId()) // .withOfficeId(account.officeId()) // @@ -277,6 +280,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi .withSavingsId(savingsId) // .with(changes) // .build(); + } private Long saveTransactionToGenerateTransactionId(final SavingsAccountTransaction transaction) { @@ -300,8 +304,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes); final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId); - checkClientOrGroupActive(account); - + checkClientOrGroupActive(account); final boolean isAccountTransfer = false; final boolean isRegularTransaction = true; final boolean isApplyWithdrawFee = true; @@ -359,7 +362,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi final MathContext mc = new MathContext(15, MoneyHelper.getRoundingMode()); boolean isInterestTransfer = false; account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, - financialYearBeginningMonth); + financialYearBeginningMonth,false); this.savingAccountRepositoryWrapper.save(account); @@ -371,13 +374,32 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi .withSavingsId(savingsId) // .build(); } - @Override - public CommandProcessingResult postInterest(final Long savingsId) { - + public CommandProcessingResult postInterest(final JsonCommand command) { + + Long savingsId=command.getSavingsId(); + final boolean postInterestAs =command.booleanPrimitiveValueOfParameterNamed("isPostInterestAsOn"); + final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate"); final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId); checkClientOrGroupActive(account); - postInterest(account); + if (postInterestAs == true) { + + if (transactionDate == null) { + + throw new PostInterestAsOnDateException(PostInterestAsOnException_TYPE.VALID_DATE); } + if (transactionDate.isBefore(account.accountSubmittedOrActivationDate())) { throw new PostInterestAsOnDateException( + PostInterestAsOnException_TYPE.ACTIVATION_DATE); } + List<SavingsAccountTransaction> savingTransactions = account.getTransactions(); + for (SavingsAccountTransaction savingTransaction : savingTransactions) { + if (transactionDate.toDate().before(savingTransaction.getDateOf())) { throw new PostInterestAsOnDateException( + PostInterestAsOnException_TYPE.LAST_TRANSACTION_DATE); } + } + + LocalDate today = DateUtils.getLocalDateOfTenant(); + if (transactionDate.isAfter(today)) { throw new PostInterestAsOnDateException(PostInterestAsOnException_TYPE.FUTURE_DATE); } + + } + postInterest(account,postInterestAs,transactionDate); return new CommandProcessingResultBuilder() // .withEntityId(savingsId) // .withOfficeId(account.officeId()) // @@ -389,7 +411,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi @Transactional @Override - public void postInterest(final SavingsAccount account) { + public void postInterest(final SavingsAccount account,final boolean postInterestAs,final LocalDate transactionDate) { final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService .isSavingsInterestPostingAtCurrentPeriodEnd(); @@ -403,14 +425,18 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi final LocalDate today = DateUtils.getLocalDateOfTenant(); final MathContext mc = new MathContext(10, MoneyHelper.getRoundingMode()); boolean isInterestTransfer = false; - account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); - + if(postInterestAs==false){ + account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,postInterestAs); + } + else{ + account.postInterest(mc, transactionDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,postInterestAs); + } // for generating transaction id's List<SavingsAccountTransaction> transactions = account.getTransactions(); for (SavingsAccountTransaction accountTransaction : transactions) { if (accountTransaction.getId() == null) { this.savingsAccountTransactionRepository.save(accountTransaction); - } + } } this.savingAccountRepositoryWrapper.saveAndFlush(account); @@ -418,7 +444,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds); } } - + @Override public CommandProcessingResult undoTransaction(final Long savingsId, final Long transactionId, final boolean allowAccountTransferModification) { @@ -466,10 +492,10 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi checkClientOrGroupActive(account); if (savingsAccountTransaction.isPostInterestCalculationRequired() && account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate())) { - account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); + account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,false); } else { account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, - financialYearBeginningMonth); + financialYearBeginningMonth,false); } List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null; if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) == 1) { @@ -555,10 +581,10 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi if (account.isBeforeLastPostingPeriod(transactionDate) || account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate())) { - account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); + account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,false); } else { account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, - financialYearBeginningMonth); + financialYearBeginningMonth,false); } List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null; if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) == 1) { @@ -604,9 +630,10 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi @Override public CommandProcessingResult close(final Long savingsId, final JsonCommand command) { final AppUser user = this.context.authenticatedUser(); - + this.savingsAccountTransactionDataValidator.validateClosing(command); final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId); + final boolean isLinkedWithAnyActiveLoan = this.accountAssociationsReadPlatformService.isLinkedWithAnyActiveAccount(savingsId); if (isLinkedWithAnyActiveLoan) { @@ -614,18 +641,36 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi + " is not allowed, since it is linked with one of the active accounts"; throw new SavingsAccountClosingNotAllowedException("linked", defaultUserMessage, savingsId); } + + final boolean isWithdrawBalance = command.booleanPrimitiveValueOfParameterNamed(withdrawBalanceParamName); final Locale locale = command.extractLocale(); final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); final LocalDate closedDate = command.localDateValueOfParameterNamed(SavingsApiConstants.closedOnDateParamName); - + final boolean isPostInterest = command.booleanPrimitiveValueOfParameterNamed(SavingsApiConstants.postInterestValidationOnClosure); + // postInterest(account,closedDate,flag); + if (isPostInterest) { + boolean postInterestOnClosingDate = false; + List<SavingsAccountTransaction> savingTransactions = account.getTransactions(); + for (SavingsAccountTransaction savingTransaction : savingTransactions) { + if (closedDate.toDate().equals(savingTransaction.getDateOf())) if (savingTransaction.getTypeOf() == SavingsAccountTransactionType.OVERDRAFT_INTEREST.getValue()) { + postInterestOnClosingDate = true; + } + } + if (postInterestOnClosingDate == false) { throw new PostInterestClosingDateException(); } + } + final Map<String, Object> changes = new LinkedHashMap<>(); if (isWithdrawBalance && account.getSummary().getAccountBalance(account.getCurrency()).isGreaterThanZero()) { + + + final BigDecimal transactionAmount = account.getSummary().getAccountBalance(); + final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes); final boolean isAccountTransfer = false; @@ -685,8 +730,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi savingsAccount.setStatus(SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue()); final MathContext mc = MathContext.DECIMAL64; boolean isInterestTransfer = false; + boolean postInterestAsOn = false; savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, - financialYearBeginningMonth); + financialYearBeginningMonth, postInterestAsOn); this.savingsAccountTransactionRepository.save(newTransferTransaction); this.savingAccountRepositoryWrapper.saveAndFlush(savingsAccount); @@ -715,8 +761,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue()); final MathContext mc = MathContext.DECIMAL64; boolean isInterestTransfer = false; + boolean postInterestAsOn =false; savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, - financialYearBeginningMonth); + financialYearBeginningMonth, postInterestAsOn); this.savingsAccountTransactionRepository.save(withdrawtransferTransaction); this.savingAccountRepositoryWrapper.saveAndFlush(savingsAccount); @@ -756,8 +803,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi } boolean isInterestTransfer = false; final MathContext mc = MathContext.DECIMAL64; + boolean postInterestAsOn = false; savingsAccount.calculateInterestUsing(mc, transferDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, - financialYearBeginningMonth); + financialYearBeginningMonth, postInterestAsOn); this.savingsAccountTransactionRepository.save(acceptTransferTransaction); this.savingAccountRepositoryWrapper.saveAndFlush(savingsAccount); @@ -906,14 +954,16 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi account.waiveCharge(savingsAccountChargeId, user); boolean isInterestTransfer = false; + boolean postInterestAsOn = false; final MathContext mc = MathContext.DECIMAL64; if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) { final LocalDate today = DateUtils.getLocalDateOfTenant(); - account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); + account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, + postInterestAsOn); } else { final LocalDate today = DateUtils.getLocalDateOfTenant(); account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, - financialYearBeginningMonth); + financialYearBeginningMonth, postInterestAsOn); } List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null; if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) == 1) { @@ -1038,14 +1088,16 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter, user); boolean isInterestTransfer = false; + boolean postInterestAsOn = false; final MathContext mc = MathContext.DECIMAL64; if (account.isBeforeLastPostingPeriod(transactionDate)) { final LocalDate today = DateUtils.getLocalDateOfTenant(); - account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); + account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, + postInterestAsOn); } else { final LocalDate today = DateUtils.getLocalDateOfTenant(); account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, - financialYearBeginningMonth); + financialYearBeginningMonth, postInterestAsOn); } List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null; if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) == 1) { http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/580840c3/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularServiceImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularServiceImpl.java index 7563f85..e3f2f0c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularServiceImpl.java @@ -60,7 +60,9 @@ public class SavingsSchedularServiceImpl implements SavingsSchedularService { for (final SavingsAccount savingsAccount : savingsAccounts) { try { this.savingAccountAssembler.assignSavingAccountHelpers(savingsAccount); - this.savingsAccountWritePlatformService.postInterest(savingsAccount); + boolean postInterestAsOn = false; + LocalDate transactionDate = null; + this.savingsAccountWritePlatformService.postInterest(savingsAccount, postInterestAsOn, transactionDate); } catch (Exception e) { Throwable realCause = e; if (e.getCause() != null) { http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/580840c3/fineract-provider/src/main/resources/sql/migrations/core_db/V321__boolean_field_As_Interest_PostedOn.sql ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/resources/sql/migrations/core_db/V321__boolean_field_As_Interest_PostedOn.sql b/fineract-provider/src/main/resources/sql/migrations/core_db/V321__boolean_field_As_Interest_PostedOn.sql new file mode 100644 index 0000000..19ba1da --- /dev/null +++ b/fineract-provider/src/main/resources/sql/migrations/core_db/V321__boolean_field_As_Interest_PostedOn.sql @@ -0,0 +1,21 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +ALTER TABLE m_savings_account_transaction +ADD is_manual boolean default 0 \ No newline at end of file