added support for undo savings fees
This commit is contained in:
+4
@@ -63,4 +63,8 @@ public class DateUtils {
|
||||
final String formattedSqlDate = df.format(date);
|
||||
return formattedSqlDate;
|
||||
}
|
||||
|
||||
public static boolean isInFuture(final LocalDate date){
|
||||
return date.isAfter(getLocalDateOfTenant());
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -19,7 +19,7 @@ public enum SavingsAccountTransactionType {
|
||||
INTEREST_POSTING(3, "savingsAccountTransactionType.interestPosting"), //
|
||||
WITHDRAWAL_FEE(4, "savingsAccountTransactionType.withdrawalFee"), //
|
||||
ANNUAL_FEE(5, "savingsAccountTransactionType.annualFee"), //
|
||||
WAIVE_CHARGES(6, "savingsAccountTransactionType.waiveCharges"), //
|
||||
WAIVE_CHARGES(6, "savingsAccountTransactionType.waiveCharge"), //
|
||||
PAY_CHARGE(7, "savingsAccountTransactionType.payCharge"), //
|
||||
INITIATE_TRANSFER(12, "savingsAccountTransactionType.initiateTransfer"), //
|
||||
APPROVE_TRANSFER(13, "savingsAccountTransactionType.approveTransfer"), //
|
||||
|
||||
+1
@@ -34,6 +34,7 @@ public class SavingsApiConstants {
|
||||
public static String adjustTransactionAction = ".adjusttransaction";
|
||||
public static String closeAction = ".close";
|
||||
public static String payChargeTransactionAction = ".paycharge";
|
||||
public static String waiveChargeTransactionAction = ".waivecharge";
|
||||
|
||||
// command
|
||||
public static String COMMAND_UNDO_TRANSACTION = "undo";
|
||||
|
||||
+73
-76
@@ -8,13 +8,13 @@ package org.mifosplatform.portfolio.savings.domain;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.annualFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.annualFeeOnMonthDayParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.dueAsOfDateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.localeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.dueAsOfDateParamName;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
@@ -1497,15 +1497,18 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
.withMonthOfYear(this.annualFeeOnMonth).withDayOfMonth(this.annualFeeOnDay).plusYears(1);
|
||||
this.annualFeeNextDueDate = newAnnualFeeNextDueDate.toDate();
|
||||
}
|
||||
} else if (transactionToUndo.isCharge()) {
|
||||
} else if (transactionToUndo.isCharge() || transactionToUndo.isWaiveCharge()) {
|
||||
// undo charge
|
||||
final Set<SavingsAccountChargePaidBy> chargesPaidBy = transactionToUndo.getSavingsAccountChargesPaid();
|
||||
for (final SavingsAccountChargePaidBy savingsAccountChargePaidBy : chargesPaidBy) {
|
||||
final SavingsAccountCharge chargeToUndo = savingsAccountChargePaidBy.getSavingsAccountCharge();
|
||||
chargeToUndo.resetPaidAmount(this.currency);
|
||||
if(transactionToUndo.isCharge()){
|
||||
chargeToUndo.undoPayment(this.getCurrency(), transactionToUndo.getAmount(this.getCurrency()));
|
||||
}else if (transactionToUndo.isWaiveCharge()){
|
||||
chargeToUndo.undoWaiver(this.getCurrency(), transactionToUndo.getAmount(this.getCurrency()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1899,6 +1902,20 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
public void removeCharge(final SavingsAccountCharge charge) {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
if (isClosed()) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("delete.transaction.invalid.account.is.closed");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
if (isActive() || isApproved()) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("delete.transaction.invalid.account.is.active");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
this.charges.remove(charge);
|
||||
}
|
||||
|
||||
@@ -1936,15 +1953,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
// waive charge
|
||||
final Money amountWaived = savingsAccountCharge.waive(getCurrency());
|
||||
|
||||
// persist an entry in transaction details
|
||||
final SavingsAccountTransaction chargeTransaction = SavingsAccountTransaction.charge(this, office(),
|
||||
savingsAccountCharge.getDueLocalDate(), amountWaived);
|
||||
|
||||
this.transactions.add(chargeTransaction);
|
||||
|
||||
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
calculateInterestUsing(mc, savingsAccountCharge.getDueLocalDate());
|
||||
handleWaiverChargeTransactions(savingsAccountCharge, amountWaived);
|
||||
}
|
||||
|
||||
public void addCharge(final DateTimeFormatter formatter, final SavingsAccountCharge savingsAccountCharge, final Charge chargeDefinition) {
|
||||
@@ -1966,10 +1975,16 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
|
||||
final LocalDate chargeDueDate = savingsAccountCharge.getDueLocalDate();
|
||||
|
||||
if (chargeDueDate != null && chargeDueDate.isBefore(getActivationLocalDate())) {
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(getActivationLocalDate().toString(formatter))
|
||||
.failWithCodeNoParameterAddedToErrorCode("before.activationDate");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
if (savingsAccountCharge.isOnSpecifiedDueDate()){
|
||||
if(getActivationLocalDate() != null && chargeDueDate.isBefore(getActivationLocalDate())){
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(getActivationLocalDate().toString(formatter))
|
||||
.failWithCodeNoParameterAddedToErrorCode("before.activationDate");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}else if(getSubmittedOnLocalDate() != null && chargeDueDate.isBefore(getSubmittedOnLocalDate())){
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(getSubmittedOnLocalDate().toString(formatter))
|
||||
.failWithCodeNoParameterAddedToErrorCode("before.submittedOnDate");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
validateActivityNotBeforeClientOrGroupTransferDate(SavingsEvent.SAVINGS_APPLY_CHARGE, chargeDueDate);
|
||||
@@ -1979,7 +1994,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
|
||||
}
|
||||
|
||||
public void payCharge(final Long savingsAccountChargeId, final BigDecimal amountPaid, final LocalDate transactionDate,
|
||||
public void payCharge(final SavingsAccountCharge savingsAccountCharge, final BigDecimal amountPaid, final LocalDate transactionDate,
|
||||
final DateTimeFormatter formatter, final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds) {
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
@@ -1996,13 +2011,23 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
if (transactionDate != null && transactionDate.isBefore(getActivationLocalDate())) {
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(getActivationLocalDate().toString(formatter))
|
||||
.failWithCodeNoParameterAddedToErrorCode("before.activationDate");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
if (savingsAccountCharge.isOnSpecifiedDueDate()){
|
||||
if(getActivationLocalDate() != null && transactionDate.isBefore(getActivationLocalDate())){
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(getActivationLocalDate().toString(formatter))
|
||||
.failWithCodeNoParameterAddedToErrorCode("transaction.before.activationDate");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}else if(getSubmittedOnLocalDate() != null && transactionDate.isBefore(getSubmittedOnLocalDate())){
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(getSubmittedOnLocalDate().toString(formatter))
|
||||
.failWithCodeNoParameterAddedToErrorCode("transaction.before.submittedOnDate");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
final SavingsAccountCharge savingsAccountCharge = getCharge(savingsAccountChargeId);
|
||||
if (DateUtils.isInFuture(transactionDate)){
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(getSubmittedOnLocalDate().toString(formatter))
|
||||
.failWithCodeNoParameterAddedToErrorCode("transaction.is.futureDate");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
|
||||
// validate charge is not already paid or waived
|
||||
if (savingsAccountCharge.isWaived()) {
|
||||
@@ -2012,9 +2037,9 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.charge.is.paid");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
|
||||
final Money amountPaidMoney = Money.of(currency, amountPaid);
|
||||
if (!savingsAccountCharge.getAmountOutstanding(getCurrency()).isGreaterThanOrEqualTo(amountPaidMoney)){
|
||||
if (!savingsAccountCharge.getAmountOutstanding(getCurrency()).isGreaterThanOrEqualTo(amountPaidMoney)) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.charge.amount.paid.in.access");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
@@ -2022,61 +2047,33 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||
|
||||
final Money chargePaid = savingsAccountCharge.pay(getCurrency(), amountPaidMoney);
|
||||
|
||||
// persist transaction details
|
||||
final SavingsAccountTransaction chargeTransaction = SavingsAccountTransaction.charge(this, office(), transactionDate, chargePaid);
|
||||
|
||||
final SavingsAccountChargePaidBy chargePaidBy = SavingsAccountChargePaidBy.instance(chargeTransaction, savingsAccountCharge,
|
||||
amountPaid);
|
||||
chargeTransaction.getSavingsAccountChargesPaid().add(chargePaidBy);
|
||||
this.transactions.add(chargeTransaction);
|
||||
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
if (isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
postInterest(mc, today, existingTransactionIds, existingReversedTransactionIds);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
calculateInterestUsing(mc, today);
|
||||
}
|
||||
|
||||
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
||||
|
||||
validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.payChargeTransactionAction);
|
||||
savingsAccountCharge.pay(getCurrency(), amountPaidMoney);
|
||||
|
||||
handlePayChargeTransactions(savingsAccountCharge, amountPaidMoney, transactionDate);
|
||||
}
|
||||
|
||||
public void payDueCharge(final SavingsAccountCharge savingsAccountCharge, final LocalDate transactionDate, final List<Long> existingTransactionIds,
|
||||
final List<Long> existingReversedTransactionIds) {
|
||||
|
||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||
final Money amountPaid = savingsAccountCharge.payDueCharge(getCurrency());
|
||||
|
||||
// persist transaction details
|
||||
final SavingsAccountTransaction chargeTransaction = SavingsAccountTransaction.charge(this, office(), transactionDate, amountPaid);
|
||||
|
||||
final SavingsAccountChargePaidBy chargePaidBy = SavingsAccountChargePaidBy.instance(chargeTransaction, savingsAccountCharge,
|
||||
amountPaid.getAmount());
|
||||
|
||||
chargeTransaction.getSavingsAccountChargesPaid().add(chargePaidBy);
|
||||
|
||||
this.transactions.add(chargeTransaction);
|
||||
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
if (isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
postInterest(mc, today, existingTransactionIds, existingReversedTransactionIds);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
calculateInterestUsing(mc, today);
|
||||
}
|
||||
|
||||
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
||||
validateAccountBalanceDoesNotBecomeNegative(amountPaid.getAmount());
|
||||
private void handlePayChargeTransactions(SavingsAccountCharge savingsAccountCharge, Money transactionAmount,
|
||||
final LocalDate transactionDate) {
|
||||
final SavingsAccountTransaction chargeTransaction = SavingsAccountTransaction.charge(this, office(), transactionDate,
|
||||
transactionAmount);
|
||||
handleChargeTransactions(savingsAccountCharge, chargeTransaction);
|
||||
}
|
||||
|
||||
|
||||
private void handleWaiverChargeTransactions(SavingsAccountCharge savingsAccountCharge, Money transactionAmount) {
|
||||
final SavingsAccountTransaction chargeTransaction = SavingsAccountTransaction.waiver(this, office(),
|
||||
DateUtils.getLocalDateOfTenant(), transactionAmount);
|
||||
handleChargeTransactions(savingsAccountCharge, chargeTransaction);
|
||||
}
|
||||
|
||||
private void handleChargeTransactions(final SavingsAccountCharge savingsAccountCharge, final SavingsAccountTransaction transaction) {
|
||||
// Provide a link between transaction and savings charge for which
|
||||
// amount is waived.
|
||||
final SavingsAccountChargePaidBy chargePaidBy = SavingsAccountChargePaidBy.instance(transaction, savingsAccountCharge, transaction
|
||||
.getAmount(this.getCurrency()).getAmount());
|
||||
transaction.getSavingsAccountChargesPaid().add(chargePaidBy);
|
||||
this.getTransactions().add(transaction);
|
||||
}
|
||||
|
||||
private SavingsAccountCharge getCharge(final Long savingsAccountChargeId) {
|
||||
SavingsAccountCharge charge = null;
|
||||
for (final SavingsAccountCharge existingCharge : this.charges) {
|
||||
|
||||
+17
-17
@@ -214,8 +214,10 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
|
||||
this.waived = false;
|
||||
}
|
||||
|
||||
public void resetPaidAmount(final MonetaryCurrency currency) {
|
||||
this.amountPaid = BigDecimal.ZERO;
|
||||
public void undoPayment(final MonetaryCurrency currency, final Money transactionAmount) {
|
||||
Money amountPaid = getAmountPaid(currency);
|
||||
amountPaid = amountPaid.minus(transactionAmount);
|
||||
this.amountPaid = amountPaid.getAmount();
|
||||
this.amountOutstanding = calculateAmountOutstanding(currency);
|
||||
this.paid = false;
|
||||
}
|
||||
@@ -223,10 +225,17 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
|
||||
public Money waive(final MonetaryCurrency currency) {
|
||||
this.amountWaived = this.amountOutstanding;
|
||||
this.amountOutstanding = BigDecimal.ZERO;
|
||||
this.paid = false;
|
||||
this.waived = true;
|
||||
return getAmountWaived(currency);
|
||||
}
|
||||
|
||||
public void undoWaiver(final MonetaryCurrency currency, final Money transactionAmount) {
|
||||
Money amountWaived = getAmountWaived(currency);
|
||||
amountWaived = amountWaived.minus(transactionAmount);
|
||||
this.amountWaived = amountWaived.getAmount();
|
||||
this.amountOutstanding = calculateAmountOutstanding(currency);
|
||||
this.waived = false;
|
||||
}
|
||||
|
||||
public Money pay(final MonetaryCurrency currency, final Money amountPaid) {
|
||||
|
||||
@@ -237,20 +246,7 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
|
||||
this.amountPaid = amountPaidToDate.getAmount();
|
||||
this.amountOutstanding = amountOutstanding.getAmount();
|
||||
this.paid = determineIfFullyPaid();
|
||||
return amountPaid;
|
||||
}
|
||||
|
||||
public Money payDueCharge(final MonetaryCurrency currency) {
|
||||
|
||||
Money amountPaidToDate = Money.of(currency, this.amountPaid);
|
||||
Money amountOutstanding = Money.of(currency, this.amountOutstanding);
|
||||
final Money amountPaid = Money.of(currency, this.amountOutstanding);;
|
||||
amountPaidToDate = amountPaidToDate.plus(amountPaid);
|
||||
amountOutstanding = amountOutstanding.minus(amountPaid);
|
||||
this.amountPaid = amountPaidToDate.getAmount();
|
||||
this.amountOutstanding = amountOutstanding.getAmount();
|
||||
this.paid = determineIfFullyPaid();
|
||||
return amountPaid;
|
||||
return amountOutstanding;
|
||||
}
|
||||
|
||||
private BigDecimal calculateAmountOutstanding(final MonetaryCurrency currency) {
|
||||
@@ -409,6 +405,10 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
|
||||
public BigDecimal amount() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
public BigDecimal amoutOutstanding(){
|
||||
return this.amountOutstanding;
|
||||
}
|
||||
|
||||
public boolean isFeeCharge() {
|
||||
return !this.penaltyCharge;
|
||||
|
||||
+1
-1
@@ -18,6 +18,6 @@ public interface SavingsAccountChargeRepository extends JpaRepository<SavingsAcc
|
||||
|
||||
SavingsAccountCharge findByIdAndSavingsAccountId(Long id, Long savingsAccountId);
|
||||
|
||||
@Query("from SavingsAccountCharge sac where sac.dueDate <=:transactionDate and sac.waived = 0 and sac.paid=0")
|
||||
@Query("from SavingsAccountCharge sac where sac.dueDate <=:transactionDate and sac.waived = 0 and sac.paid=0 order by sac.dueDate")
|
||||
List<SavingsAccountCharge> findPendingCharges(@Param("transactionDate") Date transactionDate);
|
||||
}
|
||||
|
||||
-1
@@ -5,7 +5,6 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.savings.domain;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
+4
@@ -210,6 +210,10 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
return SavingsAccountTransactionType.fromInt(this.typeOf).isWithdrawal();
|
||||
}
|
||||
|
||||
public boolean isPostInterestCalculationRequired(){
|
||||
return this.isDeposit() || this.isWithdrawal() || this.isCharge();
|
||||
}
|
||||
|
||||
public boolean isInterestPostingAndNotReversed() {
|
||||
return SavingsAccountTransactionType.fromInt(this.typeOf).isInterestPosting() && isNotReversed();
|
||||
}
|
||||
|
||||
+1
-1
@@ -52,5 +52,5 @@ public interface SavingsAccountWritePlatformService {
|
||||
|
||||
CommandProcessingResult payCharge(Long savingsAccountId, Long savingsAccountChargeId, JsonCommand command);
|
||||
|
||||
void payDueCharges();
|
||||
void processDueCharges();
|
||||
}
|
||||
+74
-54
@@ -353,7 +353,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
}
|
||||
account.undoTransaction(transactionId, reversedTransactionIds);
|
||||
checkClientOrGroupActive(account);
|
||||
if ((savingsAccountTransaction.isDeposit() || savingsAccountTransaction.isWithdrawal())
|
||||
if (savingsAccountTransaction.isPostInterestCalculationRequired()
|
||||
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate())) {
|
||||
account.postInterest(mc, today, newTransactionIds, reversedTransactionIds);
|
||||
} else {
|
||||
@@ -606,7 +606,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsAccountId);
|
||||
checkClientOrGroupActive(savingsAccount);
|
||||
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern("dd MM yyyy");
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
|
||||
final Long chargeDefinitionId = command.longValueOfParameterNamed(chargeIdParamName);
|
||||
final Charge chargeDefinition = this.chargeRepository.findOneWithNotFoundDetection(chargeDefinitionId);
|
||||
@@ -635,12 +636,11 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
this.savingAccountRepository.saveAndFlush(savingsAccount);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(savingsAccountCharge.getId()) //
|
||||
.withOfficeId(savingsAccount.officeId()) //
|
||||
.withClientId(savingsAccount.clientId()) //
|
||||
.withGroupId(savingsAccount.groupId()) //
|
||||
.withLoanId(savingsAccountId) //
|
||||
.withSavingsId(savingsAccountId) //
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -688,11 +688,11 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
this.savingsAccountChargeRepository.saveAndFlush(savingsAccountCharge);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(savingsChargeId) //
|
||||
// .withOfficeId(savings) //
|
||||
// .withClientId(loan.getClientId()) //
|
||||
// .withGroupId(loan.getGroupId()) //
|
||||
// .withLoanId(savingsAccountId) //
|
||||
.withEntityId(savingsAccountCharge.getId()) //
|
||||
.withOfficeId(savingsAccountCharge.savingsAccount().officeId()) //
|
||||
.withClientId(savingsAccountCharge.savingsAccount().clientId()) //
|
||||
.withGroupId(savingsAccountCharge.savingsAccount().groupId()) //
|
||||
.withSavingsId(savingsAccountCharge.savingsAccount().getId()) //
|
||||
.with(changes) //
|
||||
.build();
|
||||
}
|
||||
@@ -702,22 +702,37 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
public CommandProcessingResult waiveCharge(final Long savingsAccountId, final Long savingsAccountChargeId) {
|
||||
|
||||
this.context.authenticatedUser();
|
||||
|
||||
|
||||
final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection(
|
||||
savingsAccountChargeId, savingsAccountId);
|
||||
|
||||
// Get Savings account from savings charge
|
||||
final SavingsAccount account = savingsAccountCharge.savingsAccount();
|
||||
this.savingAccountAssembler.assignSavingAccountHelpers(account);
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsAccountId);
|
||||
checkClientOrGroupActive(savingsAccount);
|
||||
account.waiveCharge(savingsAccountChargeId, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
savingsAccount.waiveCharge(savingsAccountChargeId, existingTransactionIds, existingReversedTransactionIds);
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.postInterest(mc, today, existingTransactionIds, existingReversedTransactionIds);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterestUsing(mc, today);
|
||||
}
|
||||
|
||||
this.savingAccountRepository.saveAndFlush(savingsAccount);
|
||||
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.waiveChargeTransactionAction);
|
||||
|
||||
this.savingAccountRepository.saveAndFlush(account);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(savingsAccountChargeId) //
|
||||
.withOfficeId(savingsAccount.officeId()) //
|
||||
.withClientId(savingsAccount.clientId()) //
|
||||
.withGroupId(savingsAccount.groupId()) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
.withClientId(account.clientId()) //
|
||||
.withGroupId(account.groupId()) //
|
||||
.withSavingsId(savingsAccountId) //
|
||||
.build();
|
||||
}
|
||||
@@ -733,8 +748,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection(
|
||||
savingsAccountChargeId, savingsAccountId);
|
||||
|
||||
// TODO AA: validate before deleting a charge
|
||||
|
||||
savingsAccount.removeCharge(savingsAccountCharge);
|
||||
this.savingAccountRepository.saveAndFlush(savingsAccount);
|
||||
|
||||
@@ -747,31 +760,25 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
.build();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult payCharge(final Long savingsAccountId, final Long savingsAccountChargeId, final JsonCommand command) {
|
||||
|
||||
this.context.authenticatedUser();
|
||||
this.savingsAccountChargeDataValidator.validatePayCharge(command.json());
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsAccountId);
|
||||
checkClientOrGroupActive(savingsAccount);
|
||||
|
||||
final BigDecimal chargeAmount = command.bigDecimalValueOfParameterNamed(amountParamName);
|
||||
final BigDecimal amountPaid = command.bigDecimalValueOfParameterNamed(amountParamName);
|
||||
final LocalDate transactionDate = command.localDateValueOfParameterNamed(dueAsOfDateParamName);
|
||||
|
||||
final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection(
|
||||
savingsAccountChargeId, savingsAccountId);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
//transaction date should not be on a holiday or non working day
|
||||
if (!this.holidayWritePlatformService.isTransactionAllowedOnHoliday()
|
||||
&& this.holidayWritePlatformService.isHoliday(savingsAccount.officeId(), transactionDate)) {
|
||||
&& this.holidayWritePlatformService.isHoliday(savingsAccountCharge.savingsAccount().officeId(), transactionDate)) {
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(transactionDate.toString(fmt))
|
||||
.failWithCodeNoParameterAddedToErrorCode("transaction.not.allowed.transaction.date.is.on.holiday");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
@@ -783,50 +790,63 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
.failWithCodeNoParameterAddedToErrorCode("transaction.not.allowed.transaction.date.is.a.nonworking.day");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
savingsAccount.payCharge(savingsAccountChargeId, chargeAmount, transactionDate, fmt, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
this.savingAccountRepository.saveAndFlush(savingsAccount);
|
||||
|
||||
postJournalEntries(savingsAccount, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
this.payCharge(savingsAccountCharge, transactionDate, amountPaid, fmt);
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(savingsAccountChargeId) //
|
||||
.withOfficeId(savingsAccount.officeId()) //
|
||||
.withClientId(savingsAccount.clientId()) //
|
||||
.withGroupId(savingsAccount.groupId()) //
|
||||
.withSavingsId(savingsAccountId) //
|
||||
.withEntityId(savingsAccountCharge.getId()) //
|
||||
.withOfficeId(savingsAccountCharge.savingsAccount().officeId()) //
|
||||
.withClientId(savingsAccountCharge.savingsAccount().clientId()) //
|
||||
.withGroupId(savingsAccountCharge.savingsAccount().groupId()) //
|
||||
.withSavingsId(savingsAccountCharge.savingsAccount().getId()) //
|
||||
.build();
|
||||
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
@CronTarget(jobName = JobName.PAY_DUE_SAVINGS_CHARGES)
|
||||
public void payDueCharges() {
|
||||
public void processDueCharges() {
|
||||
//always use current date as transaction date for batch job
|
||||
final LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
|
||||
final List<SavingsAccountCharge> pendingCharges = this.savingsAccountChargeRepository.findPendingCharges(transactionDate.toDate());
|
||||
final List<SavingsAccountCharge> paidCharges = new ArrayList<SavingsAccountCharge>(pendingCharges.size());
|
||||
//final List<SavingsAccountCharge> paidCharges = new ArrayList<SavingsAccountCharge>(pendingCharges.size());
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern("dd MM yyyy");
|
||||
for (SavingsAccountCharge savingsAccountCharge : pendingCharges) {
|
||||
// Get Savings account from savings charge
|
||||
final SavingsAccount account = savingsAccountCharge.savingsAccount();
|
||||
this.savingAccountAssembler.assignSavingAccountHelpers(account);
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
|
||||
try {
|
||||
account.payDueCharge(savingsAccountCharge, transactionDate, existingTransactionIds, existingReversedTransactionIds);
|
||||
paidCharges.add(savingsAccountCharge);
|
||||
payCharge(savingsAccountCharge, transactionDate, savingsAccountCharge.amoutOutstanding(), fmt);
|
||||
} catch (InsufficientAccountBalanceException isab) {
|
||||
// TODO: AA - provide a meaningful error with failed
|
||||
// transactions list
|
||||
}
|
||||
}
|
||||
|
||||
this.savingsAccountChargeRepository.save(paidCharges);
|
||||
// this.savingsAccountChargeRepository.save(paidCharges);
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
private void payCharge(final SavingsAccountCharge savingsAccountCharge, final LocalDate transactionDate, final BigDecimal amountPaid,
|
||||
final DateTimeFormatter formatter) {
|
||||
// Get Savings account from savings charge
|
||||
final SavingsAccount account = savingsAccountCharge.savingsAccount();
|
||||
this.savingAccountAssembler.assignSavingAccountHelpers(account);
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter, existingTransactionIds,
|
||||
existingReversedTransactionIds);
|
||||
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.postInterest(mc, today, existingTransactionIds, existingReversedTransactionIds);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterestUsing(mc, today);
|
||||
}
|
||||
|
||||
account.validateAccountBalanceDoesNotBecomeNegative(amountPaid);
|
||||
|
||||
this.savingAccountRepository.save(account);
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user