Merge branch 'MIFOSX-1628' of git://github.com/binnygopinath/mifosx into binnygopinath-MIFOSX-1628

This commit is contained in:
Vishwas Babu A J
2014-11-20 06:09:17 +05:30
21 changed files with 1907 additions and 1287 deletions
@@ -14,6 +14,7 @@ import java.util.List;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatter;
import org.mifosplatform.infrastructure.core.data.ApiParameterError; import org.mifosplatform.infrastructure.core.data.ApiParameterError;
@@ -41,6 +42,23 @@ public class DateUtils {
return today; return today;
} }
public static LocalDateTime getLocalDateTimeOfTenant() {
LocalDateTime today = new LocalDateTime();
final MifosPlatformTenant tenant = ThreadLocalContextUtil.getTenant();
if (tenant != null) {
final DateTimeZone zone = DateTimeZone.forID(tenant.getTimezoneId());
if (zone != null) {
today = new LocalDateTime(zone);
}
}
return today;
}
public static LocalDate parseLocalDate(final String stringDate, final String pattern) { public static LocalDate parseLocalDate(final String stringDate, final String pattern) {
@@ -142,7 +142,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
final boolean isRecoveryRepayment = false; final boolean isRecoveryRepayment = false;
final LoanTransaction loanRepaymentTransaction = this.loanAccountDomainService.makeRepayment(toLoanAccount, final LoanTransaction loanRepaymentTransaction = this.loanAccountDomainService.makeRepayment(toLoanAccount,
new CommandProcessingResultBuilder(), transactionDate, transactionAmount, paymentDetail, null, null, new CommandProcessingResultBuilder(), transactionDate, transactionAmount, paymentDetail, null, null,
isRecoveryRepayment, isAccountTransfer); isRecoveryRepayment, isAccountTransfer, null); // FIXME: should not be sending null for currentUser for account transfers
final AccountTransferDetails accountTransferDetails = this.accountTransferAssembler.assembleSavingsToLoanTransfer(command, final AccountTransferDetails accountTransferDetails = this.accountTransferAssembler.assembleSavingsToLoanTransfer(command,
fromSavingsAccount, toLoanAccount, withdrawal, loanRepaymentTransaction); fromSavingsAccount, toLoanAccount, withdrawal, loanRepaymentTransaction);
@@ -157,7 +157,8 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
final Loan fromLoanAccount = this.loanAccountAssembler.assembleFrom(fromLoanAccountId); final Loan fromLoanAccount = this.loanAccountAssembler.assembleFrom(fromLoanAccountId);
final LoanTransaction loanRefundTransaction = this.loanAccountDomainService.makeRefund(fromLoanAccountId, final LoanTransaction loanRefundTransaction = this.loanAccountDomainService.makeRefund(fromLoanAccountId,
new CommandProcessingResultBuilder(), transactionDate, transactionAmount, paymentDetail, null, null); new CommandProcessingResultBuilder(), transactionDate, transactionAmount, paymentDetail, null, null,
null); // FIXME: should not be sending null for currentUser for account transfers
final Long toSavingsAccountId = command.longValueOfParameterNamed(toAccountIdParamName); final Long toSavingsAccountId = command.longValueOfParameterNamed(toAccountIdParamName);
final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsAccountId); final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsAccountId);
@@ -271,13 +272,14 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
loanTransaction = this.loanAccountDomainService.makeChargePayment(toLoanAccount, accountTransferDTO.getChargeId(), loanTransaction = this.loanAccountDomainService.makeChargePayment(toLoanAccount, accountTransferDTO.getChargeId(),
accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(),
accountTransferDTO.getPaymentDetail(), null, null, accountTransferDTO.getToTransferType(), accountTransferDTO.getPaymentDetail(), null, null, accountTransferDTO.getToTransferType(),
accountTransferDTO.getLoanInstallmentNumber()); accountTransferDTO.getLoanInstallmentNumber(), null); // FIXME: should not be sending null for currentUser for account transfers
} else { } else {
final boolean isRecoveryRepayment = false; final boolean isRecoveryRepayment = false;
loanTransaction = this.loanAccountDomainService.makeRepayment(toLoanAccount, new CommandProcessingResultBuilder(), loanTransaction = this.loanAccountDomainService.makeRepayment(toLoanAccount, new CommandProcessingResultBuilder(),
accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(),
accountTransferDTO.getPaymentDetail(), null, null, isRecoveryRepayment, isAccountTransfer); accountTransferDTO.getPaymentDetail(), null, null, isRecoveryRepayment, isAccountTransfer,
null); // FIXME: should not be sending null for currentUser for account transfers
} }
accountTransferDetails = this.accountTransferAssembler.assembleSavingsToLoanTransfer(accountTransferDTO, fromSavingsAccount, accountTransferDetails = this.accountTransferAssembler.assembleSavingsToLoanTransfer(accountTransferDTO, fromSavingsAccount,
@@ -344,12 +346,13 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
if (LoanTransactionType.DISBURSEMENT.getValue().equals(accountTransferDTO.getFromTransferType())) { if (LoanTransactionType.DISBURSEMENT.getValue().equals(accountTransferDTO.getFromTransferType())) {
loanTransaction = this.loanAccountDomainService.makeDisburseTransaction(accountTransferDTO.getFromAccountId(), loanTransaction = this.loanAccountDomainService.makeDisburseTransaction(accountTransferDTO.getFromAccountId(),
accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(),
accountTransferDTO.getPaymentDetail(), accountTransferDTO.getNoteText(), accountTransferDTO.getTxnExternalId()); accountTransferDTO.getPaymentDetail(), accountTransferDTO.getNoteText(), accountTransferDTO.getTxnExternalId(),
null); // FIXME: should not be sending null for currentUser for account transfers
} else { } else {
loanTransaction = this.loanAccountDomainService.makeRefund(accountTransferDTO.getFromAccountId(), loanTransaction = this.loanAccountDomainService.makeRefund(accountTransferDTO.getFromAccountId(),
new CommandProcessingResultBuilder(), accountTransferDTO.getTransactionDate(), new CommandProcessingResultBuilder(), accountTransferDTO.getTransactionDate(),
accountTransferDTO.getTransactionAmount(), accountTransferDTO.getPaymentDetail(), accountTransferDTO.getNoteText(), accountTransferDTO.getTransactionAmount(), accountTransferDTO.getPaymentDetail(), accountTransferDTO.getNoteText(),
accountTransferDTO.getTxnExternalId()); accountTransferDTO.getTxnExternalId(), null); // FIXME: should not be sending null for currentUser for account transfers
} }
final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount, final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount,
@@ -41,6 +41,7 @@ import org.apache.commons.lang.StringUtils;
import org.hibernate.annotations.LazyCollection; import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption; import org.hibernate.annotations.LazyCollectionOption;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatter;
import org.mifosplatform.infrastructure.codes.domain.CodeValue; import org.mifosplatform.infrastructure.codes.domain.CodeValue;
@@ -584,7 +585,8 @@ public class Loan extends AbstractPersistable<Long> {
* @param suppliedTransactionDate * @param suppliedTransactionDate
* @return * @return
*/ */
public LoanTransaction handleChargeAppliedTransaction(final LoanCharge loanCharge, final LocalDate suppliedTransactionDate) { public LoanTransaction handleChargeAppliedTransaction(final LoanCharge loanCharge, final LocalDate suppliedTransactionDate,
final AppUser currentUser) {
final Money chargeAmount = loanCharge.getAmount(getCurrency()); final Money chargeAmount = loanCharge.getAmount(getCurrency());
Money feeCharges = chargeAmount; Money feeCharges = chargeAmount;
Money penaltyCharges = Money.zero(loanCurrency()); Money penaltyCharges = Money.zero(loanCurrency());
@@ -609,7 +611,7 @@ public class Loan extends AbstractPersistable<Long> {
} }
final LoanTransaction applyLoanChargeTransaction = LoanTransaction.accrueLoanCharge(this, getOffice(), chargeAmount, final LoanTransaction applyLoanChargeTransaction = LoanTransaction.accrueLoanCharge(this, getOffice(), chargeAmount,
transactionDate, feeCharges, penaltyCharges); transactionDate, feeCharges, penaltyCharges, DateUtils.getLocalDateTimeOfTenant(), currentUser);
Integer installmentNumber = null; Integer installmentNumber = null;
final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(applyLoanChargeTransaction, loanCharge, loanCharge.getAmount( final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(applyLoanChargeTransaction, loanCharge, loanCharge.getAmount(
getCurrency()).getAmount(), installmentNumber); getCurrency()).getAmount(), installmentNumber);
@@ -864,7 +866,8 @@ public class Loan extends AbstractPersistable<Long> {
public LoanTransaction waiveLoanCharge(final LoanCharge loanCharge, final LoanLifecycleStateMachine loanLifecycleStateMachine, public LoanTransaction waiveLoanCharge(final LoanCharge loanCharge, final LoanLifecycleStateMachine loanLifecycleStateMachine,
final Map<String, Object> changes, final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds, final Map<String, Object> changes, final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
final Integer loanInstallmentNumber, final ScheduleGeneratorDTO scheduleGeneratorDTO, final Money accruedCharge) { final Integer loanInstallmentNumber, final ScheduleGeneratorDTO scheduleGeneratorDTO, final Money accruedCharge,
final AppUser currentUser) {
validateLoanIsNotClosed(loanCharge); validateLoanIsNotClosed(loanCharge);
@@ -902,7 +905,7 @@ public class Loan extends AbstractPersistable<Long> {
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds()); existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
final LoanTransaction waiveLoanChargeTransaction = LoanTransaction.waiveLoanCharge(this, getOffice(), amountWaived, final LoanTransaction waiveLoanChargeTransaction = LoanTransaction.waiveLoanCharge(this, getOffice(), amountWaived,
transactionDate, feeChargesWaived, penaltyChargesWaived, unrecognizedIncome); transactionDate, feeChargesWaived, penaltyChargesWaived, unrecognizedIncome, DateUtils.getLocalDateTimeOfTenant(), currentUser );
final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(waiveLoanChargeTransaction, loanCharge, waiveLoanChargeTransaction final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(waiveLoanChargeTransaction, loanCharge, waiveLoanChargeTransaction
.getAmount(getCurrency()).getAmount(), loanInstallmentNumber); .getAmount(getCurrency()).getAmount(), loanInstallmentNumber);
waiveLoanChargeTransaction.getLoanChargesPaid().add(loanChargePaidBy); waiveLoanChargeTransaction.getLoanChargesPaid().add(loanChargePaidBy);
@@ -910,7 +913,7 @@ public class Loan extends AbstractPersistable<Long> {
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled() if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()
&& (loanCharge.getDueLocalDate() == null || LocalDate.now().isAfter(loanCharge.getDueLocalDate()))) { && (loanCharge.getDueLocalDate() == null || LocalDate.now().isAfter(loanCharge.getDueLocalDate()))) {
regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO); regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO, currentUser);
} }
// Waive of charges whose due date falls after latest 'repayment' // Waive of charges whose due date falls after latest 'repayment'
// transaction dont require entire loan schedule to be reprocessed. // transaction dont require entire loan schedule to be reprocessed.
@@ -1037,7 +1040,8 @@ public class Loan extends AbstractPersistable<Long> {
this.collateral.addAll(associateWithThisLoan(loanCollateral)); this.collateral.addAll(associateWithThisLoan(loanCollateral));
} }
public void updateLoanSchedule(final LoanScheduleModel modifiedLoanSchedule) { public void updateLoanSchedule(final LoanScheduleModel modifiedLoanSchedule,
AppUser currentUser) {
this.repaymentScheduleInstallments.clear(); this.repaymentScheduleInstallments.clear();
for (final LoanScheduleModelPeriod scheduledLoanInstallment : modifiedLoanSchedule.getPeriods()) { for (final LoanScheduleModelPeriod scheduledLoanInstallment : modifiedLoanSchedule.getPeriods()) {
@@ -1054,7 +1058,7 @@ public class Loan extends AbstractPersistable<Long> {
updateLoanScheduleDependentDerivedFields(); updateLoanScheduleDependentDerivedFields();
updateLoanSummaryDerivedFields(); updateLoanSummaryDerivedFields();
applyAccurals(); applyAccurals(currentUser);
} }
@@ -1062,12 +1066,12 @@ public class Loan extends AbstractPersistable<Long> {
* method updates accrual derived fields on installments and reverse the * method updates accrual derived fields on installments and reverse the
* unprocessed transactions * unprocessed transactions
*/ */
private void applyAccurals() { private void applyAccurals(AppUser currentUser) {
Collection<LoanTransaction> accruals = retreiveListOfAccrualTransactions(); Collection<LoanTransaction> accruals = retreiveListOfAccrualTransactions();
if (isPeriodicAccrualAccountingEnabledOnLoanProduct()) { if (isPeriodicAccrualAccountingEnabledOnLoanProduct()) {
applyPeriodicAccruals(accruals); applyPeriodicAccruals(accruals);
} else if (isNoneOrCashOrUpfrontAccrualAccountingEnabledOnLoanProduct()) { } else if (isNoneOrCashOrUpfrontAccrualAccountingEnabledOnLoanProduct()) {
updateAccrualsForNonPeriodicAccruals(accruals); updateAccrualsForNonPeriodicAccruals(accruals, currentUser);
} }
} }
@@ -1097,15 +1101,17 @@ public class Loan extends AbstractPersistable<Long> {
} }
} }
private void updateAccrualsForNonPeriodicAccruals(final Collection<LoanTransaction> accruals) { private void updateAccrualsForNonPeriodicAccruals(final Collection<LoanTransaction> accruals,
final AppUser currentUser) {
final Money interestApplied = Money.of(getCurrency(), this.summary.getTotalInterestCharged()); final Money interestApplied = Money.of(getCurrency(), this.summary.getTotalInterestCharged());
for (LoanTransaction loanTransaction : accruals) { for (LoanTransaction loanTransaction : accruals) {
if (loanTransaction.getInterestPortion(getCurrency()).isGreaterThanZero()) { if (loanTransaction.getInterestPortion(getCurrency()).isGreaterThanZero()) {
if (loanTransaction.getInterestPortion(getCurrency()).isNotEqualTo(interestApplied)) { if (loanTransaction.getInterestPortion(getCurrency()).isNotEqualTo(interestApplied)) {
loanTransaction.reverse(); loanTransaction.reverse();
final LocalDateTime currentDateTime = DateUtils.getLocalDateTimeOfTenant();
final LoanTransaction interestAppliedTransaction = LoanTransaction.accrueInterest(getOffice(), this, interestApplied, final LoanTransaction interestAppliedTransaction = LoanTransaction.accrueInterest(getOffice(), this, interestApplied,
getDisbursementDate()); getDisbursementDate(), currentDateTime, currentUser);
this.loanTransactions.add(interestAppliedTransaction); this.loanTransactions.add(interestAppliedTransaction);
} }
} else { } else {
@@ -1115,7 +1121,7 @@ public class Loan extends AbstractPersistable<Long> {
Money chargeAmount = loanCharge.getAmount(getCurrency()); Money chargeAmount = loanCharge.getAmount(getCurrency());
if (chargeAmount.isNotEqualTo(loanTransaction.getAmount(getCurrency()))) { if (chargeAmount.isNotEqualTo(loanTransaction.getAmount(getCurrency()))) {
loanTransaction.reverse(); loanTransaction.reverse();
handleChargeAppliedTransaction(loanCharge, loanTransaction.getTransactionDate()); handleChargeAppliedTransaction(loanCharge, loanTransaction.getTransactionDate(), currentUser);
} }
} }
@@ -1664,7 +1670,7 @@ public class Loan extends AbstractPersistable<Long> {
final LocalDate submittedOn, final String externalId, final boolean allowTransactionsOnHoliday, final List<Holiday> holidays, final LocalDate submittedOn, final String externalId, final boolean allowTransactionsOnHoliday, final List<Holiday> holidays,
final WorkingDays workingDays, final boolean allowTransactionsOnNonWorkingDay, final LocalDate recalculationRestFrequencyDate) { final WorkingDays workingDays, final boolean allowTransactionsOnNonWorkingDay, final LocalDate recalculationRestFrequencyDate) {
updateLoanSchedule(loanSchedule); updateLoanSchedule(loanSchedule, currentUser);
LoanStatus from = null; LoanStatus from = null;
if (this.loanStatus != null) { if (this.loanStatus != null) {
@@ -2027,13 +2033,14 @@ public class Loan extends AbstractPersistable<Long> {
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled() if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()
&& (fetchRepaymentScheduleInstallment(1).getDueDate().isBefore(LocalDate.now()) || isDisbursementMissed())) { && (fetchRepaymentScheduleInstallment(1).getDueDate().isBefore(LocalDate.now()) || isDisbursementMissed())) {
regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO); regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO, currentUser);
} }
updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement()); updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
updateLoanRepaymentPeriodsDerivedFields(actualDisbursementDate); updateLoanRepaymentPeriodsDerivedFields(actualDisbursementDate);
updateLoanSummaryDerivedFields(); updateLoanSummaryDerivedFields();
handleDisbursementTransaction(actualDisbursementDate); LocalDateTime createdDate = DateUtils.getLocalDateTimeOfTenant();
handleDisbursementTransaction(actualDisbursementDate, createdDate, currentUser);
final Money interestApplied = Money.of(getCurrency(), this.summary.getTotalInterestCharged()); final Money interestApplied = Money.of(getCurrency(), this.summary.getTotalInterestCharged());
@@ -2045,7 +2052,7 @@ public class Loan extends AbstractPersistable<Long> {
if (isNoneOrCashOrUpfrontAccrualAccountingEnabledOnLoanProduct()) { if (isNoneOrCashOrUpfrontAccrualAccountingEnabledOnLoanProduct()) {
final LoanTransaction interestAppliedTransaction = LoanTransaction.accrueInterest(getOffice(), this, interestApplied, final LoanTransaction interestAppliedTransaction = LoanTransaction.accrueInterest(getOffice(), this, interestApplied,
actualDisbursementDate); actualDisbursementDate, createdDate, currentUser);
this.loanTransactions.add(interestAppliedTransaction); this.loanTransactions.add(interestAppliedTransaction);
} }
@@ -2054,7 +2061,7 @@ public class Loan extends AbstractPersistable<Long> {
} }
public void regenerateScheduleOnDisbursement(final ScheduleGeneratorDTO scheduleGeneratorDTO, final boolean recalculateSchedule, public void regenerateScheduleOnDisbursement(final ScheduleGeneratorDTO scheduleGeneratorDTO, final boolean recalculateSchedule,
final LocalDate actualDisbursementDate, BigDecimal emiAmount) { final LocalDate actualDisbursementDate, BigDecimal emiAmount, final AppUser currentUser) {
boolean isEmiAmountChanged = false; boolean isEmiAmountChanged = false;
if (this.loanProduct.isMultiDisburseLoan() && emiAmount != null && emiAmount.compareTo(retriveLastEmiAmount()) != 0) { if (this.loanProduct.isMultiDisburseLoan() && emiAmount != null && emiAmount.compareTo(retriveLastEmiAmount()) != 0) {
LoanTermVariations loanVariationTerms = new LoanTermVariations(LoanTermVariationType.EMI_AMOUNT.getValue(), LoanTermVariations loanVariationTerms = new LoanTermVariations(LoanTermVariationType.EMI_AMOUNT.getValue(),
@@ -2064,7 +2071,7 @@ public class Loan extends AbstractPersistable<Long> {
} }
if (isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate) || recalculateSchedule || isEmiAmountChanged) { if (isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate) || recalculateSchedule || isEmiAmountChanged) {
regenerateRepaymentSchedule(scheduleGeneratorDTO); regenerateRepaymentSchedule(scheduleGeneratorDTO, currentUser);
} }
} }
@@ -2249,11 +2256,12 @@ public class Loan extends AbstractPersistable<Long> {
* Ability to regenerate the repayment schedule based on the loans current * Ability to regenerate the repayment schedule based on the loans current
* details/state. * details/state.
*/ */
public void regenerateRepaymentSchedule(final ScheduleGeneratorDTO scheduleGeneratorDTO) { public void regenerateRepaymentSchedule(final ScheduleGeneratorDTO scheduleGeneratorDTO,
AppUser currentUser) {
final LoanScheduleModel loanSchedule = regenerateScheduleModel(scheduleGeneratorDTO); final LoanScheduleModel loanSchedule = regenerateScheduleModel(scheduleGeneratorDTO);
updateLoanSchedule(loanSchedule); updateLoanSchedule(loanSchedule, currentUser);
Set<LoanCharge> charges = this.charges(); Set<LoanCharge> charges = this.charges();
for (LoanCharge loanCharge : charges) { for (LoanCharge loanCharge : charges) {
recalculateLoanCharge(loanCharge, scheduleGeneratorDTO.getPenaltyWaitPeriod()); recalculateLoanCharge(loanCharge, scheduleGeneratorDTO.getPenaltyWaitPeriod());
@@ -2302,7 +2310,7 @@ public class Loan extends AbstractPersistable<Long> {
return loanSchedule; return loanSchedule;
} }
private void handleDisbursementTransaction(final LocalDate disbursedOn) { private void handleDisbursementTransaction(final LocalDate disbursedOn, final LocalDateTime createdDate, final AppUser currentUser) {
// add repayment transaction to track incoming money from client to mfi // add repayment transaction to track incoming money from client to mfi
// for (charges due at time of disbursement) // for (charges due at time of disbursement)
@@ -2320,7 +2328,7 @@ public class Loan extends AbstractPersistable<Long> {
if (disbursedOn.toDate().equals(this.actualDisbursementDate)) { if (disbursedOn.toDate().equals(this.actualDisbursementDate)) {
Money disbursentMoney = Money.zero(getCurrency()); Money disbursentMoney = Money.zero(getCurrency());
final LoanTransaction chargesPayment = LoanTransaction.repaymentAtDisbursement(getOffice(), disbursentMoney, null, disbursedOn, final LoanTransaction chargesPayment = LoanTransaction.repaymentAtDisbursement(getOffice(), disbursentMoney, null, disbursedOn,
null); null, createdDate, currentUser);
final Integer installmentNumber = null; final Integer installmentNumber = null;
for (final LoanCharge charge : charges()) { for (final LoanCharge charge : charges()) {
if (charge.isDueAtDisbursement()) { if (charge.isDueAtDisbursement()) {
@@ -2339,7 +2347,7 @@ public class Loan extends AbstractPersistable<Long> {
* None or Cash based accounting is enabled * None or Cash based accounting is enabled
**/ **/
if (isNoneOrCashOrUpfrontAccrualAccountingEnabledOnLoanProduct()) { if (isNoneOrCashOrUpfrontAccrualAccountingEnabledOnLoanProduct()) {
handleChargeAppliedTransaction(charge, disbursedOn); handleChargeAppliedTransaction(charge, disbursedOn, currentUser);
} }
} }
} }
@@ -2399,7 +2407,7 @@ public class Loan extends AbstractPersistable<Long> {
} }
public Map<String, Object> undoDisbursal(final ScheduleGeneratorDTO scheduleGeneratorDTO, final List<Long> existingTransactionIds, public Map<String, Object> undoDisbursal(final ScheduleGeneratorDTO scheduleGeneratorDTO, final List<Long> existingTransactionIds,
final List<Long> existingReversedTransactionIds) { final List<Long> existingReversedTransactionIds, AppUser currentUser) {
validateAccountStatus(LoanEvent.LOAN_DISBURSAL_UNDO); validateAccountStatus(LoanEvent.LOAN_DISBURSAL_UNDO);
@@ -2430,7 +2438,7 @@ public class Loan extends AbstractPersistable<Long> {
// clear off actual disbusrement date so schedule regeneration // clear off actual disbusrement date so schedule regeneration
// uses expected date. // uses expected date.
regenerateRepaymentSchedule(scheduleGeneratorDTO); regenerateRepaymentSchedule(scheduleGeneratorDTO, currentUser);
if (isDisbursedAmountChanged) { if (isDisbursedAmountChanged) {
updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement()); updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
} }
@@ -2481,7 +2489,8 @@ public class Loan extends AbstractPersistable<Long> {
public ChangedTransactionDetail waiveInterest(final LoanTransaction waiveInterestTransaction, public ChangedTransactionDetail waiveInterest(final LoanTransaction waiveInterestTransaction,
final LoanLifecycleStateMachine loanLifecycleStateMachine, final List<Long> existingTransactionIds, final LoanLifecycleStateMachine loanLifecycleStateMachine, final List<Long> existingTransactionIds,
final List<Long> existingReversedTransactionIds, final ScheduleGeneratorDTO scheduleGeneratorDTO) { final List<Long> existingReversedTransactionIds, final ScheduleGeneratorDTO scheduleGeneratorDTO,
final AppUser currentUser) {
validateAccountStatus(LoanEvent.LOAN_REPAYMENT_OR_WAIVER); validateAccountStatus(LoanEvent.LOAN_REPAYMENT_OR_WAIVER);
@@ -2494,14 +2503,15 @@ public class Loan extends AbstractPersistable<Long> {
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds()); existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
final ChangedTransactionDetail changedTransactionDetail = handleRepaymentOrRecoveryOrWaiverTransaction(waiveInterestTransaction, final ChangedTransactionDetail changedTransactionDetail = handleRepaymentOrRecoveryOrWaiverTransaction(waiveInterestTransaction,
loanLifecycleStateMachine, null, scheduleGeneratorDTO); loanLifecycleStateMachine, null, scheduleGeneratorDTO, currentUser);
return changedTransactionDetail; return changedTransactionDetail;
} }
public ChangedTransactionDetail makeRepayment(final LoanTransaction repaymentTransaction, public ChangedTransactionDetail makeRepayment(final LoanTransaction repaymentTransaction,
final LoanLifecycleStateMachine loanLifecycleStateMachine, final List<Long> existingTransactionIds, final LoanLifecycleStateMachine loanLifecycleStateMachine, final List<Long> existingTransactionIds,
final List<Long> existingReversedTransactionIds, boolean isRecoveryRepayment, final ScheduleGeneratorDTO scheduleGeneratorDTO) { final List<Long> existingReversedTransactionIds, boolean isRecoveryRepayment, final ScheduleGeneratorDTO scheduleGeneratorDTO,
final AppUser currentUser) {
LoanEvent event = null; LoanEvent event = null;
if (isRecoveryRepayment) { if (isRecoveryRepayment) {
@@ -2523,7 +2533,7 @@ public class Loan extends AbstractPersistable<Long> {
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds()); existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
final ChangedTransactionDetail changedTransactionDetail = handleRepaymentOrRecoveryOrWaiverTransaction(repaymentTransaction, final ChangedTransactionDetail changedTransactionDetail = handleRepaymentOrRecoveryOrWaiverTransaction(repaymentTransaction,
loanLifecycleStateMachine, null, scheduleGeneratorDTO); loanLifecycleStateMachine, null, scheduleGeneratorDTO, currentUser);
return changedTransactionDetail; return changedTransactionDetail;
} }
@@ -2592,7 +2602,7 @@ public class Loan extends AbstractPersistable<Long> {
private ChangedTransactionDetail handleRepaymentOrRecoveryOrWaiverTransaction(final LoanTransaction loanTransaction, private ChangedTransactionDetail handleRepaymentOrRecoveryOrWaiverTransaction(final LoanTransaction loanTransaction,
final LoanLifecycleStateMachine loanLifecycleStateMachine, final LoanTransaction adjustedTransaction, final LoanLifecycleStateMachine loanLifecycleStateMachine, final LoanTransaction adjustedTransaction,
final ScheduleGeneratorDTO scheduleGeneratorDTO) { final ScheduleGeneratorDTO scheduleGeneratorDTO, final AppUser currentUser) {
ChangedTransactionDetail changedTransactionDetail = null; ChangedTransactionDetail changedTransactionDetail = null;
@@ -2691,7 +2701,7 @@ public class Loan extends AbstractPersistable<Long> {
} }
if (reprocess) { if (reprocess) {
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) { if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO); regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO, currentUser);
} }
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
@@ -2926,7 +2936,8 @@ public class Loan extends AbstractPersistable<Long> {
return loanRepaymentScheduleInstallment; return loanRepaymentScheduleInstallment;
} }
public LoanTransaction deriveDefaultInterestWaiverTransaction() { public LoanTransaction deriveDefaultInterestWaiverTransaction(
final LocalDateTime createdDate, final AppUser currentUser) {
final Money totalInterestOutstanding = getTotalInterestOutstandingOnLoan(); final Money totalInterestOutstanding = getTotalInterestOutstandingOnLoan();
Money possibleInterestToWaive = totalInterestOutstanding.copy(); Money possibleInterestToWaive = totalInterestOutstanding.copy();
@@ -2948,13 +2959,13 @@ public class Loan extends AbstractPersistable<Long> {
} }
return LoanTransaction.waiver(getOffice(), this, possibleInterestToWaive, transactionDate, possibleInterestToWaive, return LoanTransaction.waiver(getOffice(), this, possibleInterestToWaive, transactionDate, possibleInterestToWaive,
possibleInterestToWaive.zero()); possibleInterestToWaive.zero(), createdDate, currentUser);
} }
public ChangedTransactionDetail adjustExistingTransaction(final LoanTransaction newTransactionDetail, public ChangedTransactionDetail adjustExistingTransaction(final LoanTransaction newTransactionDetail,
final LoanLifecycleStateMachine loanLifecycleStateMachine, final LoanTransaction transactionForAdjustment, final LoanLifecycleStateMachine loanLifecycleStateMachine, final LoanTransaction transactionForAdjustment,
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds, final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
final ScheduleGeneratorDTO scheduleGeneratorDTO) { final ScheduleGeneratorDTO scheduleGeneratorDTO, final AppUser currentUser) {
HolidayDetailDTO holidayDetailDTO = scheduleGeneratorDTO.getHolidayDetailDTO(); HolidayDetailDTO holidayDetailDTO = scheduleGeneratorDTO.getHolidayDetailDTO();
validateRepaymentDateIsOnHoliday(newTransactionDetail.getTransactionDate(), holidayDetailDTO.isAllowTransactionsOnHoliday(), validateRepaymentDateIsOnHoliday(newTransactionDetail.getTransactionDate(), holidayDetailDTO.isAllowTransactionsOnHoliday(),
@@ -2991,14 +3002,15 @@ public class Loan extends AbstractPersistable<Long> {
if (newTransactionDetail.isRepayment() || newTransactionDetail.isInterestWaiver()) { if (newTransactionDetail.isRepayment() || newTransactionDetail.isInterestWaiver()) {
changedTransactionDetail = handleRepaymentOrRecoveryOrWaiverTransaction(newTransactionDetail, loanLifecycleStateMachine, changedTransactionDetail = handleRepaymentOrRecoveryOrWaiverTransaction(newTransactionDetail, loanLifecycleStateMachine,
transactionForAdjustment, scheduleGeneratorDTO); transactionForAdjustment, scheduleGeneratorDTO, currentUser);
} }
return changedTransactionDetail; return changedTransactionDetail;
} }
public ChangedTransactionDetail undoWrittenOff(final List<Long> existingTransactionIds, public ChangedTransactionDetail undoWrittenOff(final List<Long> existingTransactionIds,
final List<Long> existingReversedTransactionIds, final ScheduleGeneratorDTO scheduleGeneratorDTO) { final List<Long> existingReversedTransactionIds, final ScheduleGeneratorDTO scheduleGeneratorDTO,
final AppUser currentUser) {
validateAccountStatus(LoanEvent.WRITE_OFF_OUTSTANDING_UNDO); validateAccountStatus(LoanEvent.WRITE_OFF_OUTSTANDING_UNDO);
existingTransactionIds.addAll(findExistingTransactionIds()); existingTransactionIds.addAll(findExistingTransactionIds());
@@ -3010,7 +3022,7 @@ public class Loan extends AbstractPersistable<Long> {
.determineProcessor(this.transactionProcessingStrategy); .determineProcessor(this.transactionProcessingStrategy);
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) { if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO); regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO, currentUser);
} }
ChangedTransactionDetail changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction( ChangedTransactionDetail changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(
getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments,
@@ -3081,7 +3093,7 @@ public class Loan extends AbstractPersistable<Long> {
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
.determineProcessor(this.transactionProcessingStrategy); .determineProcessor(this.transactionProcessingStrategy);
ChangedTransactionDetail changedTransactionDetail = closeDisbursements(scheduleGeneratorDTO, ChangedTransactionDetail changedTransactionDetail = closeDisbursements(scheduleGeneratorDTO,
loanRepaymentScheduleTransactionProcessor); loanRepaymentScheduleTransactionProcessor, currentUser);
validateAccountStatus(LoanEvent.WRITE_OFF_OUTSTANDING); validateAccountStatus(LoanEvent.WRITE_OFF_OUTSTANDING);
@@ -3119,7 +3131,9 @@ public class Loan extends AbstractPersistable<Long> {
throw new InvalidLoanStateTransitionException("writeoff", "cannot.be.a.future.date", errorMessage, writtenOffOnLocalDate); throw new InvalidLoanStateTransitionException("writeoff", "cannot.be.a.future.date", errorMessage, writtenOffOnLocalDate);
} }
loanTransaction = LoanTransaction.writeoff(this, getOffice(), writtenOffOnLocalDate, txnExternalId); LocalDateTime createdDate = DateUtils.getLocalDateTimeOfTenant();
loanTransaction = LoanTransaction.writeoff(this, getOffice(), writtenOffOnLocalDate, txnExternalId,
createdDate, currentUser);
final boolean isLastTransaction = isChronologicallyLatestTransaction(loanTransaction, this.loanTransactions); final boolean isLastTransaction = isChronologicallyLatestTransaction(loanTransaction, this.loanTransactions);
if (!isLastTransaction) { if (!isLastTransaction) {
final String errorMessage = "The date of the writeoff transaction must occur on or before previous transactions."; final String errorMessage = "The date of the writeoff transaction must occur on or before previous transactions.";
@@ -3141,14 +3155,15 @@ public class Loan extends AbstractPersistable<Long> {
} }
private ChangedTransactionDetail closeDisbursements(final ScheduleGeneratorDTO scheduleGeneratorDTO, private ChangedTransactionDetail closeDisbursements(final ScheduleGeneratorDTO scheduleGeneratorDTO,
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor) { final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
final AppUser currentUser) {
ChangedTransactionDetail changedTransactionDetail = null; ChangedTransactionDetail changedTransactionDetail = null;
if (isDisbursementAllowed() && atleastOnceDisbursed()) { if (isDisbursementAllowed() && atleastOnceDisbursed()) {
this.loanRepaymentScheduleDetail.setPrincipal(getDisbursedAmount()); this.loanRepaymentScheduleDetail.setPrincipal(getDisbursedAmount());
removeDisbursementDetail(); removeDisbursementDetail();
regenerateRepaymentSchedule(scheduleGeneratorDTO); regenerateRepaymentSchedule(scheduleGeneratorDTO, currentUser);
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) { if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO); regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO, currentUser);
} }
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
@@ -3178,7 +3193,7 @@ public class Loan extends AbstractPersistable<Long> {
public ChangedTransactionDetail close(final JsonCommand command, final LoanLifecycleStateMachine loanLifecycleStateMachine, public ChangedTransactionDetail close(final JsonCommand command, final LoanLifecycleStateMachine loanLifecycleStateMachine,
final Map<String, Object> changes, final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds, final Map<String, Object> changes, final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
final ScheduleGeneratorDTO scheduleGeneratorDTO) { final ScheduleGeneratorDTO scheduleGeneratorDTO, final AppUser currentUser) {
validateAccountStatus(LoanEvent.LOAN_CLOSED); validateAccountStatus(LoanEvent.LOAN_CLOSED);
@@ -3206,7 +3221,7 @@ public class Loan extends AbstractPersistable<Long> {
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
.determineProcessor(this.transactionProcessingStrategy); .determineProcessor(this.transactionProcessingStrategy);
ChangedTransactionDetail changedTransactionDetail = closeDisbursements(scheduleGeneratorDTO, ChangedTransactionDetail changedTransactionDetail = closeDisbursements(scheduleGeneratorDTO,
loanRepaymentScheduleTransactionProcessor); loanRepaymentScheduleTransactionProcessor, currentUser);
LoanTransaction loanTransaction = null; LoanTransaction loanTransaction = null;
if (isOpen()) { if (isOpen()) {
@@ -3220,7 +3235,8 @@ public class Loan extends AbstractPersistable<Long> {
changes.put("status", LoanEnumerations.status(this.loanStatus)); changes.put("status", LoanEnumerations.status(this.loanStatus));
} }
this.closedOnDate = closureDate.toDate(); this.closedOnDate = closureDate.toDate();
loanTransaction = LoanTransaction.writeoff(this, getOffice(), closureDate, txnExternalId); loanTransaction = LoanTransaction.writeoff(this, getOffice(), closureDate, txnExternalId,
DateUtils.getLocalDateTimeOfTenant(), currentUser);
final boolean isLastTransaction = isChronologicallyLatestTransaction(loanTransaction, this.loanTransactions); final boolean isLastTransaction = isChronologicallyLatestTransaction(loanTransaction, this.loanTransactions);
if (!isLastTransaction) { if (!isLastTransaction) {
final String errorMessage = "The closing date of the loan must be on or after latest transaction date."; final String errorMessage = "The closing date of the loan must be on or after latest transaction date.";
@@ -4316,7 +4332,8 @@ public class Loan extends AbstractPersistable<Long> {
public ChangedTransactionDetail updateDisbursementDateForTranche(final LoanDisbursementDetails disbursementDetails, public ChangedTransactionDetail updateDisbursementDateForTranche(final LoanDisbursementDetails disbursementDetails,
final JsonCommand command, final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds, final JsonCommand command, final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
final Map<String, Object> actualChanges, final ScheduleGeneratorDTO scheduleGeneratorDTO) { final Map<String, Object> actualChanges, final ScheduleGeneratorDTO scheduleGeneratorDTO,
final AppUser currentUser) {
validateAccountStatus(LoanEvent.LOAN_EDIT_MULTI_DISBURSE_DATE); validateAccountStatus(LoanEvent.LOAN_EDIT_MULTI_DISBURSE_DATE);
final LocalDate expectedDisbursementDate = command.localDateValueOfParameterNamed(LoanApiConstants.disbursementDateParameterName); final LocalDate expectedDisbursementDate = command.localDateValueOfParameterNamed(LoanApiConstants.disbursementDateParameterName);
disbursementDetails.updateExpectedDisbursementDate(expectedDisbursementDate.toDate()); disbursementDetails.updateExpectedDisbursementDate(expectedDisbursementDate.toDate());
@@ -4328,9 +4345,9 @@ public class Loan extends AbstractPersistable<Long> {
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds()); existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) { if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO); regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO, currentUser);
} else { } else {
regenerateRepaymentSchedule(scheduleGeneratorDTO); regenerateRepaymentSchedule(scheduleGeneratorDTO, currentUser);
} }
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
@@ -4409,7 +4426,8 @@ public class Loan extends AbstractPersistable<Long> {
} }
public ChangedTransactionDetail recalculateScheduleFromLastTransaction(final ScheduleGeneratorDTO generatorDTO, public ChangedTransactionDetail recalculateScheduleFromLastTransaction(final ScheduleGeneratorDTO generatorDTO,
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds) { final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
final AppUser currentUser) {
existingTransactionIds.addAll(findExistingTransactionIds()); existingTransactionIds.addAll(findExistingTransactionIds());
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds()); existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
/* /*
@@ -4423,14 +4441,15 @@ public class Loan extends AbstractPersistable<Long> {
* generatorDTO.setRecalculateFrom(recalculateFrom); * generatorDTO.setRecalculateFrom(recalculateFrom);
*/ */
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) { if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
regenerateRepaymentScheduleWithInterestRecalculation(generatorDTO); regenerateRepaymentScheduleWithInterestRecalculation(generatorDTO, currentUser);
} }
return processTransactions(); return processTransactions();
} }
public ChangedTransactionDetail handleRegenerateRepaymentScheduleWithInterestRecalculation(final ScheduleGeneratorDTO generatorDTO) { public ChangedTransactionDetail handleRegenerateRepaymentScheduleWithInterestRecalculation(final ScheduleGeneratorDTO generatorDTO,
regenerateRepaymentScheduleWithInterestRecalculation(generatorDTO); final AppUser currentUser) {
regenerateRepaymentScheduleWithInterestRecalculation(generatorDTO, currentUser);
return processTransactions(); return processTransactions();
} }
@@ -4459,13 +4478,14 @@ public class Loan extends AbstractPersistable<Long> {
return changedTransactionDetail; return changedTransactionDetail;
} }
private void regenerateRepaymentScheduleWithInterestRecalculation(final ScheduleGeneratorDTO generatorDTO) { private void regenerateRepaymentScheduleWithInterestRecalculation(final ScheduleGeneratorDTO generatorDTO,
final AppUser currentUser) {
LocalDate lastTransactionDate = getLastUserTransactionDate(); LocalDate lastTransactionDate = getLastUserTransactionDate();
generatorDTO.setLastTransactionDate(lastTransactionDate); generatorDTO.setLastTransactionDate(lastTransactionDate);
final LoanScheduleModel loanSchedule = getRecalculatedSchedule(generatorDTO); final LoanScheduleModel loanSchedule = getRecalculatedSchedule(generatorDTO);
if (loanSchedule == null) { return; } if (loanSchedule == null) { return; }
updateLoanSchedule(loanSchedule); updateLoanSchedule(loanSchedule, currentUser);
LocalDate lastRepaymentDate = this.getLastRepaymentPeriodDueDate(); LocalDate lastRepaymentDate = this.getLastRepaymentPeriodDueDate();
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
@@ -12,23 +12,26 @@ import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance; import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
import org.mifosplatform.portfolio.loanaccount.data.ScheduleGeneratorDTO; import org.mifosplatform.portfolio.loanaccount.data.ScheduleGeneratorDTO;
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail; import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
import org.mifosplatform.useradministration.domain.AppUser;
public interface LoanAccountDomainService { public interface LoanAccountDomainService {
LoanTransaction makeRepayment(Loan loan, CommandProcessingResultBuilder builderResult, LocalDate transactionDate, LoanTransaction makeRepayment(Loan loan, CommandProcessingResultBuilder builderResult, LocalDate transactionDate,
BigDecimal transactionAmount, PaymentDetail paymentDetail, String noteText, String txnExternalId, BigDecimal transactionAmount, PaymentDetail paymentDetail, String noteText, String txnExternalId,
final boolean isRecoveryRepayment, boolean isAccountTransfer); final boolean isRecoveryRepayment, boolean isAccountTransfer, final AppUser currentUser);
LoanTransaction makeRefund(Long accountId, CommandProcessingResultBuilder builderResult, LocalDate transactionDate, LoanTransaction makeRefund(Long accountId, CommandProcessingResultBuilder builderResult, LocalDate transactionDate,
BigDecimal transactionAmount, PaymentDetail paymentDetail, String noteText, String txnExternalId); BigDecimal transactionAmount, PaymentDetail paymentDetail, String noteText, String txnExternalId,
final AppUser currentUser);
void reverseTransfer(LoanTransaction loanTransaction); void reverseTransfer(LoanTransaction loanTransaction);
LoanTransaction makeChargePayment(Loan loan, Long chargeId, LocalDate transactionDate, BigDecimal transactionAmount, LoanTransaction makeChargePayment(Loan loan, Long chargeId, LocalDate transactionDate, BigDecimal transactionAmount,
PaymentDetail paymentDetail, String noteText, String txnExternalId, Integer transactionType, Integer installmentNumber); PaymentDetail paymentDetail, String noteText, String txnExternalId, Integer transactionType, Integer installmentNumber,
final AppUser currentUser);
LoanTransaction makeDisburseTransaction(Long loanId, LocalDate transactionDate, BigDecimal transactionAmount, LoanTransaction makeDisburseTransaction(Long loanId, LocalDate transactionDate, BigDecimal transactionAmount,
PaymentDetail paymentDetail, String noteText, String txnExternalId); PaymentDetail paymentDetail, String noteText, String txnExternalId, final AppUser currentUser);
LocalDate getCalculatedRepaymentsStartingFromDate(LocalDate actualDisbursementDate, Loan loan, CalendarInstance calendarInstance); LocalDate getCalculatedRepaymentsStartingFromDate(LocalDate actualDisbursementDate, Loan loan, CalendarInstance calendarInstance);
@@ -15,6 +15,7 @@ import java.util.Set;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.mifosplatform.accounting.journalentry.service.JournalEntryWritePlatformService; import org.mifosplatform.accounting.journalentry.service.JournalEntryWritePlatformService;
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService; import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
import org.mifosplatform.infrastructure.core.data.ApiParameterError; import org.mifosplatform.infrastructure.core.data.ApiParameterError;
@@ -22,6 +23,7 @@ import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
import org.mifosplatform.infrastructure.core.exception.GeneralPlatformDomainRuleException; import org.mifosplatform.infrastructure.core.exception.GeneralPlatformDomainRuleException;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
import org.mifosplatform.infrastructure.core.service.DateUtils;
import org.mifosplatform.organisation.holiday.domain.Holiday; import org.mifosplatform.organisation.holiday.domain.Holiday;
import org.mifosplatform.organisation.holiday.domain.HolidayRepository; import org.mifosplatform.organisation.holiday.domain.HolidayRepository;
import org.mifosplatform.organisation.holiday.domain.HolidayStatusType; import org.mifosplatform.organisation.holiday.domain.HolidayStatusType;
@@ -54,6 +56,7 @@ import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
import org.mifosplatform.portfolio.note.domain.Note; import org.mifosplatform.portfolio.note.domain.Note;
import org.mifosplatform.portfolio.note.domain.NoteRepository; import org.mifosplatform.portfolio.note.domain.NoteRepository;
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail; import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -112,7 +115,8 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
@Override @Override
public LoanTransaction makeRepayment(final Loan loan, final CommandProcessingResultBuilder builderResult, public LoanTransaction makeRepayment(final Loan loan, final CommandProcessingResultBuilder builderResult,
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final String noteText, final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final String noteText,
final String txnExternalId, final boolean isRecoveryRepayment, boolean isAccountTransfer) { final String txnExternalId, final boolean isRecoveryRepayment, boolean isAccountTransfer,
final AppUser currentUser) {
checkClientOrGroupActive(loan); checkClientOrGroupActive(loan);
@@ -134,12 +138,13 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
final Money repaymentAmount = Money.of(loan.getCurrency(), transactionAmount); final Money repaymentAmount = Money.of(loan.getCurrency(), transactionAmount);
LoanTransaction newRepaymentTransaction = null; LoanTransaction newRepaymentTransaction = null;
final LocalDateTime currentDateTime = DateUtils.getLocalDateTimeOfTenant();
if (isRecoveryRepayment) { if (isRecoveryRepayment) {
newRepaymentTransaction = LoanTransaction.recoveryRepayment(loan.getOffice(), repaymentAmount, paymentDetail, transactionDate, newRepaymentTransaction = LoanTransaction.recoveryRepayment(loan.getOffice(), repaymentAmount, paymentDetail, transactionDate,
txnExternalId); txnExternalId, currentDateTime, currentUser);
} else { } else {
newRepaymentTransaction = LoanTransaction.repayment(loan.getOffice(), repaymentAmount, paymentDetail, transactionDate, newRepaymentTransaction = LoanTransaction.repayment(loan.getOffice(), repaymentAmount, paymentDetail, transactionDate,
txnExternalId); txnExternalId, currentDateTime, currentUser);
} }
final boolean allowTransactionsOnHoliday = this.configurationDomainService.allowTransactionsOnHolidayEnabled(); final boolean allowTransactionsOnHoliday = this.configurationDomainService.allowTransactionsOnHolidayEnabled();
@@ -177,7 +182,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
final ChangedTransactionDetail changedTransactionDetail = loan.makeRepayment(newRepaymentTransaction, final ChangedTransactionDetail changedTransactionDetail = loan.makeRepayment(newRepaymentTransaction,
defaultLoanLifecycleStateMachine(), existingTransactionIds, existingReversedTransactionIds, isRecoveryRepayment, defaultLoanLifecycleStateMachine(), existingTransactionIds, existingReversedTransactionIds, isRecoveryRepayment,
scheduleGeneratorDTO); scheduleGeneratorDTO, currentUser);
saveLoanTransactionWithDataIntegrityViolationChecks(newRepaymentTransaction); saveLoanTransactionWithDataIntegrityViolationChecks(newRepaymentTransaction);
@@ -257,7 +262,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
@Transactional @Transactional
public LoanTransaction makeChargePayment(final Loan loan, final Long chargeId, final LocalDate transactionDate, public LoanTransaction makeChargePayment(final Loan loan, final Long chargeId, final LocalDate transactionDate,
final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final String noteText, final String txnExternalId, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final String noteText, final String txnExternalId,
final Integer transactionType, Integer installmentNumber) { final Integer transactionType, Integer installmentNumber, final AppUser currentUser) {
boolean isAccountTransfer = true; boolean isAccountTransfer = true;
checkClientOrGroupActive(loan); checkClientOrGroupActive(loan);
@@ -269,7 +274,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
final LoanTransactionType loanTransactionType = LoanTransactionType.fromInt(transactionType); final LoanTransactionType loanTransactionType = LoanTransactionType.fromInt(transactionType);
final LoanTransaction newPaymentTransaction = LoanTransaction.loanPayment(null, loan.getOffice(), paymentAmout, paymentDetail, final LoanTransaction newPaymentTransaction = LoanTransaction.loanPayment(null, loan.getOffice(), paymentAmout, paymentDetail,
transactionDate, txnExternalId, loanTransactionType); transactionDate, txnExternalId, loanTransactionType, DateUtils.getLocalDateTimeOfTenant(), currentUser);
if (loanTransactionType.isRepaymentAtDisbursement()) { if (loanTransactionType.isRepaymentAtDisbursement()) {
loan.handlePayDisbursementTransaction(chargeId, newPaymentTransaction, existingTransactionIds, existingReversedTransactionIds); loan.handlePayDisbursementTransaction(chargeId, newPaymentTransaction, existingTransactionIds, existingReversedTransactionIds);
@@ -329,7 +334,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
@Override @Override
public LoanTransaction makeRefund(final Long accountId, final CommandProcessingResultBuilder builderResult, public LoanTransaction makeRefund(final Long accountId, final CommandProcessingResultBuilder builderResult,
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final String noteText, final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final String noteText,
final String txnExternalId) { final String txnExternalId, final AppUser currentUser) {
boolean isAccountTransfer = true; boolean isAccountTransfer = true;
final Loan loan = this.loanAccountAssembler.assembleFrom(accountId); final Loan loan = this.loanAccountAssembler.assembleFrom(accountId);
checkClientOrGroupActive(loan); checkClientOrGroupActive(loan);
@@ -339,7 +344,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
final Money refundAmount = Money.of(loan.getCurrency(), transactionAmount); final Money refundAmount = Money.of(loan.getCurrency(), transactionAmount);
final LoanTransaction newRefundTransaction = LoanTransaction.refund(loan.getOffice(), refundAmount, paymentDetail, transactionDate, final LoanTransaction newRefundTransaction = LoanTransaction.refund(loan.getOffice(), refundAmount, paymentDetail, transactionDate,
txnExternalId); txnExternalId, DateUtils.getLocalDateTimeOfTenant(), currentUser);
final boolean allowTransactionsOnHoliday = this.configurationDomainService.allowTransactionsOnHolidayEnabled(); final boolean allowTransactionsOnHoliday = this.configurationDomainService.allowTransactionsOnHolidayEnabled();
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(),
transactionDate.toDate(), HolidayStatusType.ACTIVE.getValue()); transactionDate.toDate(), HolidayStatusType.ACTIVE.getValue());
@@ -370,7 +375,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
@Transactional @Transactional
@Override @Override
public LoanTransaction makeDisburseTransaction(final Long loanId, final LocalDate transactionDate, final BigDecimal transactionAmount, public LoanTransaction makeDisburseTransaction(final Long loanId, final LocalDate transactionDate, final BigDecimal transactionAmount,
final PaymentDetail paymentDetail, final String noteText, final String txnExternalId) { final PaymentDetail paymentDetail, final String noteText, final String txnExternalId, final AppUser currentUser) {
final Loan loan = this.loanAccountAssembler.assembleFrom(loanId); final Loan loan = this.loanAccountAssembler.assembleFrom(loanId);
checkClientOrGroupActive(loan); checkClientOrGroupActive(loan);
boolean isAccountTransfer = true; boolean isAccountTransfer = true;
@@ -378,7 +383,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
final List<Long> existingReversedTransactionIds = new ArrayList<>(); final List<Long> existingReversedTransactionIds = new ArrayList<>();
final Money amount = Money.of(loan.getCurrency(), transactionAmount); final Money amount = Money.of(loan.getCurrency(), transactionAmount);
LoanTransaction disbursementTransaction = LoanTransaction.disbursement(loan.getOffice(), amount, paymentDetail, transactionDate, LoanTransaction disbursementTransaction = LoanTransaction.disbursement(loan.getOffice(), amount, paymentDetail, transactionDate,
txnExternalId); txnExternalId, DateUtils.getLocalDateTimeOfTenant(), currentUser);
disbursementTransaction.updateLoan(loan); disbursementTransaction.updateLoan(loan);
loan.getLoanTransactions().add(disbursementTransaction); loan.getLoanTransactions().add(disbursementTransaction);
saveLoanTransactionWithDataIntegrityViolationChecks(disbursementTransaction); saveLoanTransactionWithDataIntegrityViolationChecks(disbursementTransaction);
@@ -28,6 +28,7 @@ import javax.persistence.UniqueConstraint;
import org.hibernate.annotations.LazyCollection; import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption; import org.hibernate.annotations.LazyCollectionOption;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.mifosplatform.infrastructure.core.service.DateUtils; import org.mifosplatform.infrastructure.core.service.DateUtils;
import org.mifosplatform.organisation.monetary.data.CurrencyData; import org.mifosplatform.organisation.monetary.data.CurrencyData;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
@@ -39,6 +40,7 @@ import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData;
import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations; import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations;
import org.mifosplatform.portfolio.paymentdetail.data.PaymentDetailData; import org.mifosplatform.portfolio.paymentdetail.data.PaymentDetailData;
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail; import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.springframework.data.jpa.domain.AbstractPersistable;
/** /**
@@ -98,6 +100,14 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
@Column(name = "external_id", length = 100, nullable = true, unique = true) @Column(name = "external_id", length = 100, nullable = true, unique = true)
private String externalId; private String externalId;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "created_date", nullable = false)
private final Date createdDate;
@ManyToOne
@JoinColumn(name="appuser_id", nullable = true)
private final AppUser appUser;
@LazyCollection(LazyCollectionOption.FALSE) @LazyCollection(LazyCollectionOption.FALSE)
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loanTransaction", orphanRemoval = true) @OneToMany(cascade = CascadeType.ALL, mappedBy = "loanTransaction", orphanRemoval = true)
@@ -114,46 +124,51 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
this.dateOf = null; this.dateOf = null;
this.typeOf = null; this.typeOf = null;
this.submittedOnDate = DateUtils.getDateOfTenant(); this.submittedOnDate = DateUtils.getDateOfTenant();
this.createdDate = new Date();
this.appUser = null;
} }
public static LoanTransaction disbursement(final Office office, final Money amount, final PaymentDetail paymentDetail, public static LoanTransaction disbursement(final Office office, final Money amount, final PaymentDetail paymentDetail,
final LocalDate disbursementDate, final String externalId) { final LocalDate disbursementDate, final String externalId, final LocalDateTime createdDate, final AppUser appUser) {
return new LoanTransaction(null, office, LoanTransactionType.DISBURSEMENT, paymentDetail, amount.getAmount(), disbursementDate, return new LoanTransaction(null, office, LoanTransactionType.DISBURSEMENT, paymentDetail, amount.getAmount(), disbursementDate,
externalId); externalId, createdDate, appUser);
} }
public static LoanTransaction repayment(final Office office, final Money amount, final PaymentDetail paymentDetail, public static LoanTransaction repayment(final Office office, final Money amount, final PaymentDetail paymentDetail,
final LocalDate paymentDate, final String externalId) { final LocalDate paymentDate, final String externalId, final LocalDateTime createdDate, final AppUser appUser) {
return new LoanTransaction(null, office, LoanTransactionType.REPAYMENT, paymentDetail, amount.getAmount(), paymentDate, externalId); return new LoanTransaction(null, office, LoanTransactionType.REPAYMENT, paymentDetail, amount.getAmount(), paymentDate, externalId,
createdDate, appUser);
} }
public static LoanTransaction recoveryRepayment(final Office office, final Money amount, final PaymentDetail paymentDetail, public static LoanTransaction recoveryRepayment(final Office office, final Money amount, final PaymentDetail paymentDetail,
final LocalDate paymentDate, final String externalId) { final LocalDate paymentDate, final String externalId, final LocalDateTime createdDate, final AppUser appUser) {
return new LoanTransaction(null, office, LoanTransactionType.RECOVERY_REPAYMENT, paymentDetail, amount.getAmount(), paymentDate, return new LoanTransaction(null, office, LoanTransactionType.RECOVERY_REPAYMENT, paymentDetail, amount.getAmount(), paymentDate,
externalId); externalId, createdDate, appUser);
} }
public static LoanTransaction loanPayment(final Loan loan, final Office office, final Money amount, final PaymentDetail paymentDetail, public static LoanTransaction loanPayment(final Loan loan, final Office office, final Money amount, final PaymentDetail paymentDetail,
final LocalDate paymentDate, final String externalId, final LoanTransactionType transactionType) { final LocalDate paymentDate, final String externalId, final LoanTransactionType transactionType,
return new LoanTransaction(loan, office, transactionType, paymentDetail, amount.getAmount(), paymentDate, externalId); final LocalDateTime createdDate, final AppUser appUser){
return new LoanTransaction(loan, office, transactionType, paymentDetail, amount.getAmount(), paymentDate, externalId,
createdDate, appUser);
} }
public static LoanTransaction repaymentAtDisbursement(final Office office, final Money amount, final PaymentDetail paymentDetail, public static LoanTransaction repaymentAtDisbursement(final Office office, final Money amount, final PaymentDetail paymentDetail,
final LocalDate paymentDate, final String externalId) { final LocalDate paymentDate, final String externalId, final LocalDateTime createdDate, final AppUser appUser) {
return new LoanTransaction(null, office, LoanTransactionType.REPAYMENT_AT_DISBURSEMENT, paymentDetail, amount.getAmount(), return new LoanTransaction(null, office, LoanTransactionType.REPAYMENT_AT_DISBURSEMENT, paymentDetail, amount.getAmount(),
paymentDate, externalId); paymentDate, externalId, createdDate, appUser);
} }
public static LoanTransaction waiver(final Office office, final Loan loan, final Money amount, final LocalDate waiveDate, public static LoanTransaction waiver(final Office office, final Loan loan, final Money amount, final LocalDate waiveDate,
final Money waived, final Money unrecognizedPortion) { final Money waived, final Money unrecognizedPortion, final LocalDateTime createdDate, final AppUser appUser) {
LoanTransaction loanTransaction = new LoanTransaction(loan, office, LoanTransactionType.WAIVE_INTEREST, amount.getAmount(), LoanTransaction loanTransaction = new LoanTransaction(loan, office, LoanTransactionType.WAIVE_INTEREST, amount.getAmount(),
waiveDate, null); waiveDate, null, createdDate, appUser);
loanTransaction.updateInterestComponent(waived, unrecognizedPortion); loanTransaction.updateInterestComponent(waived, unrecognizedPortion);
return loanTransaction; return loanTransaction;
} }
public static LoanTransaction accrueInterest(final Office office, final Loan loan, final Money amount, public static LoanTransaction accrueInterest(final Office office, final Loan loan, final Money amount,
final LocalDate interestAppliedDate) { final LocalDate interestAppliedDate, final LocalDateTime createdDate, final AppUser appUser) {
BigDecimal principalPortion = null; BigDecimal principalPortion = null;
BigDecimal feesPortion = null; BigDecimal feesPortion = null;
BigDecimal penaltiesPortion = null; BigDecimal penaltiesPortion = null;
@@ -163,47 +178,53 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
PaymentDetail paymentDetail = null; PaymentDetail paymentDetail = null;
String externalId = null; String externalId = null;
return new LoanTransaction(loan, office, LoanTransactionType.ACCRUAL.getValue(), interestAppliedDate.toDate(), interestPortion, return new LoanTransaction(loan, office, LoanTransactionType.ACCRUAL.getValue(), interestAppliedDate.toDate(), interestPortion,
principalPortion, interestPortion, feesPortion, penaltiesPortion, overPaymentPortion, reversed, paymentDetail, externalId); principalPortion, interestPortion, feesPortion, penaltiesPortion, overPaymentPortion, reversed, paymentDetail, externalId,
createdDate, appUser);
} }
public static LoanTransaction initiateTransfer(final Office office, final Loan loan, final LocalDate transferDate) { public static LoanTransaction initiateTransfer(final Office office, final Loan loan, final LocalDate transferDate,
final LocalDateTime createdDate, final AppUser appUser) {
return new LoanTransaction(loan, office, LoanTransactionType.INITIATE_TRANSFER.getValue(), transferDate.toDateTimeAtStartOfDay() return new LoanTransaction(loan, office, LoanTransactionType.INITIATE_TRANSFER.getValue(), transferDate.toDateTimeAtStartOfDay()
.toDate(), loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(), loan.getSummary() .toDate(), loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(), loan.getSummary()
.getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(), loan.getSummary() .getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(), loan.getSummary()
.getTotalPenaltyChargesOutstanding(), null, false, null, null); .getTotalPenaltyChargesOutstanding(), null, false, null, null, createdDate, appUser);
} }
public static LoanTransaction approveTransfer(final Office office, final Loan loan, final LocalDate transferDate) { public static LoanTransaction approveTransfer(final Office office, final Loan loan, final LocalDate transferDate,
final LocalDateTime createdDate, final AppUser appUser) {
return new LoanTransaction(loan, office, LoanTransactionType.APPROVE_TRANSFER.getValue(), transferDate.toDateTimeAtStartOfDay() return new LoanTransaction(loan, office, LoanTransactionType.APPROVE_TRANSFER.getValue(), transferDate.toDateTimeAtStartOfDay()
.toDate(), loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(), loan.getSummary() .toDate(), loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(), loan.getSummary()
.getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(), loan.getSummary() .getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(), loan.getSummary()
.getTotalPenaltyChargesOutstanding(), null, false, null, null); .getTotalPenaltyChargesOutstanding(), null, false, null, null, createdDate, appUser);
} }
public static LoanTransaction withdrawTransfer(final Office office, final Loan loan, final LocalDate transferDate) { public static LoanTransaction withdrawTransfer(final Office office, final Loan loan, final LocalDate transferDate,
final LocalDateTime createdDate, final AppUser appUser) {
return new LoanTransaction(loan, office, LoanTransactionType.WITHDRAW_TRANSFER.getValue(), transferDate.toDateTimeAtStartOfDay() return new LoanTransaction(loan, office, LoanTransactionType.WITHDRAW_TRANSFER.getValue(), transferDate.toDateTimeAtStartOfDay()
.toDate(), loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(), loan.getSummary() .toDate(), loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(), loan.getSummary()
.getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(), loan.getSummary() .getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(), loan.getSummary()
.getTotalPenaltyChargesOutstanding(), null, false, null, null); .getTotalPenaltyChargesOutstanding(), null, false, null, null, createdDate, appUser);
} }
public static LoanTransaction refund(final Office office, final Money amount, final PaymentDetail paymentDetail, public static LoanTransaction refund(final Office office, final Money amount, final PaymentDetail paymentDetail,
final LocalDate paymentDate, final String externalId) { final LocalDate paymentDate, final String externalId, final LocalDateTime createdDate, final AppUser appUser) {
return new LoanTransaction(null, office, LoanTransactionType.REFUND, paymentDetail, amount.getAmount(), paymentDate, externalId); return new LoanTransaction(null, office, LoanTransactionType.REFUND, paymentDetail, amount.getAmount(), paymentDate, externalId,
createdDate, appUser);
} }
public static LoanTransaction copyTransactionProperties(final LoanTransaction loanTransaction) { public static LoanTransaction copyTransactionProperties(final LoanTransaction loanTransaction) {
return new LoanTransaction(loanTransaction.loan, loanTransaction.office, loanTransaction.typeOf, loanTransaction.dateOf, return new LoanTransaction(loanTransaction.loan, loanTransaction.office, loanTransaction.typeOf, loanTransaction.dateOf,
loanTransaction.amount, loanTransaction.principalPortion, loanTransaction.interestPortion, loanTransaction.amount, loanTransaction.principalPortion, loanTransaction.interestPortion,
loanTransaction.feeChargesPortion, loanTransaction.penaltyChargesPortion, loanTransaction.overPaymentPortion, loanTransaction.feeChargesPortion, loanTransaction.penaltyChargesPortion, loanTransaction.overPaymentPortion,
loanTransaction.reversed, loanTransaction.paymentDetail, loanTransaction.externalId); loanTransaction.reversed, loanTransaction.paymentDetail, loanTransaction.externalId,
new LocalDateTime(loanTransaction.createdDate), loanTransaction.appUser);
} }
public static LoanTransaction accrueLoanCharge(final Loan loan, final Office office, final Money amount, final LocalDate applyDate, public static LoanTransaction accrueLoanCharge(final Loan loan, final Office office, final Money amount, final LocalDate applyDate,
final Money feeCharges, final Money penaltyCharges) { final Money feeCharges, final Money penaltyCharges, final LocalDateTime createdDate, final AppUser appUser) {
String externalId = null; String externalId = null;
final LoanTransaction applyCharge = new LoanTransaction(loan, office, LoanTransactionType.ACCRUAL, amount.getAmount(), applyDate, final LoanTransaction applyCharge = new LoanTransaction(loan, office, LoanTransactionType.ACCRUAL, amount.getAmount(), applyDate,
externalId); externalId, createdDate, appUser);
applyCharge.updateChargesComponents(feeCharges, penaltyCharges); applyCharge.updateChargesComponents(feeCharges, penaltyCharges);
return applyCharge; return applyCharge;
} }
@@ -222,7 +243,7 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
private LoanTransaction(final Loan loan, final Office office, final Integer typeOf, final Date dateOf, final BigDecimal amount, private LoanTransaction(final Loan loan, final Office office, final Integer typeOf, final Date dateOf, final BigDecimal amount,
final BigDecimal principalPortion, final BigDecimal interestPortion, final BigDecimal feeChargesPortion, final BigDecimal principalPortion, final BigDecimal interestPortion, final BigDecimal feeChargesPortion,
final BigDecimal penaltyChargesPortion, final BigDecimal overPaymentPortion, final boolean reversed, final BigDecimal penaltyChargesPortion, final BigDecimal overPaymentPortion, final boolean reversed,
final PaymentDetail paymentDetail, final String externalId) { final PaymentDetail paymentDetail, final String externalId, final LocalDateTime createdDate, final AppUser appUser) {
super(); super();
this.loan = loan; this.loan = loan;
this.typeOf = typeOf; this.typeOf = typeOf;
@@ -238,23 +259,27 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
this.office = office; this.office = office;
this.externalId = externalId; this.externalId = externalId;
this.submittedOnDate = DateUtils.getDateOfTenant(); this.submittedOnDate = DateUtils.getDateOfTenant();
this.createdDate = createdDate.toDate();
this.appUser = appUser;
} }
public static LoanTransaction waiveLoanCharge(final Loan loan, final Office office, final Money waived, final LocalDate waiveDate, public static LoanTransaction waiveLoanCharge(final Loan loan, final Office office, final Money waived, final LocalDate waiveDate,
final Money feeChargesWaived, final Money penaltyChargesWaived, final Money unrecognizedCharge) { final Money feeChargesWaived, final Money penaltyChargesWaived, final Money unrecognizedCharge,
final LocalDateTime createdDate, final AppUser appUser) {
final LoanTransaction waiver = new LoanTransaction(loan, office, LoanTransactionType.WAIVE_CHARGES, waived.getAmount(), waiveDate, final LoanTransaction waiver = new LoanTransaction(loan, office, LoanTransactionType.WAIVE_CHARGES, waived.getAmount(), waiveDate,
null); null, createdDate, appUser);
waiver.updateChargesComponents(feeChargesWaived, penaltyChargesWaived, unrecognizedCharge); waiver.updateChargesComponents(feeChargesWaived, penaltyChargesWaived, unrecognizedCharge);
return waiver; return waiver;
} }
public static LoanTransaction writeoff(final Loan loan, final Office office, final LocalDate writeOffDate, final String externalId) { public static LoanTransaction writeoff(final Loan loan, final Office office, final LocalDate writeOffDate, final String externalId,
return new LoanTransaction(loan, office, LoanTransactionType.WRITEOFF, null, writeOffDate, externalId); final LocalDateTime createdDate, final AppUser appUser) {
return new LoanTransaction(loan, office, LoanTransactionType.WRITEOFF, null, writeOffDate, externalId, createdDate, appUser);
} }
private LoanTransaction(final Loan loan, final Office office, final LoanTransactionType type, final BigDecimal amount, private LoanTransaction(final Loan loan, final Office office, final LoanTransactionType type, final BigDecimal amount,
final LocalDate date, final String externalId) { final LocalDate date, final String externalId, final LocalDateTime createdDate, final AppUser appUser) {
this.loan = loan; this.loan = loan;
this.typeOf = type.getValue(); this.typeOf = type.getValue();
this.amount = amount; this.amount = amount;
@@ -262,10 +287,12 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
this.externalId = externalId; this.externalId = externalId;
this.office = office; this.office = office;
this.submittedOnDate = DateUtils.getDateOfTenant(); this.submittedOnDate = DateUtils.getDateOfTenant();
this.createdDate = createdDate.toDate();
this.appUser = appUser;
} }
private LoanTransaction(final Loan loan, final Office office, final LoanTransactionType type, final PaymentDetail paymentDetail, private LoanTransaction(final Loan loan, final Office office, final LoanTransactionType type, final PaymentDetail paymentDetail,
final BigDecimal amount, final LocalDate date, final String externalId) { final BigDecimal amount, final LocalDate date, final String externalId, final LocalDateTime createdDate, final AppUser appUser) {
this.loan = loan; this.loan = loan;
this.typeOf = type.getValue(); this.typeOf = type.getValue();
this.paymentDetail = paymentDetail; this.paymentDetail = paymentDetail;
@@ -274,6 +301,8 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
this.externalId = externalId; this.externalId = externalId;
this.office = office; this.office = office;
this.submittedOnDate = DateUtils.getDateOfTenant(); this.submittedOnDate = DateUtils.getDateOfTenant();
this.createdDate = createdDate.toDate();
this.appUser = appUser;
} }
public void reverse() { public void reverse() {
@@ -16,6 +16,7 @@ import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.infrastructure.core.service.DateUtils;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
@@ -169,7 +170,8 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
modifiedTransactions.add(LoanTransaction.copyTransactionProperties(loanTransaction)); modifiedTransactions.add(LoanTransaction.copyTransactionProperties(loanTransaction));
} }
if (isNewPaymentRequired) { if (isNewPaymentRequired) {
LoanTransaction ondayPaymentTransaction = LoanTransaction.repayment(null, totalAmount, null, LocalDate.now(), null); LoanTransaction ondayPaymentTransaction = LoanTransaction.repayment(null, totalAmount, null, LocalDate.now(), null,
DateUtils.getLocalDateTimeOfTenant(), null);
modifiedTransactions.add(ondayPaymentTransaction); modifiedTransactions.add(ondayPaymentTransaction);
} }
@@ -360,7 +360,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
public CommandProcessingResult modifyApplication(final Long loanId, final JsonCommand command) { public CommandProcessingResult modifyApplication(final Long loanId, final JsonCommand command) {
try { try {
this.context.authenticatedUser(); AppUser currentUser = this.context.authenticatedUser();
this.fromApiJsonDeserializer.validateForModify(command.json()); this.fromApiJsonDeserializer.validateForModify(command.json());
@@ -522,7 +522,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
final JsonQuery query = JsonQuery.from(command.json(), parsedQuery, this.fromJsonHelper); final JsonQuery query = JsonQuery.from(command.json(), parsedQuery, this.fromJsonHelper);
final LoanScheduleModel loanSchedule = this.calculationPlatformService.calculateLoanSchedule(query, false); final LoanScheduleModel loanSchedule = this.calculationPlatformService.calculateLoanSchedule(query, false);
existingLoanApplication.updateLoanSchedule(loanSchedule); existingLoanApplication.updateLoanSchedule(loanSchedule, currentUser);
existingLoanApplication.recalculateAllCharges(); existingLoanApplication.recalculateAllCharges();
} }
@@ -736,7 +736,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
// to recompute the schedule // to recompute the schedule
if (changes.containsKey(LoanApiConstants.approvedLoanAmountParameterName)) { if (changes.containsKey(LoanApiConstants.approvedLoanAmountParameterName)) {
ScheduleGeneratorDTO scheduleGeneratorDTO = loanAccountDomainService.buildScheduleGeneratorDTO(loan); ScheduleGeneratorDTO scheduleGeneratorDTO = loanAccountDomainService.buildScheduleGeneratorDTO(loan);
loan.regenerateRepaymentSchedule(scheduleGeneratorDTO); loan.regenerateRepaymentSchedule(scheduleGeneratorDTO, currentUser);
} }
this.loanRepository.save(loan); this.loanRepository.save(loan);
@@ -764,7 +764,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
@Override @Override
public CommandProcessingResult undoApplicationApproval(final Long loanId, final JsonCommand command) { public CommandProcessingResult undoApplicationApproval(final Long loanId, final JsonCommand command) {
this.context.authenticatedUser(); AppUser currentUser = this.context.authenticatedUser();
this.fromApiJsonDeserializer.validateForUndo(command.json()); this.fromApiJsonDeserializer.validateForUndo(command.json());
@@ -780,7 +780,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
if (changes.containsKey(LoanApiConstants.approvedLoanAmountParameterName) if (changes.containsKey(LoanApiConstants.approvedLoanAmountParameterName)
|| changes.containsKey(LoanApiConstants.disbursementPrincipalParameterName )) { || changes.containsKey(LoanApiConstants.disbursementPrincipalParameterName )) {
ScheduleGeneratorDTO scheduleGeneratorDTO = loanAccountDomainService.buildScheduleGeneratorDTO(loan); ScheduleGeneratorDTO scheduleGeneratorDTO = loanAccountDomainService.buildScheduleGeneratorDTO(loan);
loan.regenerateRepaymentSchedule(scheduleGeneratorDTO); loan.regenerateRepaymentSchedule(scheduleGeneratorDTO, currentUser);
} }
this.loanRepository.save(loan); this.loanRepository.save(loan);
@@ -405,7 +405,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
@Override @Override
public LoanTransactionData retrieveWaiveInterestDetails(final Long loanId) { public LoanTransactionData retrieveWaiveInterestDetails(final Long loanId) {
this.context.authenticatedUser(); AppUser currentUser = this.context.authenticatedUser();
// TODO - KW -OPTIMIZE - write simple sql query to fetch back overdue // TODO - KW -OPTIMIZE - write simple sql query to fetch back overdue
// interest that can be waived along with the date of repayment period // interest that can be waived along with the date of repayment period
@@ -417,7 +417,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency); final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
final CurrencyData currencyData = applicationCurrency.toData(); final CurrencyData currencyData = applicationCurrency.toData();
final LoanTransaction waiveOfInterest = loan.deriveDefaultInterestWaiverTransaction(); final LoanTransaction waiveOfInterest = loan.deriveDefaultInterestWaiverTransaction(
DateUtils.getLocalDateTimeOfTenant(), currentUser);
final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.WAIVE_INTEREST); final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.WAIVE_INTEREST);
@@ -32,6 +32,7 @@ import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRul
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
import org.mifosplatform.infrastructure.core.exception.PlatformServiceUnavailableException; import org.mifosplatform.infrastructure.core.exception.PlatformServiceUnavailableException;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.infrastructure.core.service.DateUtils;
import org.mifosplatform.infrastructure.jobs.annotation.CronTarget; import org.mifosplatform.infrastructure.jobs.annotation.CronTarget;
import org.mifosplatform.infrastructure.jobs.exception.JobExecutionException; import org.mifosplatform.infrastructure.jobs.exception.JobExecutionException;
import org.mifosplatform.infrastructure.jobs.service.JobName; import org.mifosplatform.infrastructure.jobs.service.JobName;
@@ -316,7 +317,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
existingTransactionIds.addAll(loan.findExistingTransactionIds()); existingTransactionIds.addAll(loan.findExistingTransactionIds());
existingReversedTransactionIds.addAll(loan.findExistingReversedTransactionIds()); existingReversedTransactionIds.addAll(loan.findExistingReversedTransactionIds());
LoanTransaction disbursementTransaction = LoanTransaction.disbursement(loan.getOffice(), disburseAmount, paymentDetail, LoanTransaction disbursementTransaction = LoanTransaction.disbursement(loan.getOffice(), disburseAmount, paymentDetail,
actualDisbursementDate, txnExternalId); actualDisbursementDate, txnExternalId, DateUtils.getLocalDateTimeOfTenant(), currentUser);
disbursementTransaction.updateLoan(loan); disbursementTransaction.updateLoan(loan);
loan.getLoanTransactions().add(disbursementTransaction); loan.getLoanTransactions().add(disbursementTransaction);
} }
@@ -565,7 +566,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
existingTransactionIds.addAll(loan.findExistingTransactionIds()); existingTransactionIds.addAll(loan.findExistingTransactionIds());
existingReversedTransactionIds.addAll(loan.findExistingReversedTransactionIds()); existingReversedTransactionIds.addAll(loan.findExistingReversedTransactionIds());
LoanTransaction disbursementTransaction = LoanTransaction.disbursement(loan.getOffice(), disburseAmount, paymentDetail, LoanTransaction disbursementTransaction = LoanTransaction.disbursement(loan.getOffice(), disburseAmount, paymentDetail,
actualDisbursementDate, txnExternalId); actualDisbursementDate, txnExternalId, DateUtils.getLocalDateTimeOfTenant(), currentUser);
disbursementTransaction.updateLoan(loan); disbursementTransaction.updateLoan(loan);
loan.getLoanTransactions().add(disbursementTransaction); loan.getLoanTransactions().add(disbursementTransaction);
} }
@@ -641,6 +642,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@Override @Override
public CommandProcessingResult undoLoanDisbursal(final Long loanId, final JsonCommand command) { public CommandProcessingResult undoLoanDisbursal(final Long loanId, final JsonCommand command) {
final AppUser currentUser = this.context.authenticatedUser();
final Loan loan = this.loanAssembler.assembleFrom(loanId); final Loan loan = this.loanAssembler.assembleFrom(loanId);
checkClientOrGroupActive(loan); checkClientOrGroupActive(loan);
removeLoanCycle(loan); removeLoanCycle(loan);
@@ -668,7 +671,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
calculatedRepaymentsStartingFromDate, holidayDetailDTO); calculatedRepaymentsStartingFromDate, holidayDetailDTO);
final Map<String, Object> changes = loan final Map<String, Object> changes = loan
.undoDisbursal(scheduleGeneratorDTO, existingTransactionIds, existingReversedTransactionIds); .undoDisbursal(scheduleGeneratorDTO, existingTransactionIds, existingReversedTransactionIds, currentUser);
if (!changes.isEmpty()) { if (!changes.isEmpty()) {
saveAndFlushLoanWithDataIntegrityViolationChecks(loan); saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
@@ -702,7 +705,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@Override @Override
public CommandProcessingResult makeLoanRepayment(final Long loanId, final JsonCommand command, final boolean isRecoveryRepayment) { public CommandProcessingResult makeLoanRepayment(final Long loanId, final JsonCommand command, final boolean isRecoveryRepayment) {
this.context.authenticatedUser(); AppUser currentUser = null;
if (this.context != null) {
currentUser = this.context.authenticatedUser();
}
this.loanEventApiJsonValidator.validateNewRepaymentTransaction(command.json()); this.loanEventApiJsonValidator.validateNewRepaymentTransaction(command.json());
@@ -727,7 +733,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
boolean isAccountTransfer = false; boolean isAccountTransfer = false;
final CommandProcessingResultBuilder commandProcessingResultBuilder = new CommandProcessingResultBuilder(); final CommandProcessingResultBuilder commandProcessingResultBuilder = new CommandProcessingResultBuilder();
this.loanAccountDomainService.makeRepayment(loan, commandProcessingResultBuilder, transactionDate, transactionAmount, this.loanAccountDomainService.makeRepayment(loan, commandProcessingResultBuilder, transactionDate, transactionAmount,
paymentDetail, noteText, txnExternalId, isRecoveryRepayment, isAccountTransfer); paymentDetail, noteText, txnExternalId, isRecoveryRepayment, isAccountTransfer, currentUser);
return commandProcessingResultBuilder.withCommandId(command.commandId()) // return commandProcessingResultBuilder.withCommandId(command.commandId()) //
.withLoanId(loanId) // .withLoanId(loanId) //
@@ -739,7 +745,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@Override @Override
public Map<String, Object> makeLoanBulkRepayment(final CollectionSheetBulkRepaymentCommand bulkRepaymentCommand) { public Map<String, Object> makeLoanBulkRepayment(final CollectionSheetBulkRepaymentCommand bulkRepaymentCommand) {
this.context.authenticatedUser(); AppUser currentUser = this.context.authenticatedUser();
final SingleRepaymentCommand[] repaymentCommand = bulkRepaymentCommand.getLoanTransactions(); final SingleRepaymentCommand[] repaymentCommand = bulkRepaymentCommand.getLoanTransactions();
final Map<String, Object> changes = new LinkedHashMap<>(); final Map<String, Object> changes = new LinkedHashMap<>();
final boolean isRecoveryRepayment = false; final boolean isRecoveryRepayment = false;
@@ -756,7 +762,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final CommandProcessingResultBuilder commandProcessingResultBuilder = new CommandProcessingResultBuilder(); final CommandProcessingResultBuilder commandProcessingResultBuilder = new CommandProcessingResultBuilder();
this.loanAccountDomainService.makeRepayment(loan, commandProcessingResultBuilder, bulkRepaymentCommand.getTransactionDate(), this.loanAccountDomainService.makeRepayment(loan, commandProcessingResultBuilder, bulkRepaymentCommand.getTransactionDate(),
singleLoanRepaymentCommand.getTransactionAmount(), paymentDetail, bulkRepaymentCommand.getNote(), null, singleLoanRepaymentCommand.getTransactionAmount(), paymentDetail, bulkRepaymentCommand.getNote(), null,
isRecoveryRepayment, isAccountTransfer); isRecoveryRepayment, isAccountTransfer, currentUser);
changes.put("bulkTransactions", singleLoanRepaymentCommand); changes.put("bulkTransactions", singleLoanRepaymentCommand);
} }
@@ -767,7 +773,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@Override @Override
public CommandProcessingResult adjustLoanTransaction(final Long loanId, final Long transactionId, final JsonCommand command) { public CommandProcessingResult adjustLoanTransaction(final Long loanId, final Long transactionId, final JsonCommand command) {
this.context.authenticatedUser(); AppUser currentUser = null;
if (this.context != null) {
currentUser = this.context.authenticatedUser();
}
this.loanEventApiJsonValidator.validateTransaction(command.json()); this.loanEventApiJsonValidator.validateTransaction(command.json());
@@ -800,7 +809,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final Money transactionAmountAsMoney = Money.of(loan.getCurrency(), transactionAmount); final Money transactionAmountAsMoney = Money.of(loan.getCurrency(), transactionAmount);
final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createPaymentDetail(command, changes); final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createPaymentDetail(command, changes);
LoanTransaction newTransactionDetail = LoanTransaction.repayment(loan.getOffice(), transactionAmountAsMoney, paymentDetail, LoanTransaction newTransactionDetail = LoanTransaction.repayment(loan.getOffice(), transactionAmountAsMoney, paymentDetail,
transactionDate, txnExternalId); transactionDate, txnExternalId, DateUtils.getLocalDateTimeOfTenant(), currentUser);
if (transactionToAdjust.isInterestWaiver()) { if (transactionToAdjust.isInterestWaiver()) {
Money unrecognizedIncome = transactionAmountAsMoney.zero(); Money unrecognizedIncome = transactionAmountAsMoney.zero();
Money interestComponent = transactionAmountAsMoney; Money interestComponent = transactionAmountAsMoney;
@@ -812,7 +821,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
} }
} }
newTransactionDetail = LoanTransaction.waiver(loan.getOffice(), loan, transactionAmountAsMoney, transactionDate, newTransactionDetail = LoanTransaction.waiver(loan.getOffice(), loan, transactionAmountAsMoney, transactionDate,
interestComponent, unrecognizedIncome); interestComponent, unrecognizedIncome, DateUtils.getLocalDateTimeOfTenant(), currentUser);
} }
final boolean allowTransactionsOnHoliday = this.configurationDomainService.allowTransactionsOnHolidayEnabled(); final boolean allowTransactionsOnHoliday = this.configurationDomainService.allowTransactionsOnHolidayEnabled();
@@ -852,7 +861,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final ChangedTransactionDetail changedTransactionDetail = loan.adjustExistingTransaction(newTransactionDetail, final ChangedTransactionDetail changedTransactionDetail = loan.adjustExistingTransaction(newTransactionDetail,
defaultLoanLifecycleStateMachine(), transactionToAdjust, existingTransactionIds, existingReversedTransactionIds, defaultLoanLifecycleStateMachine(), transactionToAdjust, existingTransactionIds, existingReversedTransactionIds,
scheduleGeneratorDTO); scheduleGeneratorDTO, currentUser);
if (newTransactionDetail.isGreaterThanZero(loan.getPrincpal().getCurrency())) { if (newTransactionDetail.isGreaterThanZero(loan.getPrincpal().getCurrency())) {
if (paymentDetail != null) { if (paymentDetail != null) {
@@ -914,7 +923,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@Override @Override
public CommandProcessingResult waiveInterestOnLoan(final Long loanId, final JsonCommand command) { public CommandProcessingResult waiveInterestOnLoan(final Long loanId, final JsonCommand command) {
this.context.authenticatedUser(); AppUser currentUser = this.context.authenticatedUser();
this.loanEventApiJsonValidator.validateTransaction(command.json()); this.loanEventApiJsonValidator.validateTransaction(command.json());
@@ -943,7 +952,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
} }
} }
final LoanTransaction waiveInterestTransaction = LoanTransaction.waiver(loan.getOffice(), loan, transactionAmountAsMoney, final LoanTransaction waiveInterestTransaction = LoanTransaction.waiver(loan.getOffice(), loan, transactionAmountAsMoney,
transactionDate, interestComponent, unrecognizedIncome); transactionDate, interestComponent, unrecognizedIncome, DateUtils.getLocalDateTimeOfTenant(), currentUser);
CalendarInstance restCalendarInstance = null; CalendarInstance restCalendarInstance = null;
ApplicationCurrency applicationCurrency = null; ApplicationCurrency applicationCurrency = null;
@@ -976,7 +985,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, recalculateFrom, overdurPenaltyWaitPeriod, calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, recalculateFrom, overdurPenaltyWaitPeriod,
lastTransactionDate); lastTransactionDate);
final ChangedTransactionDetail changedTransactionDetail = loan.waiveInterest(waiveInterestTransaction, final ChangedTransactionDetail changedTransactionDetail = loan.waiveInterest(waiveInterestTransaction,
defaultLoanLifecycleStateMachine(), existingTransactionIds, existingReversedTransactionIds, scheduleGeneratorDTO); defaultLoanLifecycleStateMachine(), existingTransactionIds, existingReversedTransactionIds, scheduleGeneratorDTO,
currentUser);
this.loanTransactionRepository.save(waiveInterestTransaction); this.loanTransactionRepository.save(waiveInterestTransaction);
@@ -1096,7 +1106,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@Override @Override
public CommandProcessingResult closeLoan(final Long loanId, final JsonCommand command) { public CommandProcessingResult closeLoan(final Long loanId, final JsonCommand command) {
this.context.authenticatedUser(); AppUser currentUser = this.context.authenticatedUser();
this.loanEventApiJsonValidator.validateTransactionWithNoAmount(command.json()); this.loanEventApiJsonValidator.validateTransactionWithNoAmount(command.json());
@@ -1140,7 +1150,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, recalculateFrom, overdurPenaltyWaitPeriod, calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, recalculateFrom, overdurPenaltyWaitPeriod,
lastTransactionDate); lastTransactionDate);
ChangedTransactionDetail changedTransactionDetail = loan.close(command, defaultLoanLifecycleStateMachine(), changes, ChangedTransactionDetail changedTransactionDetail = loan.close(command, defaultLoanLifecycleStateMachine(), changes,
existingTransactionIds, existingReversedTransactionIds, scheduleGeneratorDTO); existingTransactionIds, existingReversedTransactionIds, scheduleGeneratorDTO, currentUser);
final LoanTransaction possibleClosingTransaction = changedTransactionDetail.getNewTransactionMappings().remove(0L); final LoanTransaction possibleClosingTransaction = changedTransactionDetail.getNewTransactionMappings().remove(0L);
if (possibleClosingTransaction != null) { if (possibleClosingTransaction != null) {
this.loanTransactionRepository.save(possibleClosingTransaction); this.loanTransactionRepository.save(possibleClosingTransaction);
@@ -1300,6 +1310,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
} }
public void runScheduleRecalculation(Loan loan) { public void runScheduleRecalculation(Loan loan) {
AppUser currentUser = null;
if (this.context != null) {
currentUser = this.context.authenticatedUser();
}
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) { if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
CalendarInstance restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId( CalendarInstance restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue()); loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
@@ -1325,7 +1339,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, recalculateFrom, calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, recalculateFrom,
overdurPenaltyWaitPeriod, lastTransactionDate); overdurPenaltyWaitPeriod, lastTransactionDate);
ChangedTransactionDetail changedTransactionDetail = loan ChangedTransactionDetail changedTransactionDetail = loan
.handleRegenerateRepaymentScheduleWithInterestRecalculation(generatorDTO); .handleRegenerateRepaymentScheduleWithInterestRecalculation(generatorDTO, currentUser);
saveLoanWithDataIntegrityViolationChecks(loan); saveLoanWithDataIntegrityViolationChecks(loan);
if (changedTransactionDetail != null) { if (changedTransactionDetail != null) {
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) { for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
@@ -1365,6 +1379,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private boolean addCharge(final Loan loan, final Charge chargeDefinition, final LoanCharge loanCharge) { private boolean addCharge(final Loan loan, final Charge chargeDefinition, final LoanCharge loanCharge) {
AppUser currentUser = null;
if (this.context != null) {
currentUser = this.context.authenticatedUser();
}
if (!loan.hasCurrencyCodeOf(chargeDefinition.getCurrencyCode())) { if (!loan.hasCurrencyCodeOf(chargeDefinition.getCurrencyCode())) {
final String errorMessage = "Charge and Loan must have the same currency."; final String errorMessage = "Charge and Loan must have the same currency.";
throw new InvalidCurrencyException("loanCharge", "attach.to.loan", errorMessage); throw new InvalidCurrencyException("loanCharge", "attach.to.loan", errorMessage);
@@ -1390,7 +1408,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
**/ **/
if (loan.status().isActive()) { if (loan.status().isActive()) {
if (loan.isNoneOrCashOrUpfrontAccrualAccountingEnabledOnLoanProduct()) { if (loan.isNoneOrCashOrUpfrontAccrualAccountingEnabledOnLoanProduct()) {
final LoanTransaction applyLoanChargeTransaction = loan.handleChargeAppliedTransaction(loanCharge, null); final LoanTransaction applyLoanChargeTransaction = loan.handleChargeAppliedTransaction(loanCharge, null, currentUser);
this.loanTransactionRepository.save(applyLoanChargeTransaction); this.loanTransactionRepository.save(applyLoanChargeTransaction);
} }
/*** /***
@@ -1455,7 +1473,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@Override @Override
public CommandProcessingResult waiveLoanCharge(final Long loanId, final Long loanChargeId, final JsonCommand command) { public CommandProcessingResult waiveLoanCharge(final Long loanId, final Long loanChargeId, final JsonCommand command) {
this.context.authenticatedUser(); AppUser currentUser = this.context.authenticatedUser();
final Loan loan = this.loanAssembler.assembleFrom(loanId); final Loan loan = this.loanAssembler.assembleFrom(loanId);
checkClientOrGroupActive(loan); checkClientOrGroupActive(loan);
@@ -1539,7 +1557,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
} }
final LoanTransaction waiveTransaction = loan.waiveLoanCharge(loanCharge, defaultLoanLifecycleStateMachine(), changes, final LoanTransaction waiveTransaction = loan.waiveLoanCharge(loanCharge, defaultLoanLifecycleStateMachine(), changes,
existingTransactionIds, existingReversedTransactionIds, loanInstallmentNumber, scheduleGeneratorDTO, accruedCharge); existingTransactionIds, existingReversedTransactionIds, loanInstallmentNumber, scheduleGeneratorDTO, accruedCharge,
currentUser);
this.loanTransactionRepository.save(waiveTransaction); this.loanTransactionRepository.save(waiveTransaction);
saveLoanWithDataIntegrityViolationChecks(loan); saveLoanWithDataIntegrityViolationChecks(loan);
@@ -1758,6 +1777,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@Transactional @Transactional
@Override @Override
public LoanTransaction initiateLoanTransfer(final Long accountId, final LocalDate transferDate) { public LoanTransaction initiateLoanTransfer(final Long accountId, final LocalDate transferDate) {
AppUser currentUser = null;
if (this.context != null) {
currentUser = this.context.authenticatedUser();
}
final Loan loan = this.loanAssembler.assembleFrom(accountId); final Loan loan = this.loanAssembler.assembleFrom(accountId);
checkClientOrGroupActive(loan); checkClientOrGroupActive(loan);
@@ -1765,7 +1789,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final List<Long> existingTransactionIds = new ArrayList<>(loan.findExistingTransactionIds()); final List<Long> existingTransactionIds = new ArrayList<>(loan.findExistingTransactionIds());
final List<Long> existingReversedTransactionIds = new ArrayList<>(loan.findExistingReversedTransactionIds()); final List<Long> existingReversedTransactionIds = new ArrayList<>(loan.findExistingReversedTransactionIds());
final LoanTransaction newTransferTransaction = LoanTransaction.initiateTransfer(loan.getOffice(), loan, transferDate); final LoanTransaction newTransferTransaction = LoanTransaction.initiateTransfer(loan.getOffice(), loan, transferDate,
DateUtils.getLocalDateTimeOfTenant(), currentUser);
loan.getLoanTransactions().add(newTransferTransaction); loan.getLoanTransactions().add(newTransferTransaction);
loan.setLoanStatus(LoanStatus.TRANSFER_IN_PROGRESS.getValue()); loan.setLoanStatus(LoanStatus.TRANSFER_IN_PROGRESS.getValue());
@@ -1781,13 +1806,19 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@Override @Override
public LoanTransaction acceptLoanTransfer(final Long accountId, final LocalDate transferDate, final Office acceptedInOffice, public LoanTransaction acceptLoanTransfer(final Long accountId, final LocalDate transferDate, final Office acceptedInOffice,
final Staff loanOfficer) { final Staff loanOfficer) {
AppUser currentUser = null;
if (this.context != null) {
currentUser = this.context.authenticatedUser();
}
final Loan loan = this.loanAssembler.assembleFrom(accountId); final Loan loan = this.loanAssembler.assembleFrom(accountId);
final List<Long> existingTransactionIds = new ArrayList<>(loan.findExistingTransactionIds()); final List<Long> existingTransactionIds = new ArrayList<>(loan.findExistingTransactionIds());
final List<Long> existingReversedTransactionIds = new ArrayList<>(loan.findExistingReversedTransactionIds()); final List<Long> existingReversedTransactionIds = new ArrayList<>(loan.findExistingReversedTransactionIds());
final LoanTransaction newTransferAcceptanceTransaction = LoanTransaction.approveTransfer(acceptedInOffice, loan, transferDate); final LoanTransaction newTransferAcceptanceTransaction = LoanTransaction.approveTransfer(acceptedInOffice, loan, transferDate,
DateUtils.getLocalDateTimeOfTenant(), currentUser);
loan.getLoanTransactions().add(newTransferAcceptanceTransaction); loan.getLoanTransactions().add(newTransferAcceptanceTransaction);
if (loan.getTotalOverpaid() != null) { if (loan.getTotalOverpaid() != null) {
loan.setLoanStatus(LoanStatus.OVERPAID.getValue()); loan.setLoanStatus(LoanStatus.OVERPAID.getValue());
@@ -1809,12 +1840,19 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@Transactional @Transactional
@Override @Override
public LoanTransaction withdrawLoanTransfer(final Long accountId, final LocalDate transferDate) { public LoanTransaction withdrawLoanTransfer(final Long accountId, final LocalDate transferDate) {
AppUser currentUser = null;
if (this.context != null) {
currentUser = this.context.authenticatedUser();
}
final Loan loan = this.loanAssembler.assembleFrom(accountId); final Loan loan = this.loanAssembler.assembleFrom(accountId);
final List<Long> existingTransactionIds = new ArrayList<>(loan.findExistingTransactionIds()); final List<Long> existingTransactionIds = new ArrayList<>(loan.findExistingTransactionIds());
final List<Long> existingReversedTransactionIds = new ArrayList<>(loan.findExistingReversedTransactionIds()); final List<Long> existingReversedTransactionIds = new ArrayList<>(loan.findExistingReversedTransactionIds());
final LoanTransaction newTransferAcceptanceTransaction = LoanTransaction.withdrawTransfer(loan.getOffice(), loan, transferDate); final LoanTransaction newTransferAcceptanceTransaction = LoanTransaction.withdrawTransfer(loan.getOffice(), loan, transferDate,
DateUtils.getLocalDateTimeOfTenant(), currentUser);
loan.getLoanTransactions().add(newTransferAcceptanceTransaction); loan.getLoanTransactions().add(newTransferAcceptanceTransaction);
loan.setLoanStatus(LoanStatus.ACTIVE.getValue()); loan.setLoanStatus(LoanStatus.ACTIVE.getValue());
@@ -2355,6 +2393,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@Override @Override
public CommandProcessingResult undoWriteOff(Long loanId) { public CommandProcessingResult undoWriteOff(Long loanId) {
final AppUser currentUser = this.context.authenticatedUser();
final Loan loan = this.loanAssembler.assembleFrom(loanId); final Loan loan = this.loanAssembler.assembleFrom(loanId);
checkClientOrGroupActive(loan); checkClientOrGroupActive(loan);
final List<Long> existingTransactionIds = new ArrayList<>(); final List<Long> existingTransactionIds = new ArrayList<>();
@@ -2395,7 +2435,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
lastTransactionDate); lastTransactionDate);
ChangedTransactionDetail changedTransactionDetail = loan.undoWrittenOff(existingTransactionIds, existingReversedTransactionIds, ChangedTransactionDetail changedTransactionDetail = loan.undoWrittenOff(existingTransactionIds, existingReversedTransactionIds,
scheduleGeneratorDTO); scheduleGeneratorDTO, currentUser);
if (changedTransactionDetail != null) { if (changedTransactionDetail != null) {
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) { for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
this.loanTransactionRepository.save(mapEntry.getValue()); this.loanTransactionRepository.save(mapEntry.getValue());
@@ -2417,6 +2457,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@Override @Override
@Transactional @Transactional
public CommandProcessingResult updateDisbursementDateForTranche(final Long loanId, final Long disbursementId, final JsonCommand command) { public CommandProcessingResult updateDisbursementDateForTranche(final Long loanId, final Long disbursementId, final JsonCommand command) {
AppUser currentUser = this.context.authenticatedUser();
final Loan loan = this.loanAssembler.assembleFrom(loanId); final Loan loan = this.loanAssembler.assembleFrom(loanId);
checkClientOrGroupActive(loan); checkClientOrGroupActive(loan);
@@ -2452,7 +2494,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
lastTransactionDate); lastTransactionDate);
final ChangedTransactionDetail changedTransactionDetail = loan.updateDisbursementDateForTranche(loanDisbursementDetails, command, final ChangedTransactionDetail changedTransactionDetail = loan.updateDisbursementDateForTranche(loanDisbursementDetails, command,
existingTransactionIds, existingReversedTransactionIds, changes, scheduleGeneratorDTO); existingTransactionIds, existingReversedTransactionIds, changes, scheduleGeneratorDTO, currentUser);
saveAndFlushLoanWithDataIntegrityViolationChecks(loan); saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
@@ -2555,6 +2597,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@Transactional @Transactional
public void recalculateInterest(final long loanId) { public void recalculateInterest(final long loanId) {
AppUser currentUser = null;
if (this.context != null) {
currentUser = this.context.authenticatedUser();
}
Loan loan = this.loanAssembler.assembleFrom(loanId); Loan loan = this.loanAssembler.assembleFrom(loanId);
CalendarInstance restCalendarInstance = null; CalendarInstance restCalendarInstance = null;
ApplicationCurrency applicationCurrency = null; ApplicationCurrency applicationCurrency = null;
@@ -2589,7 +2635,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
lastTransactionDate); lastTransactionDate);
ChangedTransactionDetail changedTransactionDetail = loan.recalculateScheduleFromLastTransaction(generatorDTO, ChangedTransactionDetail changedTransactionDetail = loan.recalculateScheduleFromLastTransaction(generatorDTO,
existingTransactionIds, existingReversedTransactionIds); existingTransactionIds, existingReversedTransactionIds, currentUser);
saveLoanWithDataIntegrityViolationChecks(loan); saveLoanWithDataIntegrityViolationChecks(loan);
@@ -2620,9 +2666,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private void regenerateScheduleOnDisbursement(final JsonCommand command, final Loan loan, final boolean recalculateSchedule, private void regenerateScheduleOnDisbursement(final JsonCommand command, final Loan loan, final boolean recalculateSchedule,
final ScheduleGeneratorDTO scheduleGeneratorDTO) { final ScheduleGeneratorDTO scheduleGeneratorDTO) {
AppUser currentUser = this.context.authenticatedUser();
final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate"); final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate");
BigDecimal emiAmount = command.bigDecimalValueOfParameterNamed(LoanApiConstants.emiAmountParameterName); BigDecimal emiAmount = command.bigDecimalValueOfParameterNamed(LoanApiConstants.emiAmountParameterName);
loan.regenerateScheduleOnDisbursement(scheduleGeneratorDTO, recalculateSchedule, actualDisbursementDate, emiAmount); loan.regenerateScheduleOnDisbursement(scheduleGeneratorDTO, recalculateSchedule, actualDisbursementDate, emiAmount,
currentUser);
} }
private List<LoanRepaymentScheduleInstallment> retrieveRepaymentScheduleFromModel(LoanScheduleModel model) { private List<LoanRepaymentScheduleInstallment> retrieveRepaymentScheduleFromModel(LoanScheduleModel model) {
@@ -11,6 +11,7 @@ import java.util.Date;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatter;
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail; import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
import org.mifosplatform.useradministration.domain.AppUser;
public class SavingsAccountTransactionDTO { public class SavingsAccountTransactionDTO {
@@ -20,15 +21,18 @@ public class SavingsAccountTransactionDTO {
private final PaymentDetail paymentDetail; private final PaymentDetail paymentDetail;
private final Date createdDate; private final Date createdDate;
private final Long savingsAccountId; private final Long savingsAccountId;
private final AppUser appUser;
public SavingsAccountTransactionDTO(final DateTimeFormatter formatter, final LocalDate transactionDate, public SavingsAccountTransactionDTO(final DateTimeFormatter formatter, final LocalDate transactionDate,
final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final Date createdDate) { final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final Date createdDate,
final AppUser appUser) {
this.formatter = formatter; this.formatter = formatter;
this.transactionDate = transactionDate; this.transactionDate = transactionDate;
this.transactionAmount = transactionAmount; this.transactionAmount = transactionAmount;
this.paymentDetail = paymentDetail; this.paymentDetail = paymentDetail;
this.createdDate = createdDate; this.createdDate = createdDate;
this.savingsAccountId = null; this.savingsAccountId = null;
this.appUser = appUser;
} }
/** /**
@@ -42,13 +46,14 @@ public class SavingsAccountTransactionDTO {
* @param savingsAccountId * @param savingsAccountId
*/ */
public SavingsAccountTransactionDTO(DateTimeFormatter formatter, LocalDate transactionDate, BigDecimal transactionAmount, public SavingsAccountTransactionDTO(DateTimeFormatter formatter, LocalDate transactionDate, BigDecimal transactionAmount,
PaymentDetail paymentDetail, Date createdDate, Long savingsAccountId) { PaymentDetail paymentDetail, Date createdDate, Long savingsAccountId, AppUser appUser) {
this.formatter = formatter; this.formatter = formatter;
this.transactionDate = transactionDate; this.transactionDate = transactionDate;
this.transactionAmount = transactionAmount; this.transactionAmount = transactionAmount;
this.paymentDetail = paymentDetail; this.paymentDetail = paymentDetail;
this.createdDate = createdDate; this.createdDate = createdDate;
this.savingsAccountId = savingsAccountId; this.savingsAccountId = savingsAccountId;
this.appUser = appUser;
} }
public DateTimeFormatter getFormatter() { public DateTimeFormatter getFormatter() {
@@ -74,5 +79,9 @@ public class SavingsAccountTransactionDTO {
public Long getSavingsAccountId() { public Long getSavingsAccountId() {
return this.savingsAccountId; return this.savingsAccountId;
} }
public AppUser getAppUser() {
return this.appUser;
}
} }
@@ -52,6 +52,7 @@ import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.infrastructure.core.service.DateUtils; import org.mifosplatform.infrastructure.core.service.DateUtils;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.organisation.staff.domain.Staff; import org.mifosplatform.organisation.staff.domain.Staff;
import org.mifosplatform.organisation.staff.domain.StaffRepositoryWrapper; import org.mifosplatform.organisation.staff.domain.StaffRepositoryWrapper;
import org.mifosplatform.portfolio.account.service.AccountTransfersReadPlatformService; import org.mifosplatform.portfolio.account.service.AccountTransfersReadPlatformService;
@@ -88,6 +89,7 @@ import com.google.gson.JsonObject;
@Service @Service
public class DepositAccountAssembler { public class DepositAccountAssembler {
private final PlatformSecurityContext context;
private final SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper; private final SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper;
private final SavingsHelper savingsHelper; private final SavingsHelper savingsHelper;
private final ClientRepositoryWrapper clientRepository; private final ClientRepositoryWrapper clientRepository;
@@ -108,7 +110,8 @@ public class DepositAccountAssembler {
final SavingsAccountChargeAssembler savingsAccountChargeAssembler, final FromJsonHelper fromApiJsonHelper, final SavingsAccountChargeAssembler savingsAccountChargeAssembler, final FromJsonHelper fromApiJsonHelper,
final DepositProductAssembler depositProductAssembler, final DepositProductAssembler depositProductAssembler,
final RecurringDepositProductRepository recurringDepositProductRepository, final RecurringDepositProductRepository recurringDepositProductRepository,
final AccountTransfersReadPlatformService accountTransfersReadPlatformService) { final AccountTransfersReadPlatformService accountTransfersReadPlatformService,
final PlatformSecurityContext context) {
this.savingsAccountTransactionSummaryWrapper = savingsAccountTransactionSummaryWrapper; this.savingsAccountTransactionSummaryWrapper = savingsAccountTransactionSummaryWrapper;
this.clientRepository = clientRepository; this.clientRepository = clientRepository;
@@ -121,6 +124,7 @@ public class DepositAccountAssembler {
this.depositProductAssembler = depositProductAssembler; this.depositProductAssembler = depositProductAssembler;
this.recurringDepositProductRepository = recurringDepositProductRepository; this.recurringDepositProductRepository = recurringDepositProductRepository;
this.savingsHelper = new SavingsHelper(accountTransfersReadPlatformService); this.savingsHelper = new SavingsHelper(accountTransfersReadPlatformService);
this.context = context;
} }
/** /**
@@ -390,6 +394,10 @@ public class DepositAccountAssembler {
} }
public Collection<SavingsAccountTransactionDTO> assembleBulkMandatorySavingsAccountTransactionDTOs(final JsonCommand command) { public Collection<SavingsAccountTransactionDTO> assembleBulkMandatorySavingsAccountTransactionDTOs(final JsonCommand command) {
AppUser user = null;
if (this.context != null) {
user = this.context.authenticatedUser();
}
final String json = command.json(); final String json = command.json();
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final JsonElement element = this.fromApiJsonHelper.parse(json); final JsonElement element = this.fromApiJsonHelper.parse(json);
@@ -412,7 +420,7 @@ public class DepositAccountAssembler {
final BigDecimal dueAmount = this.fromApiJsonHelper.extractBigDecimalNamed(transactionAmountParamName, final BigDecimal dueAmount = this.fromApiJsonHelper.extractBigDecimalNamed(transactionAmountParamName,
savingsTransactionElement, locale); savingsTransactionElement, locale);
final SavingsAccountTransactionDTO savingsAccountTransactionDTO = new SavingsAccountTransactionDTO(formatter, final SavingsAccountTransactionDTO savingsAccountTransactionDTO = new SavingsAccountTransactionDTO(formatter,
transactionDate, dueAmount, paymentDetail, new Date(), savingsId); transactionDate, dueAmount, paymentDetail, new Date(), savingsId, user);
savingsAccountTransactions.add(savingsAccountTransactionDTO); savingsAccountTransactions.add(savingsAccountTransactionDTO);
} }
} }
@@ -232,7 +232,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
depositAccountAssembler.assignSavingAccountHelpers(reinvestedDeposit); depositAccountAssembler.assignSavingAccountHelpers(reinvestedDeposit);
reinvestedDeposit.updateMaturityDateAndAmount(mc, isPreMatureClosure, reinvestedDeposit.updateMaturityDateAndAmount(mc, isPreMatureClosure,
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
reinvestedDeposit.processAccountUponActivation(fmt); reinvestedDeposit.processAccountUponActivation(fmt, user);
reinvestedDeposit.updateMaturityDateAndAmount(mc, isPreMatureClosure, reinvestedDeposit.updateMaturityDateAndAmount(mc, isPreMatureClosure,
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
this.savingsAccountRepository.save(reinvestedDeposit); this.savingsAccountRepository.save(reinvestedDeposit);
@@ -180,7 +180,7 @@ public class FixedDepositAccount extends SavingsAccount {
List<SavingsAccountTransaction> allTransactions = new ArrayList<>(); List<SavingsAccountTransaction> allTransactions = new ArrayList<>();
final Money transactionAmountMoney = Money.of(getCurrency(), this.accountTermAndPreClosure.depositAmount()); final Money transactionAmountMoney = Money.of(getCurrency(), this.accountTermAndPreClosure.depositAmount());
final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(null, office(), null, final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(null, office(), null,
this.accountSubmittedOrActivationDate(), transactionAmountMoney, new Date()); this.accountSubmittedOrActivationDate(), transactionAmountMoney, new Date(), null); // TODO: verify if it is ok to pass null for AppUser
transaction.updateRunningBalance(transactionAmountMoney); transaction.updateRunningBalance(transactionAmountMoney);
transaction.updateCumulativeBalanceAndDates(this.getCurrency(), interestCalculatedUpto()); transaction.updateCumulativeBalanceAndDates(this.getCurrency(), interestCalculatedUpto());
allTransactions.add(transaction); allTransactions.add(transaction);
@@ -738,7 +738,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
final Money amount = Money.of(this.currency, transactionDTO.getTransactionAmount()); final Money amount = Money.of(this.currency, transactionDTO.getTransactionAmount());
final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(this, office(), transactionDTO.getPaymentDetail(), final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(this, office(), transactionDTO.getPaymentDetail(),
transactionDTO.getTransactionDate(), amount, transactionDTO.getCreatedDate()); transactionDTO.getTransactionDate(), amount, transactionDTO.getCreatedDate(), transactionDTO.getAppUser());
this.transactions.add(transaction); this.transactions.add(transaction);
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions); this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
@@ -821,21 +821,23 @@ public class SavingsAccount extends AbstractPersistable<Long> {
final Money transactionAmountMoney = Money.of(this.currency, transactionDTO.getTransactionAmount()); final Money transactionAmountMoney = Money.of(this.currency, transactionDTO.getTransactionAmount());
final SavingsAccountTransaction transaction = SavingsAccountTransaction.withdrawal(this, office(), final SavingsAccountTransaction transaction = SavingsAccountTransaction.withdrawal(this, office(),
transactionDTO.getPaymentDetail(), transactionDTO.getTransactionDate(), transactionAmountMoney, transactionDTO.getPaymentDetail(), transactionDTO.getTransactionDate(), transactionAmountMoney,
transactionDTO.getCreatedDate()); transactionDTO.getCreatedDate(), transactionDTO.getAppUser());
this.transactions.add(transaction); this.transactions.add(transaction);
if (applyWithdrawFee) { if (applyWithdrawFee) {
// auto pay withdrawal fee // auto pay withdrawal fee
payWithdrawalFee(transactionDTO.getTransactionAmount(), transactionDTO.getTransactionDate()); payWithdrawalFee(transactionDTO.getTransactionAmount(), transactionDTO.getTransactionDate(),
transactionDTO.getAppUser());
} }
return transaction; return transaction;
} }
private void payWithdrawalFee(final BigDecimal transactionAmoount, final LocalDate transactionDate) { private void payWithdrawalFee(final BigDecimal transactionAmoount, final LocalDate transactionDate,
final AppUser user) {
for (SavingsAccountCharge charge : this.charges()) { for (SavingsAccountCharge charge : this.charges()) {
if (charge.isWithdrawalFee() && charge.isActive()) { if (charge.isWithdrawalFee() && charge.isActive()) {
charge.updateWithdralFeeAmount(transactionAmoount); charge.updateWithdralFeeAmount(transactionAmoount);
this.payCharge(charge, charge.getAmountOutstanding(this.getCurrency()), transactionDate); this.payCharge(charge, charge.getAmountOutstanding(this.getCurrency()), transactionDate, user);
} }
} }
} }
@@ -1817,7 +1819,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
} }
public void processAccountUponActivation(final boolean isSavingsInterestPostingAtCurrentPeriodEnd, public void processAccountUponActivation(final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
final Integer financialYearBeginningMonth) { final Integer financialYearBeginningMonth, final AppUser user) {
// update annual fee due date // update annual fee due date
for (SavingsAccountCharge charge : this.charges()) { for (SavingsAccountCharge charge : this.charges()) {
@@ -1825,7 +1827,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
} }
// auto pay the activation time charges // auto pay the activation time charges
this.payActivationCharges(isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); this.payActivationCharges(isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, user);
// TODO : AA add activation charges to actual changes list // TODO : AA add activation charges to actual changes list
} }
@@ -1848,12 +1850,13 @@ public class SavingsAccount extends AbstractPersistable<Long> {
this.lockedInUntilDate = calculateDateAccountIsLockedUntil(getActivationLocalDate()); this.lockedInUntilDate = calculateDateAccountIsLockedUntil(getActivationLocalDate());
} }
private void payActivationCharges(final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth) { private void payActivationCharges(final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth,
final AppUser user) {
boolean isSavingsChargeApplied = false; boolean isSavingsChargeApplied = false;
for (SavingsAccountCharge savingsAccountCharge : this.charges()) { for (SavingsAccountCharge savingsAccountCharge : this.charges()) {
if (savingsAccountCharge.isSavingsActivation()) { if (savingsAccountCharge.isSavingsActivation()) {
isSavingsChargeApplied = true; isSavingsChargeApplied = true;
payCharge(savingsAccountCharge, savingsAccountCharge.getAmountOutstanding(getCurrency()), getActivationLocalDate()); payCharge(savingsAccountCharge, savingsAccountCharge.getAmountOutstanding(getCurrency()), getActivationLocalDate(), user);
} }
} }
@@ -2037,7 +2040,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
this.charges.remove(charge); this.charges.remove(charge);
} }
public void waiveCharge(final Long savingsAccountChargeId) { public void waiveCharge(final Long savingsAccountChargeId, final AppUser user) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>(); final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
@@ -2076,7 +2079,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
// waive charge // waive charge
final Money amountWaived = savingsAccountCharge.waive(getCurrency()); final Money amountWaived = savingsAccountCharge.waive(getCurrency());
handleWaiverChargeTransactions(savingsAccountCharge, amountWaived); handleWaiverChargeTransactions(savingsAccountCharge, amountWaived, user);
} }
@@ -2167,7 +2170,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
} }
public void payCharge(final SavingsAccountCharge savingsAccountCharge, final BigDecimal amountPaid, final LocalDate transactionDate, public void payCharge(final SavingsAccountCharge savingsAccountCharge, final BigDecimal amountPaid, final LocalDate transactionDate,
final DateTimeFormatter formatter) { final DateTimeFormatter formatter, final AppUser user) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>(); final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
@@ -2242,32 +2245,34 @@ public class SavingsAccount extends AbstractPersistable<Long> {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
} }
this.payCharge(savingsAccountCharge, chargePaid, transactionDate); this.payCharge(savingsAccountCharge, chargePaid, transactionDate, user);
} }
public void payCharge(final SavingsAccountCharge savingsAccountCharge, final Money amountPaid, final LocalDate transactionDate) { public void payCharge(final SavingsAccountCharge savingsAccountCharge, final Money amountPaid, final LocalDate transactionDate,
final AppUser user) {
savingsAccountCharge.pay(getCurrency(), amountPaid); savingsAccountCharge.pay(getCurrency(), amountPaid);
handlePayChargeTransactions(savingsAccountCharge, amountPaid, transactionDate); handlePayChargeTransactions(savingsAccountCharge, amountPaid, transactionDate, user);
} }
private void handlePayChargeTransactions(SavingsAccountCharge savingsAccountCharge, Money transactionAmount, private void handlePayChargeTransactions(SavingsAccountCharge savingsAccountCharge, Money transactionAmount,
final LocalDate transactionDate) { final LocalDate transactionDate, final AppUser user) {
SavingsAccountTransaction chargeTransaction = null; SavingsAccountTransaction chargeTransaction = null;
if (savingsAccountCharge.isWithdrawalFee()) { if (savingsAccountCharge.isWithdrawalFee()) {
chargeTransaction = SavingsAccountTransaction.withdrawalFee(this, office(), transactionDate, transactionAmount); chargeTransaction = SavingsAccountTransaction.withdrawalFee(this, office(), transactionDate, transactionAmount, user);
} else if (savingsAccountCharge.isAnnualFee()) { } else if (savingsAccountCharge.isAnnualFee()) {
chargeTransaction = SavingsAccountTransaction.annualFee(this, office(), transactionDate, transactionAmount); chargeTransaction = SavingsAccountTransaction.annualFee(this, office(), transactionDate, transactionAmount, user);
} else { } else {
chargeTransaction = SavingsAccountTransaction.charge(this, office(), transactionDate, transactionAmount); chargeTransaction = SavingsAccountTransaction.charge(this, office(), transactionDate, transactionAmount, user);
} }
handleChargeTransactions(savingsAccountCharge, chargeTransaction); handleChargeTransactions(savingsAccountCharge, chargeTransaction);
} }
private void handleWaiverChargeTransactions(SavingsAccountCharge savingsAccountCharge, Money transactionAmount) { private void handleWaiverChargeTransactions(SavingsAccountCharge savingsAccountCharge, Money transactionAmount,
AppUser user) {
final SavingsAccountTransaction chargeTransaction = SavingsAccountTransaction.waiver(this, office(), final SavingsAccountTransaction chargeTransaction = SavingsAccountTransaction.waiver(this, office(),
DateUtils.getLocalDateOfTenant(), transactionAmount); DateUtils.getLocalDateOfTenant(), transactionAmount, user);
handleChargeTransactions(savingsAccountCharge, chargeTransaction); handleChargeTransactions(savingsAccountCharge, chargeTransaction);
} }
@@ -17,6 +17,7 @@ import org.joda.time.format.DateTimeFormatter;
import org.mifosplatform.accounting.journalentry.service.JournalEntryWritePlatformService; import org.mifosplatform.accounting.journalentry.service.JournalEntryWritePlatformService;
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService; import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
import org.mifosplatform.infrastructure.core.service.DateUtils; import org.mifosplatform.infrastructure.core.service.DateUtils;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
@@ -24,6 +25,7 @@ import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
import org.mifosplatform.portfolio.savings.SavingsTransactionBooleanValues; import org.mifosplatform.portfolio.savings.SavingsTransactionBooleanValues;
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionDTO; import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionDTO;
import org.mifosplatform.portfolio.savings.exception.DepositAccountTransactionNotAllowedException; import org.mifosplatform.portfolio.savings.exception.DepositAccountTransactionNotAllowedException;
import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -31,6 +33,7 @@ import org.springframework.transaction.annotation.Transactional;
@Service @Service
public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainService { public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainService {
private final PlatformSecurityContext context;
private final SavingsAccountRepositoryWrapper savingsAccountRepository; private final SavingsAccountRepositoryWrapper savingsAccountRepository;
private final SavingsAccountTransactionRepository savingsAccountTransactionRepository; private final SavingsAccountTransactionRepository savingsAccountTransactionRepository;
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper; private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper;
@@ -42,12 +45,14 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
final SavingsAccountTransactionRepository savingsAccountTransactionRepository, final SavingsAccountTransactionRepository savingsAccountTransactionRepository,
final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper, final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper,
final JournalEntryWritePlatformService journalEntryWritePlatformService, final JournalEntryWritePlatformService journalEntryWritePlatformService,
final ConfigurationDomainService configurationDomainService) { final ConfigurationDomainService configurationDomainService,
final PlatformSecurityContext context) {
this.savingsAccountRepository = savingsAccountRepository; this.savingsAccountRepository = savingsAccountRepository;
this.savingsAccountTransactionRepository = savingsAccountTransactionRepository; this.savingsAccountTransactionRepository = savingsAccountTransactionRepository;
this.applicationCurrencyRepositoryWrapper = applicationCurrencyRepositoryWrapper; this.applicationCurrencyRepositoryWrapper = applicationCurrencyRepositoryWrapper;
this.journalEntryWritePlatformService = journalEntryWritePlatformService; this.journalEntryWritePlatformService = journalEntryWritePlatformService;
this.configurationDomainService = configurationDomainService; this.configurationDomainService = configurationDomainService;
this.context = context;
} }
@Transactional @Transactional
@@ -56,6 +61,10 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail,
final SavingsTransactionBooleanValues transactionBooleanValues) { final SavingsTransactionBooleanValues transactionBooleanValues) {
AppUser user = null;
if (this.context != null) {
user = this.context.authenticatedUser();
}
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd(); .isSavingsInterestPostingAtCurrentPeriodEnd();
final Integer financialYearBeginningMonth = this.configurationDomainService final Integer financialYearBeginningMonth = this.configurationDomainService
@@ -67,7 +76,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
final Set<Long> existingReversedTransactionIds = new HashSet<>(); final Set<Long> existingReversedTransactionIds = new HashSet<>();
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount, final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
paymentDetail, new Date()); paymentDetail, new Date(), user);
final SavingsAccountTransaction withdrawal = account.withdraw(transactionDTO, transactionBooleanValues.isApplyWithdrawFee()); final SavingsAccountTransaction withdrawal = account.withdraw(transactionDTO, transactionBooleanValues.isApplyWithdrawFee());
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
@@ -97,6 +106,10 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail,
final boolean isAccountTransfer, final boolean isRegularTransaction) { final boolean isAccountTransfer, final boolean isRegularTransaction) {
AppUser user = null;
if (this.context != null) {
user = this.context.authenticatedUser();
}
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd(); .isSavingsInterestPostingAtCurrentPeriodEnd();
final Integer financialYearBeginningMonth = this.configurationDomainService final Integer financialYearBeginningMonth = this.configurationDomainService
@@ -110,7 +123,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
final Set<Long> existingReversedTransactionIds = new HashSet<>(); final Set<Long> existingReversedTransactionIds = new HashSet<>();
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount, final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
paymentDetail, new Date()); paymentDetail, new Date(), user);
final SavingsAccountTransaction deposit = account.deposit(transactionDTO); final SavingsAccountTransaction deposit = account.deposit(transactionDTO);
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
@@ -37,6 +37,7 @@ import org.mifosplatform.portfolio.savings.SavingsAccountTransactionType;
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionEnumData; import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionEnumData;
import org.mifosplatform.portfolio.savings.domain.interest.EndOfDayBalance; import org.mifosplatform.portfolio.savings.domain.interest.EndOfDayBalance;
import org.mifosplatform.portfolio.savings.service.SavingsEnumerations; import org.mifosplatform.portfolio.savings.service.SavingsEnumerations;
import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.springframework.data.jpa.domain.AbstractPersistable;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
@@ -96,6 +97,10 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
@Temporal(TemporalType.TIMESTAMP) @Temporal(TemporalType.TIMESTAMP)
@Column(name = "created_date", nullable = false) @Column(name = "created_date", nullable = false)
private final Date createdDate; private final Date createdDate;
@ManyToOne
@JoinColumn(name = "appuser_id", nullable = false)
private AppUser appUser;
protected SavingsAccountTransaction() { protected SavingsAccountTransaction() {
this.dateOf = null; this.dateOf = null;
@@ -104,97 +109,101 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
} }
public static SavingsAccountTransaction deposit(final SavingsAccount savingsAccount, final Office office, public static SavingsAccountTransaction deposit(final SavingsAccount savingsAccount, final Office office,
final PaymentDetail paymentDetail, final LocalDate date, final Money amount, Date createdDate) { final PaymentDetail paymentDetail, final LocalDate date, final Money amount, Date createdDate, final AppUser appUser) {
final boolean isReversed = false; final boolean isReversed = false;
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, SavingsAccountTransactionType.DEPOSIT.getValue(), date, return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, SavingsAccountTransactionType.DEPOSIT.getValue(), date,
createdDate, amount, isReversed); createdDate, amount, isReversed, appUser);
} }
public static SavingsAccountTransaction withdrawal(final SavingsAccount savingsAccount, final Office office, public static SavingsAccountTransaction withdrawal(final SavingsAccount savingsAccount, final Office office,
final PaymentDetail paymentDetail, final LocalDate date, final Money amount, Date createdDate) { final PaymentDetail paymentDetail, final LocalDate date, final Money amount, Date createdDate, final AppUser appUser) {
final boolean isReversed = false; final boolean isReversed = false;
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, SavingsAccountTransactionType.WITHDRAWAL.getValue(), return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, SavingsAccountTransactionType.WITHDRAWAL.getValue(),
date, createdDate, amount, isReversed); date, createdDate, amount, isReversed, appUser);
} }
public static SavingsAccountTransaction interestPosting(final SavingsAccount savingsAccount, final Office office, final LocalDate date, public static SavingsAccountTransaction interestPosting(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
final Money amount) { final Money amount) {
final boolean isReversed = false; final boolean isReversed = false;
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.INTEREST_POSTING.getValue(), date, return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.INTEREST_POSTING.getValue(), date,
amount, isReversed); amount, isReversed, null);
} }
public static SavingsAccountTransaction withdrawalFee(final SavingsAccount savingsAccount, final Office office, final LocalDate date, public static SavingsAccountTransaction withdrawalFee(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
final Money amount) { final Money amount, final AppUser appUser) {
final boolean isReversed = false; final boolean isReversed = false;
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.WITHDRAWAL_FEE.getValue(), date, amount, return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.WITHDRAWAL_FEE.getValue(), date, amount,
isReversed); isReversed, appUser);
} }
public static SavingsAccountTransaction annualFee(final SavingsAccount savingsAccount, final Office office, final LocalDate date, public static SavingsAccountTransaction annualFee(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
final Money amount) { final Money amount, final AppUser appUser) {
final boolean isReversed = false; final boolean isReversed = false;
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.ANNUAL_FEE.getValue(), date, amount, return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.ANNUAL_FEE.getValue(), date, amount,
isReversed); isReversed, appUser);
} }
public static SavingsAccountTransaction charge(final SavingsAccount savingsAccount, final Office office, final LocalDate date, public static SavingsAccountTransaction charge(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
final Money amount) { final Money amount, final AppUser appUser) {
final boolean isReversed = false; final boolean isReversed = false;
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.PAY_CHARGE.getValue(), date, amount, return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.PAY_CHARGE.getValue(), date, amount,
isReversed); isReversed, appUser);
} }
public static SavingsAccountTransaction waiver(final SavingsAccount savingsAccount, final Office office, final LocalDate date, public static SavingsAccountTransaction waiver(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
final Money amount) { final Money amount, final AppUser appUser) {
final boolean isReversed = false; final boolean isReversed = false;
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.WAIVE_CHARGES.getValue(), date, amount, return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.WAIVE_CHARGES.getValue(), date, amount,
isReversed); isReversed, appUser);
} }
public static SavingsAccountTransaction initiateTransfer(final SavingsAccount savingsAccount, final Office office, final LocalDate date) { public static SavingsAccountTransaction initiateTransfer(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
final AppUser appUser) {
final boolean isReversed = false; final boolean isReversed = false;
final PaymentDetail paymentDetail = null; final PaymentDetail paymentDetail = null;
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, return new SavingsAccountTransaction(savingsAccount, office, paymentDetail,
SavingsAccountTransactionType.INITIATE_TRANSFER.getValue(), date, new Date(), savingsAccount.getSummary() SavingsAccountTransactionType.INITIATE_TRANSFER.getValue(), date, new Date(), savingsAccount.getSummary()
.getAccountBalance(), isReversed); .getAccountBalance(), isReversed, appUser);
} }
public static SavingsAccountTransaction approveTransfer(final SavingsAccount savingsAccount, final Office office, final LocalDate date) { public static SavingsAccountTransaction approveTransfer(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
final AppUser appUser) {
final boolean isReversed = false; final boolean isReversed = false;
final PaymentDetail paymentDetail = null; final PaymentDetail paymentDetail = null;
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, return new SavingsAccountTransaction(savingsAccount, office, paymentDetail,
SavingsAccountTransactionType.APPROVE_TRANSFER.getValue(), date, new Date(), savingsAccount.getSummary() SavingsAccountTransactionType.APPROVE_TRANSFER.getValue(), date, new Date(), savingsAccount.getSummary()
.getAccountBalance(), isReversed); .getAccountBalance(), isReversed, appUser);
} }
public static SavingsAccountTransaction withdrawTransfer(final SavingsAccount savingsAccount, final Office office, final LocalDate date) { public static SavingsAccountTransaction withdrawTransfer(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
final AppUser appUser) {
final boolean isReversed = false; final boolean isReversed = false;
final PaymentDetail paymentDetail = null; final PaymentDetail paymentDetail = null;
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, return new SavingsAccountTransaction(savingsAccount, office, paymentDetail,
SavingsAccountTransactionType.WITHDRAW_TRANSFER.getValue(), date, new Date(), savingsAccount.getSummary() SavingsAccountTransactionType.WITHDRAW_TRANSFER.getValue(), date, new Date(), savingsAccount.getSummary()
.getAccountBalance(), isReversed); .getAccountBalance(), isReversed, appUser);
} }
public static SavingsAccountTransaction copyTransaction(SavingsAccountTransaction accountTransaction) { public static SavingsAccountTransaction copyTransaction(SavingsAccountTransaction accountTransaction) {
return new SavingsAccountTransaction(accountTransaction.savingsAccount, accountTransaction.office, return new SavingsAccountTransaction(accountTransaction.savingsAccount, accountTransaction.office,
accountTransaction.paymentDetail, accountTransaction.typeOf, accountTransaction.transactionLocalDate(), accountTransaction.paymentDetail, accountTransaction.typeOf, accountTransaction.transactionLocalDate(),
accountTransaction.createdDate, accountTransaction.amount, accountTransaction.reversed); accountTransaction.createdDate, accountTransaction.amount, accountTransaction.reversed, accountTransaction.appUser);
} }
private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final Integer typeOf, private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final Integer typeOf,
final LocalDate transactionLocalDate, final Money amount, final boolean isReversed) { final LocalDate transactionLocalDate, final Money amount, final boolean isReversed, final AppUser appUser) {
this(savingsAccount, office, null, typeOf, transactionLocalDate, new Date(), amount, isReversed); this(savingsAccount, office, null, typeOf, transactionLocalDate, new Date(), amount, isReversed, appUser);
} }
private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final PaymentDetail paymentDetail, 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 Integer typeOf, final LocalDate transactionLocalDate, final Date createdDate, final Money amount, final boolean isReversed,
this(savingsAccount, office, paymentDetail, typeOf, transactionLocalDate, createdDate, amount.getAmount(), isReversed); final AppUser appUser) {
this(savingsAccount, office, paymentDetail, typeOf, transactionLocalDate, createdDate, amount.getAmount(), isReversed, appUser);
} }
private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final PaymentDetail paymentDetail, private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final PaymentDetail paymentDetail,
final Integer typeOf, final LocalDate transactionLocalDate, final Date createdDate, final BigDecimal amount, final Integer typeOf, final LocalDate transactionLocalDate, final Date createdDate, final BigDecimal amount,
final boolean isReversed) { final boolean isReversed, final AppUser appUser) {
this.savingsAccount = savingsAccount; this.savingsAccount = savingsAccount;
this.office = office; this.office = office;
this.typeOf = typeOf; this.typeOf = typeOf;
@@ -203,6 +212,7 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
this.reversed = isReversed; this.reversed = isReversed;
this.paymentDetail = paymentDetail; this.paymentDetail = paymentDetail;
this.createdDate = createdDate; this.createdDate = createdDate;
this.appUser = appUser;
} }
public LocalDate transactionLocalDate() { public LocalDate transactionLocalDate() {
@@ -583,6 +583,11 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
@Override @Override
public CommandProcessingResult adjustRDTransaction(final Long savingsId, final Long transactionId, final JsonCommand command) { public CommandProcessingResult adjustRDTransaction(final Long savingsId, final Long transactionId, final JsonCommand command) {
AppUser user = null;
if (this.context != null) {
user = this.context.authenticatedUser();
}
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd(); .isSavingsInterestPostingAtCurrentPeriodEnd();
@@ -625,11 +630,11 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
SavingsAccountTransaction transaction = null; SavingsAccountTransaction transaction = null;
if (savingsAccountTransaction.isDeposit()) { if (savingsAccountTransaction.isDeposit()) {
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount, final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
paymentDetail, savingsAccountTransaction.createdDate()); paymentDetail, savingsAccountTransaction.createdDate(), user);
transaction = account.deposit(transactionDTO); transaction = account.deposit(transactionDTO);
} else { } else {
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount, final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
paymentDetail, savingsAccountTransaction.createdDate()); paymentDetail, savingsAccountTransaction.createdDate(), user);
transaction = account.withdraw(transactionDTO, true); transaction = account.withdraw(transactionDTO, true);
} }
final Long newtransactionId = saveTransactionToGenerateTransactionId(transaction); final Long newtransactionId = saveTransactionToGenerateTransactionId(transaction);
@@ -825,6 +830,10 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
public SavingsAccountTransaction initiateSavingsTransfer(final Long accountId, final LocalDate transferDate, public SavingsAccountTransaction initiateSavingsTransfer(final Long accountId, final LocalDate transferDate,
final DepositAccountType depositAccountType) { final DepositAccountType depositAccountType) {
AppUser user = null;
if (this.context != null) {
user = this.context.authenticatedUser();
}
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd(); .isSavingsInterestPostingAtCurrentPeriodEnd();
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth(); final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
@@ -836,7 +845,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds);
final SavingsAccountTransaction newTransferTransaction = SavingsAccountTransaction.initiateTransfer(savingsAccount, final SavingsAccountTransaction newTransferTransaction = SavingsAccountTransaction.initiateTransfer(savingsAccount,
savingsAccount.office(), transferDate); savingsAccount.office(), transferDate, user);
savingsAccount.getTransactions().add(newTransferTransaction); savingsAccount.getTransactions().add(newTransferTransaction);
savingsAccount.setStatus(SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue()); savingsAccount.setStatus(SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue());
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
@@ -855,6 +864,11 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
@Override @Override
public SavingsAccountTransaction withdrawSavingsTransfer(final Long accountId, final LocalDate transferDate, public SavingsAccountTransaction withdrawSavingsTransfer(final Long accountId, final LocalDate transferDate,
final DepositAccountType depositAccountType) { final DepositAccountType depositAccountType) {
AppUser user = null;
if (this.context != null) {
user = this.context.authenticatedUser();
}
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd(); .isSavingsInterestPostingAtCurrentPeriodEnd();
@@ -867,7 +881,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds);
final SavingsAccountTransaction withdrawtransferTransaction = SavingsAccountTransaction.withdrawTransfer(savingsAccount, final SavingsAccountTransaction withdrawtransferTransaction = SavingsAccountTransaction.withdrawTransfer(savingsAccount,
savingsAccount.office(), transferDate); savingsAccount.office(), transferDate, user);
savingsAccount.getTransactions().add(withdrawtransferTransaction); savingsAccount.getTransactions().add(withdrawtransferTransaction);
savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue()); savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue());
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
@@ -894,6 +908,11 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
public SavingsAccountTransaction acceptSavingsTransfer(final Long accountId, final LocalDate transferDate, public SavingsAccountTransaction acceptSavingsTransfer(final Long accountId, final LocalDate transferDate,
final Office acceptedInOffice, final Staff fieldOfficer, final DepositAccountType depositAccountType) { final Office acceptedInOffice, final Staff fieldOfficer, final DepositAccountType depositAccountType) {
AppUser user = null;
if (this.context != null) {
user = this.context.authenticatedUser();
}
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd(); .isSavingsInterestPostingAtCurrentPeriodEnd();
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth(); final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
@@ -905,7 +924,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds);
final SavingsAccountTransaction acceptTransferTransaction = SavingsAccountTransaction.approveTransfer(savingsAccount, final SavingsAccountTransaction acceptTransferTransaction = SavingsAccountTransaction.approveTransfer(savingsAccount,
acceptedInOffice, transferDate); acceptedInOffice, transferDate, user);
savingsAccount.getTransactions().add(acceptTransferTransaction); savingsAccount.getTransactions().add(acceptTransferTransaction);
savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue()); savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue());
if (fieldOfficer != null) { if (fieldOfficer != null) {
@@ -1038,7 +1057,10 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
public CommandProcessingResult waiveCharge(final Long savingsAccountId, final Long savingsAccountChargeId, public CommandProcessingResult waiveCharge(final Long savingsAccountId, final Long savingsAccountChargeId,
@SuppressWarnings("unused") final DepositAccountType depositAccountType) { @SuppressWarnings("unused") final DepositAccountType depositAccountType) {
this.context.authenticatedUser(); AppUser user = null;
if (this.context != null) {
user = this.context.authenticatedUser();
}
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd(); .isSavingsInterestPostingAtCurrentPeriodEnd();
@@ -1055,7 +1077,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final Set<Long> existingReversedTransactionIds = new HashSet<>(); final Set<Long> existingReversedTransactionIds = new HashSet<>();
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
account.waiveCharge(savingsAccountChargeId); account.waiveCharge(savingsAccountChargeId, user);
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) { if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) {
@@ -1109,7 +1131,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
public CommandProcessingResult payCharge(final Long savingsAccountId, final Long savingsAccountChargeId, final JsonCommand command, public CommandProcessingResult payCharge(final Long savingsAccountId, final Long savingsAccountChargeId, final JsonCommand command,
@SuppressWarnings("unused") final DepositAccountType depositAccountType) { @SuppressWarnings("unused") final DepositAccountType depositAccountType) {
this.context.authenticatedUser(); this.context.authenticatedUser();
this.savingsAccountChargeDataValidator.validatePayCharge(command.json()); this.savingsAccountChargeDataValidator.validatePayCharge(command.json());
final Locale locale = command.extractLocale(); final Locale locale = command.extractLocale();
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
@@ -1168,6 +1191,11 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
@Transactional @Transactional
private void payCharge(final SavingsAccountCharge savingsAccountCharge, final LocalDate transactionDate, final BigDecimal amountPaid, private void payCharge(final SavingsAccountCharge savingsAccountCharge, final LocalDate transactionDate, final BigDecimal amountPaid,
final DateTimeFormatter formatter) { final DateTimeFormatter formatter) {
AppUser user = null;
if (this.context != null) {
user = this.context.authenticatedUser();
}
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd(); .isSavingsInterestPostingAtCurrentPeriodEnd();
@@ -1179,7 +1207,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final Set<Long> existingTransactionIds = new HashSet<>(); final Set<Long> existingTransactionIds = new HashSet<>();
final Set<Long> existingReversedTransactionIds = new HashSet<>(); final Set<Long> existingReversedTransactionIds = new HashSet<>();
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter); account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter, user);
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
if (account.isBeforeLastPostingPeriod(transactionDate)) { if (account.isBeforeLastPostingPeriod(transactionDate)) {
@@ -195,6 +195,11 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
public void processPostActiveActions(final SavingsAccount account, final DateTimeFormatter fmt, final Set<Long> existingTransactionIds, public void processPostActiveActions(final SavingsAccount account, final DateTimeFormatter fmt, final Set<Long> existingTransactionIds,
final Set<Long> existingReversedTransactionIds) { final Set<Long> existingReversedTransactionIds) {
AppUser user = null;
if (this.context != null) {
user = this.context.authenticatedUser();
}
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd(); .isSavingsInterestPostingAtCurrentPeriodEnd();
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth(); final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
@@ -207,7 +212,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
null, isAccountTransfer, isRegularTransaction); null, isAccountTransfer, isRegularTransaction);
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
} }
account.processAccountUponActivation(isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); account.processAccountUponActivation(isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, user);
account.validateAccountBalanceDoesNotBecomeNegative(SavingsAccountTransactionType.PAY_CHARGE.name()); account.validateAccountBalanceDoesNotBecomeNegative(SavingsAccountTransactionType.PAY_CHARGE.name());
} }
@@ -292,12 +297,17 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override @Override
public CommandProcessingResult applyAnnualFee(final Long savingsAccountChargeId, final Long accountId) { public CommandProcessingResult applyAnnualFee(final Long savingsAccountChargeId, final Long accountId) {
AppUser user = null;
if (this.context != null) {
user = this.context.authenticatedUser();
}
final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection( final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection(
savingsAccountChargeId, accountId); savingsAccountChargeId, accountId);
final DateTimeFormatter fmt = DateTimeFormat.forPattern("dd MM yyyy"); final DateTimeFormatter fmt = DateTimeFormat.forPattern("dd MM yyyy");
this.payCharge(savingsAccountCharge, savingsAccountCharge.getDueLocalDate(), savingsAccountCharge.amount(), fmt); this.payCharge(savingsAccountCharge, savingsAccountCharge.getDueLocalDate(), savingsAccountCharge.amount(), fmt, user);
return new CommandProcessingResultBuilder() // return new CommandProcessingResultBuilder() //
.withEntityId(savingsAccountCharge.getId()) // .withEntityId(savingsAccountCharge.getId()) //
@@ -461,6 +471,11 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override @Override
public CommandProcessingResult adjustSavingsTransaction(final Long savingsId, final Long transactionId, final JsonCommand command) { public CommandProcessingResult adjustSavingsTransaction(final Long savingsId, final Long transactionId, final JsonCommand command) {
AppUser user = null;
if (this.context != null) {
user = this.context.authenticatedUser();
}
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd(); .isSavingsInterestPostingAtCurrentPeriodEnd();
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth(); final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
@@ -511,7 +526,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
SavingsAccountTransaction transaction = null; SavingsAccountTransaction transaction = null;
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount, final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
paymentDetail, savingsAccountTransaction.createdDate()); paymentDetail, savingsAccountTransaction.createdDate(), user);
if (savingsAccountTransaction.isDeposit()) { if (savingsAccountTransaction.isDeposit()) {
transaction = account.deposit(transactionDTO); transaction = account.deposit(transactionDTO);
} else { } else {
@@ -625,6 +640,11 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override @Override
public SavingsAccountTransaction initiateSavingsTransfer(final Long accountId, final LocalDate transferDate) { public SavingsAccountTransaction initiateSavingsTransfer(final Long accountId, final LocalDate transferDate) {
AppUser user = null;
if (this.context != null) {
user = this.context.authenticatedUser();
}
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd(); .isSavingsInterestPostingAtCurrentPeriodEnd();
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth(); final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
@@ -636,7 +656,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds);
final SavingsAccountTransaction newTransferTransaction = SavingsAccountTransaction.initiateTransfer(savingsAccount, final SavingsAccountTransaction newTransferTransaction = SavingsAccountTransaction.initiateTransfer(savingsAccount,
savingsAccount.office(), transferDate); savingsAccount.office(), transferDate, user);
savingsAccount.getTransactions().add(newTransferTransaction); savingsAccount.getTransactions().add(newTransferTransaction);
savingsAccount.setStatus(SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue()); savingsAccount.setStatus(SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue());
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
@@ -655,6 +675,11 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override @Override
public SavingsAccountTransaction withdrawSavingsTransfer(final Long accountId, final LocalDate transferDate) { public SavingsAccountTransaction withdrawSavingsTransfer(final Long accountId, final LocalDate transferDate) {
AppUser user = null;
if (this.context != null) {
user = this.context.authenticatedUser();
}
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd(); .isSavingsInterestPostingAtCurrentPeriodEnd();
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth(); final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
@@ -666,7 +691,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds);
final SavingsAccountTransaction withdrawtransferTransaction = SavingsAccountTransaction.withdrawTransfer(savingsAccount, final SavingsAccountTransaction withdrawtransferTransaction = SavingsAccountTransaction.withdrawTransfer(savingsAccount,
savingsAccount.office(), transferDate); savingsAccount.office(), transferDate, user);
savingsAccount.getTransactions().add(withdrawtransferTransaction); savingsAccount.getTransactions().add(withdrawtransferTransaction);
savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue()); savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue());
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
@@ -693,6 +718,11 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
public SavingsAccountTransaction acceptSavingsTransfer(final Long accountId, final LocalDate transferDate, public SavingsAccountTransaction acceptSavingsTransfer(final Long accountId, final LocalDate transferDate,
final Office acceptedInOffice, final Staff fieldOfficer) { final Office acceptedInOffice, final Staff fieldOfficer) {
AppUser user = null;
if (this.context != null) {
user = this.context.authenticatedUser();
}
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd(); .isSavingsInterestPostingAtCurrentPeriodEnd();
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth(); final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
@@ -704,7 +734,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds);
final SavingsAccountTransaction acceptTransferTransaction = SavingsAccountTransaction.approveTransfer(savingsAccount, final SavingsAccountTransaction acceptTransferTransaction = SavingsAccountTransaction.approveTransfer(savingsAccount,
acceptedInOffice, transferDate); acceptedInOffice, transferDate, user);
savingsAccount.getTransactions().add(acceptTransferTransaction); savingsAccount.getTransactions().add(acceptTransferTransaction);
savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue()); savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue());
if (fieldOfficer != null) { if (fieldOfficer != null) {
@@ -836,7 +866,10 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override @Override
public CommandProcessingResult waiveCharge(final Long savingsAccountId, final Long savingsAccountChargeId) { public CommandProcessingResult waiveCharge(final Long savingsAccountId, final Long savingsAccountChargeId) {
this.context.authenticatedUser(); AppUser user = null;
if (this.context != null) {
user = this.context.authenticatedUser();
}
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd(); .isSavingsInterestPostingAtCurrentPeriodEnd();
@@ -853,7 +886,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final Set<Long> existingReversedTransactionIds = new HashSet<>(); final Set<Long> existingReversedTransactionIds = new HashSet<>();
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
account.waiveCharge(savingsAccountChargeId); account.waiveCharge(savingsAccountChargeId, user);
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) { if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) {
@@ -906,7 +939,11 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override @Override
public CommandProcessingResult payCharge(final Long savingsAccountId, final Long savingsAccountChargeId, final JsonCommand command) { public CommandProcessingResult payCharge(final Long savingsAccountId, final Long savingsAccountChargeId, final JsonCommand command) {
this.context.authenticatedUser(); AppUser user = null;
if (this.context != null) {
user = this.context.authenticatedUser();
}
this.savingsAccountChargeDataValidator.validatePayCharge(command.json()); this.savingsAccountChargeDataValidator.validatePayCharge(command.json());
final Locale locale = command.extractLocale(); final Locale locale = command.extractLocale();
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
@@ -935,7 +972,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
} }
this.payCharge(savingsAccountCharge, transactionDate, amountPaid, fmt); this.payCharge(savingsAccountCharge, transactionDate, amountPaid, fmt, user);
return new CommandProcessingResultBuilder() // return new CommandProcessingResultBuilder() //
.withEntityId(savingsAccountCharge.getId()) // .withEntityId(savingsAccountCharge.getId()) //
.withOfficeId(savingsAccountCharge.savingsAccount().officeId()) // .withOfficeId(savingsAccountCharge.savingsAccount().officeId()) //
@@ -950,6 +987,11 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override @Override
public void applyChargeDue(final Long savingsAccountChargeId, final Long accountId) { public void applyChargeDue(final Long savingsAccountChargeId, final Long accountId) {
// always use current date as transaction date for batch job // always use current date as transaction date for batch job
AppUser user = null;
if (this.context != null) {
user = this.context.authenticatedUser();
}
final LocalDate transactionDate = DateUtils.getLocalDateOfTenant(); final LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection( final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection(
savingsAccountChargeId, accountId); savingsAccountChargeId, accountId);
@@ -957,13 +999,13 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final DateTimeFormatter fmt = DateTimeFormat.forPattern("dd MM yyyy"); final DateTimeFormatter fmt = DateTimeFormat.forPattern("dd MM yyyy");
while (transactionDate.isAfter(savingsAccountCharge.getDueLocalDate()) && savingsAccountCharge.isNotFullyPaid()) { while (transactionDate.isAfter(savingsAccountCharge.getDueLocalDate()) && savingsAccountCharge.isNotFullyPaid()) {
payCharge(savingsAccountCharge, transactionDate, savingsAccountCharge.amoutOutstanding(), fmt); payCharge(savingsAccountCharge, transactionDate, savingsAccountCharge.amoutOutstanding(), fmt, user);
} }
} }
@Transactional @Transactional
private void payCharge(final SavingsAccountCharge savingsAccountCharge, final LocalDate transactionDate, final BigDecimal amountPaid, private void payCharge(final SavingsAccountCharge savingsAccountCharge, final LocalDate transactionDate, final BigDecimal amountPaid,
final DateTimeFormatter formatter) { final DateTimeFormatter formatter, final AppUser user) {
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd(); .isSavingsInterestPostingAtCurrentPeriodEnd();
@@ -975,7 +1017,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final Set<Long> existingTransactionIds = new HashSet<>(); final Set<Long> existingTransactionIds = new HashSet<>();
final Set<Long> existingReversedTransactionIds = new HashSet<>(); final Set<Long> existingReversedTransactionIds = new HashSet<>();
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter); account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter, user);
boolean isInterestTransfer = false; boolean isInterestTransfer = false;
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
if (account.isBeforeLastPostingPeriod(transactionDate)) { if (account.isBeforeLastPostingPeriod(transactionDate)) {
@@ -0,0 +1,8 @@
ALTER TABLE `m_loan_transaction`
ADD COLUMN (
`created_date` DATETIME,
`appuser_id` BIGINT(20)
);
ALTER TABLE `m_savings_account_transaction`
ADD COLUMN `appuser_id` BIGINT(20);