Merge pull request #2372 from logoutdhaval/fineract-1642

FINERACT-1642: Bulk reversal of related Transactions
This commit is contained in:
Manoj
2022-06-24 21:58:01 +05:30
committed by GitHub
20 changed files with 353 additions and 125 deletions
@@ -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) {
@@ -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;
}
}
@@ -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);
}
}
@@ -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
@@ -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
@@ -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);
@@ -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,
@@ -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);
@@ -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));
}
@@ -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;
}
@@ -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);
}
@@ -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());
}
}
@@ -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);
}
}
@@ -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,
@@ -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);
@@ -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>
@@ -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>
@@ -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");
}
}
@@ -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);