Merge pull request #2372 from logoutdhaval/fineract-1642
FINERACT-1642: Bulk reversal of related Transactions
This commit is contained in:
+8
@@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.api;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
@@ -182,6 +184,12 @@ public class SavingsAccountTransactionsApiResource {
|
||||
@Path("{transactionId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Operation(summary = "Undo/Reverse/Modify/Release Amount transaction API", description = "Undo/Reverse/Modify/Release Amount transaction API\n\n"
|
||||
+ "Example Requests:\n" + "\n" + "\n" + "savingsaccounts/{savingsId}/transactions/{transactionId}?command=reverse\n" + "\n"
|
||||
+ "Accepted command = undo, reverse, modify, releaseAmount")
|
||||
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = SavingsAccountTransactionsApiResourceSwagger.PostSavingsAccountBulkReversalTransactionsRequest.class)))
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(implementation = SavingsAccountTransactionsApiResourceSwagger.PostSavingsAccountBulkReversalTransactionsRequest.class)))) })
|
||||
public String adjustTransaction(@PathParam("savingsId") final Long savingsId, @PathParam("transactionId") final Long transactionId,
|
||||
@QueryParam("command") final String commandParam, final String apiRequestBodyAsJson) {
|
||||
|
||||
|
||||
+9
@@ -57,4 +57,13 @@ final class SavingsAccountTransactionsApiResourceSwagger {
|
||||
@Schema(example = "1")
|
||||
public Integer resourceId;
|
||||
}
|
||||
|
||||
@Schema(description = "PostSavingsAccountBulkReversalTransactionsRequest")
|
||||
public static final class PostSavingsAccountBulkReversalTransactionsRequest {
|
||||
|
||||
private PostSavingsAccountBulkReversalTransactionsRequest() {}
|
||||
|
||||
@Schema(example = "true")
|
||||
public String isBulk;
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -948,4 +948,9 @@ public final class SavingsAccountTransactionData implements Serializable {
|
||||
this.id = id;
|
||||
this.modifiedId = id;
|
||||
}
|
||||
|
||||
public boolean isReversalTransaction() {
|
||||
return Boolean.TRUE.equals(this.isReversal);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -639,13 +639,13 @@ public class FixedDepositAccount extends SavingsAccount {
|
||||
return interestOnMaturity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInterest(final MathContext mc, final LocalDate postingDate, boolean isInterestTransfer,
|
||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth,
|
||||
final LocalDate postInterestOnDate, final boolean backdatedTxnsAllowedTill) {
|
||||
final LocalDate interestPostingUpToDate = interestPostingUpToDate(postingDate);
|
||||
boolean postReversals = false;
|
||||
super.postInterest(mc, interestPostingUpToDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill);
|
||||
financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill, postReversals);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-2
@@ -752,13 +752,13 @@ public class RecurringDepositAccount extends SavingsAccount {
|
||||
return interestOnMaturity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInterest(final MathContext mc, final LocalDate postingDate, final boolean isInterestTransfer,
|
||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth,
|
||||
final LocalDate postInterestAson, final boolean backdatedTxnsAllowedTill) {
|
||||
final LocalDate interestPostingUpToDate = interestPostingUpToDate(postingDate);
|
||||
boolean postReversals = false;
|
||||
super.postInterest(mc, interestPostingUpToDate, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestAson, backdatedTxnsAllowedTill);
|
||||
financialYearBeginningMonth, postInterestAson, backdatedTxnsAllowedTill, postReversals);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+40
-25
@@ -53,6 +53,7 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
@@ -511,7 +512,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
|
||||
public void postInterest(final MathContext mc, final LocalDate interestPostingUpToDate, final boolean isInterestTransfer,
|
||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth,
|
||||
final LocalDate postInterestOnDate, final boolean backdatedTxnsAllowedTill) {
|
||||
final LocalDate postInterestOnDate, final boolean backdatedTxnsAllowedTill, final boolean postReversals) {
|
||||
final List<PostingPeriod> postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate, isInterestTransfer,
|
||||
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill);
|
||||
|
||||
@@ -570,6 +571,10 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
if (correctionRequired) {
|
||||
boolean applyWithHoldTaxForOldTransaction = false;
|
||||
postingTransaction.reverse();
|
||||
SavingsAccountTransaction reversal = null;
|
||||
if (postReversals) {
|
||||
reversal = SavingsAccountTransaction.reversal(postingTransaction);
|
||||
}
|
||||
final SavingsAccountTransaction withholdTransaction = findTransactionFor(interestPostingTransactionDate,
|
||||
withholdTransactions);
|
||||
if (withholdTransaction != null) {
|
||||
@@ -588,8 +593,14 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
}
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
addTransactionToExisting(newPostingTransaction);
|
||||
if (reversal != null) {
|
||||
addTransactionToExisting(reversal);
|
||||
}
|
||||
} else {
|
||||
addTransaction(newPostingTransaction);
|
||||
if (reversal != null) {
|
||||
addTransaction(reversal);
|
||||
}
|
||||
}
|
||||
if (applyWithHoldTaxForOldTransaction) {
|
||||
createWithHoldTransaction(interestEarnedToBePostedForPeriod.getAmount(), interestPostingTransactionDate,
|
||||
@@ -1166,7 +1177,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
}
|
||||
|
||||
public SavingsAccountTransaction withdraw(final SavingsAccountTransactionDTO transactionDTO, final boolean applyWithdrawFee,
|
||||
final boolean backdatedTxnsAllowedTill) {
|
||||
final boolean backdatedTxnsAllowedTill, String refNo) {
|
||||
|
||||
if (!isTransactionsAllowed()) {
|
||||
|
||||
@@ -1222,13 +1233,13 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
if (applyWithdrawFee) {
|
||||
// auto pay withdrawal fee
|
||||
payWithdrawalFee(transactionDTO.getTransactionAmount(), transactionDTO.getTransactionDate(), transactionDTO.getAppUser(),
|
||||
transactionDTO.getPaymentDetail(), backdatedTxnsAllowedTill);
|
||||
transactionDTO.getPaymentDetail(), backdatedTxnsAllowedTill, refNo);
|
||||
}
|
||||
|
||||
final Money transactionAmountMoney = Money.of(this.currency, transactionDTO.getTransactionAmount());
|
||||
final SavingsAccountTransaction transaction = SavingsAccountTransaction.withdrawal(this, office(),
|
||||
transactionDTO.getPaymentDetail(), transactionDTO.getTransactionDate(), transactionAmountMoney,
|
||||
transactionDTO.getCreatedDate(), transactionDTO.getAppUser());
|
||||
transactionDTO.getCreatedDate(), transactionDTO.getAppUser(), refNo);
|
||||
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
addTransactionToExisting(transaction);
|
||||
@@ -1256,7 +1267,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
}
|
||||
|
||||
private void payWithdrawalFee(final BigDecimal transactionAmount, final LocalDate transactionDate, final AppUser user,
|
||||
final PaymentDetail paymentDetail, final boolean backdatedTxnsAllowedTill) {
|
||||
final PaymentDetail paymentDetail, final boolean backdatedTxnsAllowedTill, final String refNo) {
|
||||
for (SavingsAccountCharge charge : this.charges()) {
|
||||
|
||||
if (charge.isWithdrawalFee() && charge.isActive()) {
|
||||
@@ -1268,23 +1279,23 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
if (charge.isEnablePaymentType() && charge.isEnableFreeWithdrawal()) { // discount transaction to
|
||||
// specific paymentType
|
||||
if (paymentDetail.getPaymentType().getPaymentName().equals(charge.getCharge().getPaymentType().getPaymentName())) {
|
||||
resetFreeChargeDaysCount(charge, transactionAmount, transactionDate, user);
|
||||
resetFreeChargeDaysCount(charge, transactionAmount, transactionDate, user, refNo);
|
||||
}
|
||||
} else if (charge.isEnablePaymentType()) { // normal charge-transaction to specific paymentType
|
||||
if (paymentDetail.getPaymentType().getPaymentName().equals(charge.getCharge().getPaymentType().getPaymentName())) {
|
||||
charge.updateWithdralFeeAmount(transactionAmount);
|
||||
this.payCharge(charge, charge.getAmountOutstanding(this.getCurrency()), transactionDate, user,
|
||||
backdatedTxnsAllowedTill);
|
||||
backdatedTxnsAllowedTill, refNo);
|
||||
}
|
||||
} else if (!charge.isEnablePaymentType() && charge.isEnableFreeWithdrawal()) { // discount transaction
|
||||
// irrespective of
|
||||
// PaymentTypes.
|
||||
resetFreeChargeDaysCount(charge, transactionAmount, transactionDate, user);
|
||||
resetFreeChargeDaysCount(charge, transactionAmount, transactionDate, user, refNo);
|
||||
|
||||
} else { // normal-withdraw
|
||||
charge.updateWithdralFeeAmount(transactionAmount);
|
||||
this.payCharge(charge, charge.getAmountOutstanding(this.getCurrency()), transactionDate, user,
|
||||
backdatedTxnsAllowedTill);
|
||||
this.payCharge(charge, charge.getAmountOutstanding(this.getCurrency()), transactionDate, user, backdatedTxnsAllowedTill,
|
||||
refNo);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1293,7 +1304,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
}
|
||||
|
||||
private void resetFreeChargeDaysCount(SavingsAccountCharge charge, final BigDecimal transactionAmount, final LocalDate transactionDate,
|
||||
final AppUser user) {
|
||||
final AppUser user, final String refNo) {
|
||||
Date resetDate = charge.getResetChargeDate();
|
||||
|
||||
Integer restartPeriod = charge.getRestartFrequency();
|
||||
@@ -1319,7 +1330,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
YearMonth gapYearMonth = YearMonth.from(gapIntervalMonth);
|
||||
YearMonth localYearMonth = YearMonth.from(localDate);
|
||||
if (localYearMonth.isBefore(gapYearMonth)) {
|
||||
countValidation(charge, transactionAmount, transactionDate, user);
|
||||
countValidation(charge, transactionAmount, transactionDate, user, refNo);
|
||||
} else {
|
||||
discountCharge(1, charge);
|
||||
}
|
||||
@@ -1338,7 +1349,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
Integer totalDays = days.intValue();
|
||||
|
||||
if (totalDays < restartPeriod) {
|
||||
countValidation(charge, transactionAmount, transactionDate, user);
|
||||
countValidation(charge, transactionAmount, transactionDate, user, refNo);
|
||||
} else {
|
||||
discountCharge(1, charge);
|
||||
}
|
||||
@@ -1346,7 +1357,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
}
|
||||
|
||||
private void countValidation(SavingsAccountCharge charge, final BigDecimal transactionAmount, final LocalDate transactionDate,
|
||||
final AppUser user) {
|
||||
final AppUser user, final String refNo) {
|
||||
boolean backdatedTxnsAllowedTill = false;
|
||||
if (charge.getFreeWithdrawalCount() < charge.getFrequencyFreeWithdrawalCharge()) {
|
||||
final Integer count = charge.getFreeWithdrawalCount() + 1;
|
||||
@@ -1354,7 +1365,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
charge.updateNoWithdrawalFee();
|
||||
} else {
|
||||
charge.updateWithdralFeeAmount(transactionAmount);
|
||||
this.payCharge(charge, charge.getAmountOutstanding(this.getCurrency()), transactionDate, user, backdatedTxnsAllowedTill);
|
||||
this.payCharge(charge, charge.getAmountOutstanding(this.getCurrency()), transactionDate, user, backdatedTxnsAllowedTill, refNo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2743,11 +2754,12 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
private void payActivationCharges(final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth,
|
||||
final AppUser user, final boolean backdatedTxnsAllowedTill) {
|
||||
boolean isSavingsChargeApplied = false;
|
||||
UUID refNo = UUID.randomUUID();
|
||||
for (SavingsAccountCharge savingsAccountCharge : this.charges()) {
|
||||
if (savingsAccountCharge.isSavingsActivation()) {
|
||||
isSavingsChargeApplied = true;
|
||||
payCharge(savingsAccountCharge, savingsAccountCharge.getAmountOutstanding(getCurrency()), getActivationLocalDate(), user,
|
||||
backdatedTxnsAllowedTill);
|
||||
backdatedTxnsAllowedTill, refNo.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2757,8 +2769,9 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
LocalDate postInterestAsOnDate = null;
|
||||
if (this.isBeforeLastPostingPeriod(getActivationLocalDate(), backdatedTxnsAllowedTill)) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
boolean postReversals = false;
|
||||
this.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestAsOnDate, backdatedTxnsAllowedTill);
|
||||
postInterestAsOnDate, backdatedTxnsAllowedTill, postReversals);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
this.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
@@ -3106,8 +3119,8 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
}
|
||||
|
||||
public SavingsAccountTransaction payCharge(final SavingsAccountCharge savingsAccountCharge, final BigDecimal amountPaid,
|
||||
final LocalDate transactionDate, final DateTimeFormatter formatter, final AppUser user,
|
||||
final boolean backdatedTxnsAllowedTill) {
|
||||
final LocalDate transactionDate, final DateTimeFormatter formatter, final AppUser user, final boolean backdatedTxnsAllowedTill,
|
||||
final String refNo) {
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
@@ -3195,21 +3208,21 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
}
|
||||
}
|
||||
|
||||
return this.payCharge(savingsAccountCharge, chargePaid, transactionDate, user, backdatedTxnsAllowedTill);
|
||||
return this.payCharge(savingsAccountCharge, chargePaid, transactionDate, user, backdatedTxnsAllowedTill, refNo);
|
||||
}
|
||||
|
||||
public SavingsAccountTransaction payCharge(final SavingsAccountCharge savingsAccountCharge, final Money amountPaid,
|
||||
final LocalDate transactionDate, final AppUser user, final boolean backdatedTxnsAllowedTill) {
|
||||
final LocalDate transactionDate, final AppUser user, final boolean backdatedTxnsAllowedTill, String refNo) {
|
||||
savingsAccountCharge.pay(getCurrency(), amountPaid);
|
||||
return handlePayChargeTransactions(savingsAccountCharge, amountPaid, transactionDate, user, backdatedTxnsAllowedTill);
|
||||
return handlePayChargeTransactions(savingsAccountCharge, amountPaid, transactionDate, user, backdatedTxnsAllowedTill, refNo);
|
||||
}
|
||||
|
||||
private SavingsAccountTransaction handlePayChargeTransactions(SavingsAccountCharge savingsAccountCharge, Money transactionAmount,
|
||||
final LocalDate transactionDate, final AppUser user, final boolean backdatedTxnsAllowedTill) {
|
||||
final LocalDate transactionDate, final AppUser user, final boolean backdatedTxnsAllowedTill, final String refNo) {
|
||||
SavingsAccountTransaction chargeTransaction = null;
|
||||
|
||||
if (savingsAccountCharge.isWithdrawalFee()) {
|
||||
chargeTransaction = SavingsAccountTransaction.withdrawalFee(this, office(), transactionDate, transactionAmount, user);
|
||||
chargeTransaction = SavingsAccountTransaction.withdrawalFee(this, office(), transactionDate, transactionAmount, user, refNo);
|
||||
} else if (savingsAccountCharge.isAnnualFee()) {
|
||||
chargeTransaction = SavingsAccountTransaction.annualFee(this, office(), transactionDate, transactionAmount, user);
|
||||
} else {
|
||||
@@ -3502,7 +3515,9 @@ public class SavingsAccount extends AbstractPersistableCustom {
|
||||
for (SavingsAccountCharge charge : this.charges()) {
|
||||
if (charge.isSavingsNoActivity() && charge.isActive()) {
|
||||
charge.updateWithdralFeeAmount(this.getAccountBalance());
|
||||
this.payCharge(charge, charge.getAmountOutstanding(this.getCurrency()), transactionDate, appUser, backdatedTxnsAllowedTill);
|
||||
UUID refNo = UUID.randomUUID();
|
||||
this.payCharge(charge, charge.getAmountOutstanding(this.getCurrency()), transactionDate, appUser, backdatedTxnsAllowedTill,
|
||||
refNo.toString());
|
||||
}
|
||||
}
|
||||
recalculateDailyBalances(Money.zero(this.currency), transactionDate, backdatedTxnsAllowedTill);
|
||||
|
||||
+2
-1
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.savings.domain;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
import org.apache.fineract.portfolio.savings.SavingsTransactionBooleanValues;
|
||||
@@ -42,7 +43,7 @@ public interface SavingsAccountDomainService {
|
||||
SavingsAccountTransaction handleDividendPayout(SavingsAccount account, LocalDate transactionDate, BigDecimal transactionAmount,
|
||||
boolean backdatedTxnsAllowedTill);
|
||||
|
||||
SavingsAccountTransaction handleReversal(SavingsAccount account, SavingsAccountTransaction savingsAccountTransaction,
|
||||
SavingsAccountTransaction handleReversal(SavingsAccount account, List<SavingsAccountTransaction> savingsAccountTransactions,
|
||||
boolean backdatedTxnsAllowedTill);
|
||||
|
||||
SavingsAccountTransaction handleHold(SavingsAccount account, AppUser createdUser, BigDecimal amount, LocalDate transactionDate,
|
||||
|
||||
+30
-23
@@ -28,6 +28,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
|
||||
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
@@ -108,14 +109,16 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
||||
Integer accountType = null;
|
||||
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
|
||||
paymentDetail, new Date(), user, accountType);
|
||||
UUID refNo = UUID.randomUUID();
|
||||
final SavingsAccountTransaction withdrawal = account.withdraw(transactionDTO, transactionBooleanValues.isApplyWithdrawFee(),
|
||||
backdatedTxnsAllowedTill);
|
||||
backdatedTxnsAllowedTill, refNo.toString());
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate, backdatedTxnsAllowedTill)) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
boolean postReversals = false;
|
||||
account.postInterest(mc, today, transactionBooleanValues.isInterestTransfer(), isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill);
|
||||
financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill, postReversals);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterestUsing(mc, today, transactionBooleanValues.isInterestTransfer(),
|
||||
@@ -195,8 +198,9 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
||||
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate, backdatedTxnsAllowedTill)) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
boolean postReversals = false;
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestOnDate, backdatedTxnsAllowedTill);
|
||||
postInterestOnDate, backdatedTxnsAllowedTill, postReversals);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
@@ -283,15 +287,12 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
||||
}
|
||||
|
||||
@Override
|
||||
public SavingsAccountTransaction handleReversal(SavingsAccount account, SavingsAccountTransaction savingsAccountTransaction,
|
||||
public SavingsAccountTransaction handleReversal(SavingsAccount account, List<SavingsAccountTransaction> savingsAccountTransactions,
|
||||
boolean backdatedTxnsAllowedTill) {
|
||||
|
||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
|
||||
.isSavingsInterestPostingAtCurrentPeriodEnd();
|
||||
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
|
||||
|
||||
final Set<SavingsAccountChargePaidBy> chargePaidBySet = savingsAccountTransaction.getSavingsAccountChargesPaid();
|
||||
|
||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||
|
||||
@@ -300,30 +301,36 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
||||
} else {
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
}
|
||||
List<SavingsAccountTransaction> newTransactions = new ArrayList<>();
|
||||
SavingsAccountTransaction reversal = null;
|
||||
|
||||
SavingsAccountTransaction reversal = SavingsAccountTransaction.reversal(savingsAccountTransaction);
|
||||
reversal.getSavingsAccountChargesPaid().addAll(chargePaidBySet);
|
||||
account.undoTransaction(savingsAccountTransaction);
|
||||
Set<SavingsAccountChargePaidBy> chargePaidBySet = null;
|
||||
for (SavingsAccountTransaction savingsAccountTransaction : savingsAccountTransactions) {
|
||||
reversal = SavingsAccountTransaction.reversal(savingsAccountTransaction);
|
||||
chargePaidBySet = savingsAccountTransaction.getSavingsAccountChargesPaid();
|
||||
reversal.getSavingsAccountChargesPaid().addAll(chargePaidBySet);
|
||||
account.undoTransaction(savingsAccountTransaction);
|
||||
newTransactions.add(reversal);
|
||||
}
|
||||
|
||||
boolean isInterestTransfer = false;
|
||||
LocalDate postInterestOnDate = null;
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
final MathContext mc = new MathContext(15, MoneyHelper.getRoundingMode());
|
||||
for (SavingsAccountTransaction savingsAccountTransaction : savingsAccountTransactions) {
|
||||
if (savingsAccountTransaction.isPostInterestCalculationRequired()
|
||||
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(), backdatedTxnsAllowedTill)) {
|
||||
boolean postReversals = true;
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestOnDate, backdatedTxnsAllowedTill, postReversals);
|
||||
} else {
|
||||
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill);
|
||||
}
|
||||
|
||||
if (savingsAccountTransaction.isPostInterestCalculationRequired()
|
||||
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(), backdatedTxnsAllowedTill)) {
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestOnDate, backdatedTxnsAllowedTill);
|
||||
} else {
|
||||
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill);
|
||||
account.validateAccountBalanceDoesNotBecomeNegativeMinimal(savingsAccountTransaction.getAmount(), false);
|
||||
account.activateAccountBasedOnBalance();
|
||||
}
|
||||
|
||||
List<SavingsAccountTransaction> newTransactions = new ArrayList<>();
|
||||
newTransactions.add(reversal);
|
||||
|
||||
account.validateAccountBalanceDoesNotBecomeNegativeMinimal(savingsAccountTransaction.getAmount(), false);
|
||||
account.activateAccountBasedOnBalance();
|
||||
this.savingsAccountRepository.save(account);
|
||||
this.savingsAccountTransactionRepository.saveAll(newTransactions);
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, false, backdatedTxnsAllowedTill);
|
||||
|
||||
+4
-2
@@ -211,7 +211,8 @@ public final class SavingsAccountSummary {
|
||||
HashMap<String, Money> map = new HashMap<>();
|
||||
for (int i = savingsAccountTransactions.size() - 1; i >= 0; i--) {
|
||||
final SavingsAccountTransaction savingsAccountTransaction = savingsAccountTransactions.get(i);
|
||||
if (savingsAccountTransaction.isInterestPostingAndNotReversed() && savingsAccountTransaction.isNotReversed() && !isUpdated) {
|
||||
if (savingsAccountTransaction.isInterestPostingAndNotReversed() && savingsAccountTransaction.isNotReversed()
|
||||
&& !savingsAccountTransaction.isReversalTransaction() && !isUpdated) {
|
||||
setRunningBalanceOnPivotDate(savingsAccountTransaction.getRunningBalance(currency).getAmount());
|
||||
setInterestPostedTillDate(savingsAccountTransaction.getLastTransactionDate());
|
||||
isUpdated = true;
|
||||
@@ -220,7 +221,8 @@ public final class SavingsAccountSummary {
|
||||
}
|
||||
}
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
if (savingsAccountTransaction.isInterestPostingAndNotReversed() && savingsAccountTransaction.isNotReversed()) {
|
||||
if (savingsAccountTransaction.isInterestPostingAndNotReversed() && savingsAccountTransaction.isNotReversed()
|
||||
&& !savingsAccountTransaction.isReversalTransaction()) {
|
||||
interestTotal = interestTotal.plus(savingsAccountTransaction.getAmount(currency));
|
||||
}
|
||||
|
||||
|
||||
+50
-25
@@ -143,6 +143,9 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
|
||||
@Column(name = "is_lien_transaction")
|
||||
private Boolean lienTransaction;
|
||||
|
||||
@Column(name = "ref_no", nullable = true)
|
||||
private String refNo;
|
||||
|
||||
SavingsAccountTransaction() {
|
||||
this.dateOf = null;
|
||||
this.typeOf = null;
|
||||
@@ -154,8 +157,9 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
|
||||
final boolean isReversed = false;
|
||||
final boolean isManualTransaction = false;
|
||||
final Boolean lienTransaction = false;
|
||||
final String refNo = null;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, SavingsAccountTransactionType.DEPOSIT.getValue(), date,
|
||||
createdDate, amount, isReversed, appUser, isManualTransaction, lienTransaction);
|
||||
createdDate, amount, isReversed, appUser, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction deposit(final SavingsAccount savingsAccount, final Office office,
|
||||
@@ -164,42 +168,46 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
|
||||
final boolean isReversed = false;
|
||||
final boolean isManualTransaction = false;
|
||||
final Boolean lienTransaction = false;
|
||||
final String refNo = null;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, savingsAccountTransactionType.getValue(), date,
|
||||
createdDate, amount, isReversed, appUser, isManualTransaction, lienTransaction);
|
||||
createdDate, amount, isReversed, appUser, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction withdrawal(final SavingsAccount savingsAccount, final Office office,
|
||||
final PaymentDetail paymentDetail, final LocalDate date, final Money amount, Date createdDate, final AppUser appUser) {
|
||||
final PaymentDetail paymentDetail, final LocalDate date, final Money amount, Date createdDate, final AppUser appUser,
|
||||
final String refNo) {
|
||||
final boolean isReversed = false;
|
||||
final boolean isManualTransaction = false;
|
||||
final Boolean lienTransaction = false;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, SavingsAccountTransactionType.WITHDRAWAL.getValue(),
|
||||
date, createdDate, amount, isReversed, appUser, isManualTransaction, lienTransaction);
|
||||
date, createdDate, amount, isReversed, appUser, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction interestPosting(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
|
||||
final Money amount, final boolean isManualTransaction) {
|
||||
final boolean isReversed = false;
|
||||
final Boolean lienTransaction = false;
|
||||
final String refNo = null;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.INTEREST_POSTING.getValue(), date,
|
||||
amount, isReversed, null, isManualTransaction, lienTransaction);
|
||||
amount, isReversed, null, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction overdraftInterest(final SavingsAccount savingsAccount, final Office office,
|
||||
final LocalDate date, final Money amount, final boolean isManualTransaction) {
|
||||
final boolean isReversed = false;
|
||||
final Boolean lienTransaction = false;
|
||||
final String refNo = null;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.OVERDRAFT_INTEREST.getValue(), date,
|
||||
amount, isReversed, null, isManualTransaction, lienTransaction);
|
||||
amount, isReversed, null, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction withdrawalFee(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
|
||||
final Money amount, final AppUser appUser) {
|
||||
final Money amount, final AppUser appUser, final String refNo) {
|
||||
final boolean isReversed = false;
|
||||
final boolean isManualTransaction = false;
|
||||
final Boolean lienTransaction = false;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.WITHDRAWAL_FEE.getValue(), date, amount,
|
||||
isReversed, appUser, isManualTransaction, lienTransaction);
|
||||
isReversed, appUser, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction annualFee(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
|
||||
@@ -207,8 +215,9 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
|
||||
final boolean isReversed = false;
|
||||
final boolean isManualTransaction = false;
|
||||
final Boolean lienTransaction = false;
|
||||
final String refNo = null;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.ANNUAL_FEE.getValue(), date, amount,
|
||||
isReversed, appUser, isManualTransaction, lienTransaction);
|
||||
isReversed, appUser, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction charge(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
|
||||
@@ -216,8 +225,9 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
|
||||
final boolean isReversed = false;
|
||||
final boolean isManualTransaction = false;
|
||||
final Boolean lienTransaction = false;
|
||||
final String refNo = null;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.PAY_CHARGE.getValue(), date, amount,
|
||||
isReversed, appUser, isManualTransaction, lienTransaction);
|
||||
isReversed, appUser, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction from(final Integer transactionTypeEnum, final LocalDate transactionDate,
|
||||
@@ -233,8 +243,9 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
|
||||
final boolean isReversed = false;
|
||||
final boolean isManualTransaction = false;
|
||||
final Boolean lienTransaction = false;
|
||||
final String refNo = null;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.WAIVE_CHARGES.getValue(), date, amount,
|
||||
isReversed, appUser, isManualTransaction, lienTransaction);
|
||||
isReversed, appUser, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction initiateTransfer(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
|
||||
@@ -243,9 +254,10 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
|
||||
final boolean isManualTransaction = false;
|
||||
final PaymentDetail paymentDetail = null;
|
||||
final Boolean lienTransaction = false;
|
||||
final String refNo = null;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail,
|
||||
SavingsAccountTransactionType.INITIATE_TRANSFER.getValue(), date, new Date(),
|
||||
savingsAccount.getSummary().getAccountBalance(), isReversed, appUser, isManualTransaction, lienTransaction);
|
||||
savingsAccount.getSummary().getAccountBalance(), isReversed, appUser, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction approveTransfer(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
|
||||
@@ -254,9 +266,10 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
|
||||
final boolean isManualTransaction = false;
|
||||
final PaymentDetail paymentDetail = null;
|
||||
final Boolean lienTransaction = false;
|
||||
final String refNo = null;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail,
|
||||
SavingsAccountTransactionType.APPROVE_TRANSFER.getValue(), date, new Date(),
|
||||
savingsAccount.getSummary().getAccountBalance(), isReversed, appUser, isManualTransaction, lienTransaction);
|
||||
savingsAccount.getSummary().getAccountBalance(), isReversed, appUser, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction withdrawTransfer(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
|
||||
@@ -265,9 +278,10 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
|
||||
final boolean isManualTransaction = false;
|
||||
final PaymentDetail paymentDetail = null;
|
||||
final Boolean lienTransaction = false;
|
||||
final String refNo = null;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail,
|
||||
SavingsAccountTransactionType.WITHDRAW_TRANSFER.getValue(), date, new Date(),
|
||||
savingsAccount.getSummary().getAccountBalance(), isReversed, appUser, isManualTransaction, lienTransaction);
|
||||
savingsAccount.getSummary().getAccountBalance(), isReversed, appUser, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction withHoldTax(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
|
||||
@@ -275,9 +289,10 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
|
||||
final boolean isReversed = false;
|
||||
final boolean isManualTransaction = false;
|
||||
final Boolean lienTransaction = false;
|
||||
final String refNo = null;
|
||||
SavingsAccountTransaction accountTransaction = new SavingsAccountTransaction(savingsAccount, office,
|
||||
SavingsAccountTransactionType.WITHHOLD_TAX.getValue(), date, amount, isReversed, null, isManualTransaction,
|
||||
lienTransaction);
|
||||
SavingsAccountTransactionType.WITHHOLD_TAX.getValue(), date, amount, isReversed, null, isManualTransaction, lienTransaction,
|
||||
refNo);
|
||||
updateTaxDetails(taxDetails, accountTransaction);
|
||||
return accountTransaction;
|
||||
}
|
||||
@@ -287,9 +302,10 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
|
||||
final boolean isReversed = false;
|
||||
final PaymentDetail paymentDetail = null;
|
||||
final Boolean lienTransaction = false;
|
||||
final String refNo = null;
|
||||
return new SavingsAccountTransaction(savingsAccount, savingsAccount.office(), paymentDetail,
|
||||
SavingsAccountTransactionType.ESCHEAT.getValue(), date, new Date(), savingsAccount.getSummary().getAccountBalance(),
|
||||
isReversed, appUser, accountTransaction, lienTransaction);
|
||||
isReversed, appUser, accountTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static void updateTaxDetails(final Map<TaxComponent, BigDecimal> taxDetails,
|
||||
@@ -306,26 +322,28 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
|
||||
return new SavingsAccountTransaction(accountTransaction.savingsAccount, accountTransaction.office, accountTransaction.paymentDetail,
|
||||
accountTransaction.typeOf, accountTransaction.transactionLocalDate(), DateUtils.getDateOfTenant(),
|
||||
accountTransaction.amount, accountTransaction.reversed, accountTransaction.appUser, accountTransaction.isManualTransaction,
|
||||
accountTransaction.lienTransaction);
|
||||
accountTransaction.lienTransaction, accountTransaction.refNo);
|
||||
}
|
||||
|
||||
private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final Integer typeOf,
|
||||
final LocalDate transactionLocalDate, final Money amount, final boolean isReversed, final AppUser appUser,
|
||||
final boolean isManualTransaction, final Boolean lienTransaction) {
|
||||
final boolean isManualTransaction, final Boolean lienTransaction, final String refNo) {
|
||||
this(savingsAccount, office, null, typeOf, transactionLocalDate, new Date(), amount, isReversed, appUser, isManualTransaction,
|
||||
lienTransaction);
|
||||
lienTransaction, refNo);
|
||||
}
|
||||
|
||||
private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final PaymentDetail paymentDetail,
|
||||
final Integer typeOf, final LocalDate transactionLocalDate, final Date createdDate, final Money amount,
|
||||
final boolean isReversed, final AppUser appUser, final boolean isManualTransaction, final Boolean lienTransaction) {
|
||||
final boolean isReversed, final AppUser appUser, final boolean isManualTransaction, final Boolean lienTransaction,
|
||||
final String refNo) {
|
||||
this(savingsAccount, office, paymentDetail, typeOf, transactionLocalDate, createdDate, amount.getAmount(), isReversed, appUser,
|
||||
isManualTransaction, lienTransaction);
|
||||
isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final PaymentDetail paymentDetail,
|
||||
final Integer typeOf, final LocalDate transactionLocalDate, final Date createdDate, final BigDecimal amount,
|
||||
final boolean isReversed, final AppUser appUser, final boolean isManualTransaction, final Boolean lienTransaction) {
|
||||
final boolean isReversed, final AppUser appUser, final boolean isManualTransaction, final Boolean lienTransaction,
|
||||
final String refNo) {
|
||||
this.savingsAccount = savingsAccount;
|
||||
this.office = office;
|
||||
this.typeOf = typeOf;
|
||||
@@ -337,6 +355,7 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
|
||||
this.appUser = appUser;
|
||||
this.isManualTransaction = isManualTransaction;
|
||||
this.lienTransaction = lienTransaction;
|
||||
this.refNo = refNo;
|
||||
}
|
||||
|
||||
private SavingsAccountTransaction(final Integer transactionTypeEnum, final LocalDate transactionDate, final BigDecimal amount,
|
||||
@@ -362,15 +381,17 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
|
||||
final Boolean lienTransaction) {
|
||||
final boolean isReversed = false;
|
||||
final boolean isManualTransaction = false;
|
||||
final String refNo = null;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, SavingsAccountTransactionType.AMOUNT_HOLD.getValue(),
|
||||
date, createdDate, amount, isReversed, appUser, isManualTransaction, lienTransaction);
|
||||
date, createdDate, amount, isReversed, appUser, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction releaseAmount(SavingsAccountTransaction accountTransaction, LocalDate transactionDate,
|
||||
Date createdDate, final AppUser appUser) {
|
||||
return new SavingsAccountTransaction(accountTransaction.savingsAccount, accountTransaction.office, accountTransaction.paymentDetail,
|
||||
SavingsAccountTransactionType.AMOUNT_RELEASE.getValue(), transactionDate, createdDate, accountTransaction.amount,
|
||||
accountTransaction.reversed, appUser, accountTransaction.isManualTransaction, accountTransaction.lienTransaction);
|
||||
accountTransaction.reversed, appUser, accountTransaction.isManualTransaction, accountTransaction.lienTransaction,
|
||||
accountTransaction.refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction reversal(SavingsAccountTransaction accountTransaction) {
|
||||
@@ -860,6 +881,10 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
|
||||
return this.dateOf;
|
||||
}
|
||||
|
||||
public String getRefNo() {
|
||||
return this.refNo;
|
||||
}
|
||||
|
||||
public PaymentDetail getPaymentDetail() {
|
||||
return this.paymentDetail;
|
||||
}
|
||||
|
||||
+2
@@ -42,4 +42,6 @@ public interface SavingsAccountTransactionRepository
|
||||
@Lock(LockModeType.PESSIMISTIC_WRITE)
|
||||
List<SavingsAccountTransaction> findBySavingsAccount(@Param("savingsAccount") SavingsAccount savingsAccount);
|
||||
|
||||
@Query("select sat from SavingsAccountTransaction sat where sat.refNo = :refNo")
|
||||
List<SavingsAccountTransaction> findAllTransactionByRefNo(@Param("refNo") String refNo);
|
||||
}
|
||||
|
||||
+21
-21
@@ -67,7 +67,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
public BigDecimal calculateTotalWithdrawals(final CurrencyData currency, final List<SavingsAccountTransactionData> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransactionData transaction : transactions) {
|
||||
if (transaction.isWithdrawal() && transaction.isNotReversed()) {
|
||||
if (transaction.isWithdrawal() && transaction.isNotReversed() && !transaction.isReversalTransaction()) {
|
||||
total = total.plus(transaction.getAmount());
|
||||
}
|
||||
}
|
||||
@@ -77,7 +77,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
public BigDecimal calculateTotalInterestPosted(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransaction transaction : transactions) {
|
||||
if (transaction.isInterestPostingAndNotReversed() && transaction.isNotReversed()) {
|
||||
if (transaction.isInterestPostingAndNotReversed() && transaction.isNotReversed() && !transaction.isReversalTransaction()) {
|
||||
total = total.plus(transaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
@@ -87,7 +87,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
public BigDecimal calculateTotalInterestPosted(final CurrencyData currency, final List<SavingsAccountTransactionData> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransactionData transaction : transactions) {
|
||||
if (transaction.isInterestPostingAndNotReversed() && transaction.isNotReversed()) {
|
||||
if (transaction.isInterestPostingAndNotReversed() && transaction.isNotReversed() && !transaction.isReversalTransaction()) {
|
||||
total = total.plus(transaction.getAmount());
|
||||
}
|
||||
}
|
||||
@@ -98,7 +98,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
final List<SavingsAccountTransaction> savingsAccountTransactions) {
|
||||
Money total = Money.of(currency, currentInterestPosted);
|
||||
for (final SavingsAccountTransaction transaction : savingsAccountTransactions) {
|
||||
if (transaction.isInterestPostingAndNotReversed() && transaction.isNotReversed()) {
|
||||
if (transaction.isInterestPostingAndNotReversed() && transaction.isNotReversed() && !transaction.isReversalTransaction()) {
|
||||
total = total.plus(transaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
@@ -108,7 +108,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
public BigDecimal calculateTotalWithdrawalFees(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransaction transaction : transactions) {
|
||||
if (transaction.isWithdrawalFeeAndNotReversed() && transaction.isNotReversed()) {
|
||||
if (transaction.isWithdrawalFeeAndNotReversed() && transaction.isNotReversed() && !transaction.isReversalTransaction()) {
|
||||
total = total.plus(transaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
@@ -118,7 +118,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
public BigDecimal calculateTotalWithdrawalFees(final CurrencyData currency, final List<SavingsAccountTransactionData> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransactionData transaction : transactions) {
|
||||
if (transaction.isWithdrawalFeeAndNotReversed() && transaction.isNotReversed()) {
|
||||
if (transaction.isWithdrawalFeeAndNotReversed() && transaction.isNotReversed() && !transaction.isReversalTransaction()) {
|
||||
total = total.plus(transaction.getAmount());
|
||||
}
|
||||
}
|
||||
@@ -128,7 +128,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
public BigDecimal calculateTotalAnnualFees(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransaction transaction : transactions) {
|
||||
if (transaction.isAnnualFeeAndNotReversed() && transaction.isNotReversed()) {
|
||||
if (transaction.isAnnualFeeAndNotReversed() && transaction.isNotReversed() && !transaction.isReversalTransaction()) {
|
||||
total = total.plus(transaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
@@ -138,7 +138,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
public BigDecimal calculateTotalAnnualFees(final CurrencyData currency, final List<SavingsAccountTransactionData> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransactionData transaction : transactions) {
|
||||
if (transaction.isAnnualFeeAndNotReversed() && transaction.isNotReversed()) {
|
||||
if (transaction.isAnnualFeeAndNotReversed() && transaction.isNotReversed() && !transaction.isReversalTransaction()) {
|
||||
total = total.plus(transaction.getAmount());
|
||||
}
|
||||
}
|
||||
@@ -148,7 +148,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
public BigDecimal calculateTotalFeesCharge(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransaction transaction : transactions) {
|
||||
if (transaction.isFeeChargeAndNotReversed()) {
|
||||
if (transaction.isFeeChargeAndNotReversed() && !transaction.isReversalTransaction()) {
|
||||
total = total.plus(transaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
@@ -158,7 +158,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
public BigDecimal calculateTotalFeesCharge(final CurrencyData currency, final List<SavingsAccountTransactionData> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransactionData transaction : transactions) {
|
||||
if (transaction.isFeeChargeAndNotReversed()) {
|
||||
if (transaction.isFeeChargeAndNotReversed() && !transaction.isReversalTransaction()) {
|
||||
total = total.plus(transaction.getAmount());
|
||||
}
|
||||
}
|
||||
@@ -168,7 +168,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
public BigDecimal calculateTotalFeesChargeWaived(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransaction transaction : transactions) {
|
||||
if (transaction.isWaiveFeeChargeAndNotReversed()) {
|
||||
if (transaction.isWaiveFeeChargeAndNotReversed() && !transaction.isReversalTransaction()) {
|
||||
total = total.plus(transaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
@@ -178,7 +178,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
public BigDecimal calculateTotalFeesChargeWaived(final CurrencyData currency, final List<SavingsAccountTransactionData> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransactionData transaction : transactions) {
|
||||
if (transaction.isWaiveFeeChargeAndNotReversed()) {
|
||||
if (transaction.isWaiveFeeChargeAndNotReversed() && !transaction.isReversalTransaction()) {
|
||||
total = total.plus(transaction.getAmount());
|
||||
}
|
||||
}
|
||||
@@ -188,7 +188,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
public BigDecimal calculateTotalPenaltyCharge(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransaction transaction : transactions) {
|
||||
if (transaction.isPenaltyChargeAndNotReversed()) {
|
||||
if (transaction.isPenaltyChargeAndNotReversed() && !transaction.isReversalTransaction()) {
|
||||
total = total.plus(transaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
@@ -198,7 +198,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
public BigDecimal calculateTotalPenaltyCharge(final CurrencyData currency, final List<SavingsAccountTransactionData> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransactionData transaction : transactions) {
|
||||
if (transaction.isPenaltyChargeAndNotReversed()) {
|
||||
if (transaction.isPenaltyChargeAndNotReversed() && !transaction.isReversalTransaction()) {
|
||||
total = total.plus(transaction.getAmount());
|
||||
}
|
||||
}
|
||||
@@ -209,7 +209,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
final List<SavingsAccountTransaction> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransaction transaction : transactions) {
|
||||
if (transaction.isWaivePenaltyChargeAndNotReversed()) {
|
||||
if (transaction.isWaivePenaltyChargeAndNotReversed() && !transaction.isReversalTransaction()) {
|
||||
total = total.plus(transaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
@@ -220,7 +220,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
final List<SavingsAccountTransactionData> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransactionData transaction : transactions) {
|
||||
if (transaction.isWaivePenaltyChargeAndNotReversed()) {
|
||||
if (transaction.isWaivePenaltyChargeAndNotReversed() && !transaction.isReversalTransaction()) {
|
||||
total = total.plus(transaction.getAmount());
|
||||
}
|
||||
}
|
||||
@@ -231,7 +231,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
List<SavingsAccountTransaction> transactions) {
|
||||
Money total = Money.of(currency, overdraftPosted);
|
||||
for (final SavingsAccountTransaction transaction : transactions) {
|
||||
if (transaction.isOverdraftInterestAndNotReversed()) {
|
||||
if (transaction.isOverdraftInterestAndNotReversed() && !transaction.isReversalTransaction()) {
|
||||
total = total.plus(transaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
@@ -241,7 +241,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
public BigDecimal calculateTotalOverdraftInterest(MonetaryCurrency currency, List<SavingsAccountTransaction> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransaction transaction : transactions) {
|
||||
if (transaction.isOverdraftInterestAndNotReversed()) {
|
||||
if (transaction.isOverdraftInterestAndNotReversed() && !transaction.isReversalTransaction()) {
|
||||
total = total.plus(transaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
@@ -251,7 +251,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
public BigDecimal calculateTotalOverdraftInterest(CurrencyData currency, List<SavingsAccountTransactionData> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransactionData transaction : transactions) {
|
||||
if (transaction.isOverdraftInterestAndNotReversed()) {
|
||||
if (transaction.isOverdraftInterestAndNotReversed() && !transaction.isReversalTransaction()) {
|
||||
total = total.plus(transaction.getAmount());
|
||||
}
|
||||
}
|
||||
@@ -261,7 +261,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
public BigDecimal calculateTotalWithholdTaxWithdrawal(MonetaryCurrency currency, List<SavingsAccountTransaction> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransaction transaction : transactions) {
|
||||
if (transaction.isWithHoldTaxAndNotReversed()) {
|
||||
if (transaction.isWithHoldTaxAndNotReversed() && !transaction.isReversalTransaction()) {
|
||||
total = total.plus(transaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
@@ -271,7 +271,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
public BigDecimal calculateTotalWithholdTaxWithdrawal(CurrencyData currency, List<SavingsAccountTransactionData> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransactionData transaction : transactions) {
|
||||
if (transaction.isWithHoldTaxAndNotReversed()) {
|
||||
if (transaction.isWithHoldTaxAndNotReversed() && !transaction.isReversalTransaction()) {
|
||||
total = total.plus(transaction.getAmount());
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -45,6 +45,6 @@ public class ReverseTransactionSavingsAccountCommandHandler implements NewComman
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
final Long transactionId = Long.valueOf(command.getTransactionId());
|
||||
return this.writePlatformService.reverseTransaction(command.getSavingsId(), transactionId, false);
|
||||
return this.writePlatformService.reverseTransaction(command.getSavingsId(), transactionId, false, command);
|
||||
}
|
||||
}
|
||||
|
||||
+11
-6
@@ -37,6 +37,7 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
|
||||
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
@@ -296,7 +297,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
for (SavingsAccountCharge savingsAccountCharge : account.charges()) {
|
||||
if (savingsAccountCharge.isSavingsActivation()) {
|
||||
account.payCharge(savingsAccountCharge, savingsAccountCharge.getAmount(account.getCurrency()),
|
||||
account.getActivationLocalDate(), user, false);
|
||||
account.getActivationLocalDate(), user, false, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -571,8 +572,9 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
final MathContext mc = new MathContext(10, MoneyHelper.getRoundingMode());
|
||||
boolean isInterestTransfer = false;
|
||||
LocalDate postInterestOnDate = null;
|
||||
boolean postReversals = false;
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestOnDate, false);
|
||||
postInterestOnDate, false, postReversals);
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(account);
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
@@ -744,6 +746,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
|
||||
SavingsAccountTransaction transaction = null;
|
||||
Integer accountType = null;
|
||||
UUID refNo = UUID.randomUUID();
|
||||
if (savingsAccountTransaction.isDeposit()) {
|
||||
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
|
||||
paymentDetail, savingsAccountTransaction.createdDate(), user, accountType);
|
||||
@@ -751,7 +754,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
} else {
|
||||
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
|
||||
paymentDetail, savingsAccountTransaction.createdDate(), user, accountType);
|
||||
transaction = account.withdraw(transactionDTO, true, false);
|
||||
transaction = account.withdraw(transactionDTO, true, false, refNo.toString());
|
||||
}
|
||||
final Long newtransactionId = saveTransactionToGenerateTransactionId(transaction);
|
||||
boolean isInterestTransfer = false;
|
||||
@@ -1218,8 +1221,9 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate(), false)) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
boolean postReversals = false;
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestOnDate, false);
|
||||
postInterestOnDate, false, postReversals);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
@@ -1351,14 +1355,15 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter, user, false);
|
||||
account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter, user, false, null);
|
||||
boolean isInterestTransfer = false;
|
||||
LocalDate postInterestOnDate = null;
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate, false)) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
boolean postReversals = false;
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestOnDate, false);
|
||||
postInterestOnDate, false, postReversals);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
|
||||
+2
-1
@@ -41,7 +41,8 @@ public interface SavingsAccountWritePlatformService {
|
||||
|
||||
CommandProcessingResult calculateInterest(Long savingsId);
|
||||
|
||||
CommandProcessingResult reverseTransaction(Long savingsId, Long transactionId, boolean allowAccountTransferModification);
|
||||
CommandProcessingResult reverseTransaction(Long savingsId, Long transactionId, boolean allowAccountTransferModification,
|
||||
JsonCommand command);
|
||||
|
||||
CommandProcessingResult undoTransaction(Long savingsId, Long transactionId, boolean allowAccountTransferModification);
|
||||
|
||||
|
||||
+30
-16
@@ -38,6 +38,7 @@ import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -46,6 +47,7 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
|
||||
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
@@ -614,9 +616,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
if (postInterestAs) {
|
||||
postInterestOnDate = transactionDate;
|
||||
}
|
||||
|
||||
boolean postReversals = false;
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestOnDate, backdatedTxnsAllowedTill);
|
||||
postInterestOnDate, backdatedTxnsAllowedTill, postReversals);
|
||||
|
||||
if (!backdatedTxnsAllowedTill) {
|
||||
List<SavingsAccountTransaction> transactions = account.getTransactions();
|
||||
@@ -685,9 +687,10 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult reverseTransaction(final Long savingsId, final Long transactionId,
|
||||
final boolean allowAccountTransferModification) {
|
||||
final boolean allowAccountTransferModification, final JsonCommand command) {
|
||||
|
||||
final boolean backdatedTxnsAllowedTill = this.savingAccountAssembler.getPivotConfigStatus();
|
||||
final boolean isBulk = command.booleanPrimitiveValueOfParameterNamed("isBulk");
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, backdatedTxnsAllowedTill);
|
||||
|
||||
final SavingsAccountTransaction savingsAccountTransaction = this.savingsAccountTransactionRepository
|
||||
@@ -707,18 +710,24 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
throw new PlatformServiceUnavailableException("error.msg.saving.account.transaction.update.not.allowed",
|
||||
"Savings account transaction:" + transactionId + " update not allowed for this savings type", transactionId);
|
||||
}
|
||||
|
||||
if (account.isNotActive()) {
|
||||
throwValidationForActiveStatus(SavingsApiConstants.undoTransactionAction);
|
||||
}
|
||||
|
||||
SavingsAccountTransaction reversal = null;
|
||||
Long reversalId = null;
|
||||
checkClientOrGroupActive(account);
|
||||
|
||||
final SavingsAccountTransaction reversal = this.savingsAccountDomainService.handleReversal(account, savingsAccountTransaction,
|
||||
backdatedTxnsAllowedTill);
|
||||
|
||||
List<SavingsAccountTransaction> savingsAccountTransactions = null;
|
||||
if (isBulk) {
|
||||
String transactionRefNo = savingsAccountTransaction.getRefNo();
|
||||
savingsAccountTransactions = this.savingsAccountTransactionRepository.findAllTransactionByRefNo(transactionRefNo);
|
||||
reversal = this.savingsAccountDomainService.handleReversal(account, savingsAccountTransactions, backdatedTxnsAllowedTill);
|
||||
} else {
|
||||
reversal = this.savingsAccountDomainService.handleReversal(account, Collections.singletonList(savingsAccountTransaction),
|
||||
backdatedTxnsAllowedTill);
|
||||
}
|
||||
reversalId = reversal.getId();
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(reversal.getId()) //
|
||||
.withEntityId(reversalId) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
.withClientId(account.clientId()) //
|
||||
.withGroupId(account.groupId()) //
|
||||
@@ -781,8 +790,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
checkClientOrGroupActive(account);
|
||||
if (savingsAccountTransaction.isPostInterestCalculationRequired()
|
||||
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(), false)) {
|
||||
boolean postReversals = false;
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestOnDate, false);
|
||||
postInterestOnDate, false, postReversals);
|
||||
} else {
|
||||
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate, false);
|
||||
@@ -875,14 +885,16 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
if (savingsAccountTransaction.isDeposit()) {
|
||||
transaction = account.deposit(transactionDTO, false);
|
||||
} else {
|
||||
transaction = account.withdraw(transactionDTO, true, false);
|
||||
UUID refNo = UUID.randomUUID();
|
||||
transaction = account.withdraw(transactionDTO, true, false, refNo.toString());
|
||||
}
|
||||
final Long newtransactionId = saveTransactionToGenerateTransactionId(transaction);
|
||||
final LocalDate postInterestOnDate = null;
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate, false)
|
||||
|| account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(), false)) {
|
||||
boolean postReversals = false;
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestOnDate, false);
|
||||
postInterestOnDate, false, postReversals);
|
||||
} else {
|
||||
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
financialYearBeginningMonth, postInterestOnDate, false);
|
||||
@@ -1312,8 +1324,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate(), backdatedTxnsAllowedTill)) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
boolean postReversals = false;
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestOnDate, backdatedTxnsAllowedTill);
|
||||
postInterestOnDate, backdatedTxnsAllowedTill, postReversals);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
@@ -1458,14 +1471,15 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
SavingsAccountTransaction chargeTransaction = account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter, user,
|
||||
backdatedTxnsAllowedTill);
|
||||
backdatedTxnsAllowedTill, null);
|
||||
boolean isInterestTransfer = false;
|
||||
LocalDate postInterestOnDate = null;
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate, backdatedTxnsAllowedTill)) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
boolean postReversals = false;
|
||||
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
|
||||
postInterestOnDate, isInterestTransfer);
|
||||
postInterestOnDate, isInterestTransfer, postReversals);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
|
||||
@@ -35,4 +35,5 @@
|
||||
<include file="parts/0013_remove_topics.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0014_remove_unused_jobs.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0015_add_business_date.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0016_changed_unique_constraint_of_ref_no.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
|
||||
<changeSet author="fineract" id="1" context="postgresql">
|
||||
<dropUniqueConstraint tableName="m_savings_account_transaction" constraintName="m_savings_account_transaction_ref_no_key"/>
|
||||
</changeSet>
|
||||
<changeSet author="fineract" id="1" context="mysql">
|
||||
<dropUniqueConstraint tableName="m_savings_account_transaction" constraintName="ref_no"/>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+84
@@ -2731,4 +2731,88 @@ public class ClientSavingsIntegrationTest {
|
||||
assertEquals(balance, summary.get("accountBalance"), "Verifying opening Balance is 500");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReversalWhenIsBulkIsTrue() {
|
||||
this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec);
|
||||
|
||||
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
|
||||
final String minBalanceForInterestCalculation = null;
|
||||
final String minRequiredBalance = "0";
|
||||
final String enforceMinRequiredBalance = "false";
|
||||
final boolean allowOverdraft = false;
|
||||
final boolean isBulk = true;
|
||||
|
||||
final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE,
|
||||
minBalanceForInterestCalculation, minRequiredBalance, enforceMinRequiredBalance, allowOverdraft);
|
||||
Assertions.assertNotNull(savingsProductID);
|
||||
|
||||
final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(clientID, savingsProductID, ACCOUNT_TYPE_INDIVIDUAL);
|
||||
Assertions.assertNotNull(savingsId);
|
||||
final Integer withdrawalChargeId = ChargesHelper.createCharges(this.requestSpec, this.responseSpec,
|
||||
ChargesHelper.getSavingsWithdrawalFeeJSON());
|
||||
Assertions.assertNotNull(withdrawalChargeId);
|
||||
|
||||
this.savingsAccountHelper.addChargesForSavings(savingsId, withdrawalChargeId, false);
|
||||
|
||||
HashMap savingsStatusHashMap = this.savingsAccountHelper.approveSavings(savingsId);
|
||||
SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap);
|
||||
|
||||
savingsStatusHashMap = this.savingsAccountHelper.activateSavings(savingsId);
|
||||
SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap);
|
||||
|
||||
Integer withdrawalTransactionId = (Integer) this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, "500",
|
||||
SavingsAccountHelper.TRANSACTION_DATE, CommonConstants.RESPONSE_RESOURCE_ID);
|
||||
HashMap summary = this.savingsAccountHelper.getSavingsSummary(savingsId);
|
||||
Float balance = Float.parseFloat("400.0");
|
||||
assertEquals(balance, summary.get("accountBalance"), "Verifying account balance is 400");
|
||||
LOG.info("------------------------When Bulk transaction is true------------------------");
|
||||
this.savingsAccountHelper.reverseSavingsAccountTransaction(savingsId, withdrawalTransactionId, isBulk);
|
||||
summary = this.savingsAccountHelper.getSavingsSummary(savingsId);
|
||||
balance = Float.parseFloat("1000.0");
|
||||
assertEquals(balance, summary.get("accountBalance"), "Verifying account balance is 1000");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReversalWhenIsBulkIsFalse() {
|
||||
this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec);
|
||||
|
||||
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
|
||||
final String minBalanceForInterestCalculation = null;
|
||||
final String minRequiredBalance = "0";
|
||||
final String enforceMinRequiredBalance = "false";
|
||||
final boolean allowOverdraft = false;
|
||||
final boolean isBulk = false;
|
||||
|
||||
final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE,
|
||||
minBalanceForInterestCalculation, minRequiredBalance, enforceMinRequiredBalance, allowOverdraft);
|
||||
Assertions.assertNotNull(savingsProductID);
|
||||
|
||||
final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(clientID, savingsProductID, ACCOUNT_TYPE_INDIVIDUAL);
|
||||
Assertions.assertNotNull(savingsId);
|
||||
final Integer withdrawalChargeId = ChargesHelper.createCharges(this.requestSpec, this.responseSpec,
|
||||
ChargesHelper.getSavingsWithdrawalFeeJSON());
|
||||
Assertions.assertNotNull(withdrawalChargeId);
|
||||
|
||||
this.savingsAccountHelper.addChargesForSavings(savingsId, withdrawalChargeId, false);
|
||||
|
||||
HashMap savingsStatusHashMap = this.savingsAccountHelper.approveSavings(savingsId);
|
||||
SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap);
|
||||
|
||||
savingsStatusHashMap = this.savingsAccountHelper.activateSavings(savingsId);
|
||||
SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap);
|
||||
|
||||
Integer withdrawalTransactionId = (Integer) this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, "500",
|
||||
SavingsAccountHelper.TRANSACTION_DATE, CommonConstants.RESPONSE_RESOURCE_ID);
|
||||
HashMap summary = this.savingsAccountHelper.getSavingsSummary(savingsId);
|
||||
Float balance = Float.parseFloat("400.0");
|
||||
assertEquals(balance, summary.get("accountBalance"), "Verifying account balance is 400");
|
||||
LOG.info("------------------------When Bulk transaction is false------------------------");
|
||||
this.savingsAccountHelper.reverseSavingsAccountTransaction(savingsId, withdrawalTransactionId, isBulk);
|
||||
summary = this.savingsAccountHelper.getSavingsSummary(savingsId);
|
||||
balance = Float.parseFloat("900.0");
|
||||
assertEquals(balance, summary.get("accountBalance"), "Verifying account balance is 900");
|
||||
}
|
||||
}
|
||||
|
||||
+18
@@ -280,6 +280,12 @@ public class SavingsAccountHelper {
|
||||
getSavingsTransactionJSON("0", LAST_TRANSACTION_DATE), CommonConstants.RESPONSE_RESOURCE_ID);
|
||||
}
|
||||
|
||||
public Integer reverseSavingsAccountTransaction(final Integer savingsId, final Integer transactionId, final boolean isBulk) {
|
||||
LOG.info("\n--------------------------------- REVERSE SAVINGS TRANSACTION --------------------------------");
|
||||
return (Integer) performSavingActions(createAdjustTransactionURL(REVERSE_TRASACTION_COMMAND, savingsId, transactionId),
|
||||
getSavingsTransactionJSON("0", LAST_TRANSACTION_DATE, isBulk), CommonConstants.RESPONSE_RESOURCE_ID);
|
||||
}
|
||||
|
||||
public void calculateInterestForSavings(final Integer savingsId) {
|
||||
LOG.info("--------------------------------- CALCULATING INTEREST FOR SAVINGS --------------------------------");
|
||||
performSavingActions(createSavingsCalculateInterestURL(CALCULATE_INTEREST_SAVINGS_COMMAND, savingsId),
|
||||
@@ -460,6 +466,18 @@ public class SavingsAccountHelper {
|
||||
return savingsAccountWithdrawalJson;
|
||||
}
|
||||
|
||||
private String getSavingsTransactionJSON(final String amount, final String transactionDate, final boolean isBulk) {
|
||||
final HashMap<String, String> map = new HashMap<>();
|
||||
map.put("locale", CommonConstants.LOCALE);
|
||||
map.put("dateFormat", CommonConstants.DATE_FORMAT);
|
||||
map.put("transactionDate", transactionDate);
|
||||
map.put("transactionAmount", amount);
|
||||
map.put("isBulk", String.valueOf(isBulk));
|
||||
String savingsAccountWithdrawalJson = new Gson().toJson(map);
|
||||
LOG.info(savingsAccountWithdrawalJson);
|
||||
return savingsAccountWithdrawalJson;
|
||||
}
|
||||
|
||||
private String getLienSavingsTransactionJSON(final String amount, final String transactionDate, final Boolean lienAllowed) {
|
||||
final HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("locale", CommonConstants.LOCALE);
|
||||
|
||||
Reference in New Issue
Block a user