Merge branch 'binnygopinath-MIFOSX-1628' into develop

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