Bug fixes for accrual based accounting
This commit is contained in:
+43
-16
@@ -8,7 +8,6 @@ import org.mifosplatform.accounting.common.AccountingConstants.ACCRUAL_ACCOUNTS_
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccount;
|
||||
import org.mifosplatform.accounting.journalentry.data.LoanDTO;
|
||||
import org.mifosplatform.accounting.journalentry.data.LoanTransactionDTO;
|
||||
import org.mifosplatform.infrastructure.core.service.FileUtils;
|
||||
import org.mifosplatform.organisation.office.domain.Office;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -50,7 +49,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
|
||||
/** Handle Write Offs and waivers **/
|
||||
else if ((loanTransactionDTO.getTransactionType().isWriteOff() || loanTransactionDTO.getTransactionType().isWaiveInterest() || loanTransactionDTO
|
||||
.getTransactionType().isWaiveCharges()) && !loanTransactionDTO.isReversed()) {
|
||||
.getTransactionType().isWaiveCharges())) {
|
||||
createJournalEntriesForWriteOff(loanDTO, loanTransactionDTO, office);
|
||||
}
|
||||
}
|
||||
@@ -68,8 +67,6 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
private void createJournalEntriesForDisbursements(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO,
|
||||
final Office office) {
|
||||
|
||||
// TODO: remove the junk transaction Id
|
||||
String junkTransactionId = "junk" + FileUtils.generateRandomString();
|
||||
// loan properties
|
||||
final Long loanProductId = loanDTO.getLoanProductId();
|
||||
final Long loanId = loanDTO.getLoanId();
|
||||
@@ -106,14 +103,14 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
final GLAccount interestOnLoansAccount = helper.getLinkedAccrualAccountsForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS);
|
||||
if (isReversed) {
|
||||
helper.createDebitJournalEntryForLoanProduct(office, interestOnLoansAccount, loanId, junkTransactionId, transactionDate,
|
||||
helper.createDebitJournalEntryForLoanProduct(office, interestOnLoansAccount, loanId, transactionId, transactionDate,
|
||||
interestApplied);
|
||||
helper.createCreditJournalEntryForLoanProduct(office, interestReceivableAccount, loanId, transactionId, transactionDate,
|
||||
interestApplied);
|
||||
helper.createCreditJournalEntryForLoanProduct(office, interestReceivableAccount, loanId, junkTransactionId,
|
||||
transactionDate, interestApplied);
|
||||
} else {
|
||||
helper.createDebitJournalEntryForLoanProduct(office, interestReceivableAccount, loanId, junkTransactionId, transactionDate,
|
||||
helper.createDebitJournalEntryForLoanProduct(office, interestReceivableAccount, loanId, transactionId, transactionDate,
|
||||
interestApplied);
|
||||
helper.createCreditJournalEntryForLoanProduct(office, interestOnLoansAccount, loanId, junkTransactionId, transactionDate,
|
||||
helper.createCreditJournalEntryForLoanProduct(office, interestOnLoansAccount, loanId, transactionId, transactionDate,
|
||||
interestApplied);
|
||||
}
|
||||
}
|
||||
@@ -240,6 +237,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
final BigDecimal interestAmount = loanTransactionDTO.getInterest();
|
||||
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||
final boolean isReversed = loanTransactionDTO.isReversed();
|
||||
|
||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||
|
||||
@@ -248,34 +246,63 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
|
||||
final GLAccount loanPortfolioAccount = helper.getLinkedAccrualAccountsForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO);
|
||||
helper.createCreditJournalEntryForLoanProduct(office, loanPortfolioAccount, loanId, transactionId, transactionDate,
|
||||
principalAmount);
|
||||
if (isReversed) {
|
||||
helper.createDebitJournalEntryForLoanProduct(office, loanPortfolioAccount, loanId, transactionId, transactionDate,
|
||||
principalAmount);
|
||||
} else {
|
||||
helper.createCreditJournalEntryForLoanProduct(office, loanPortfolioAccount, loanId, transactionId, transactionDate,
|
||||
principalAmount);
|
||||
}
|
||||
|
||||
}
|
||||
if (interestAmount != null && !(interestAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
||||
|
||||
final GLAccount interestAccount = helper.getLinkedAccrualAccountsForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE);
|
||||
helper.createCreditJournalEntryForLoanProduct(office, interestAccount, loanId, transactionId, transactionDate, interestAmount);
|
||||
if (isReversed) {
|
||||
helper.createDebitJournalEntryForLoanProduct(office, interestAccount, loanId, transactionId, transactionDate,
|
||||
interestAmount);
|
||||
} else {
|
||||
helper.createCreditJournalEntryForLoanProduct(office, interestAccount, loanId, transactionId, transactionDate,
|
||||
interestAmount);
|
||||
}
|
||||
}
|
||||
if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
||||
|
||||
final GLAccount incomeFromFeesAccount = helper.getLinkedAccrualAccountsForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE);
|
||||
helper.createCreditJournalEntryForLoanProduct(office, incomeFromFeesAccount, loanId, transactionId, transactionDate, feesAmount);
|
||||
if (isReversed) {
|
||||
helper.createDebitJournalEntryForLoanProduct(office, incomeFromFeesAccount, loanId, transactionId, transactionDate,
|
||||
feesAmount);
|
||||
} else {
|
||||
helper.createCreditJournalEntryForLoanProduct(office, incomeFromFeesAccount, loanId, transactionId, transactionDate,
|
||||
feesAmount);
|
||||
}
|
||||
}
|
||||
if (penaltiesAmount != null && !(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
|
||||
|
||||
final GLAccount incomeFromPenaltiesAccount = helper.getLinkedAccrualAccountsForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE);
|
||||
helper.createCreditJournalEntryForLoanProduct(office, incomeFromPenaltiesAccount, loanId, transactionId, transactionDate,
|
||||
penaltiesAmount);
|
||||
if (isReversed) {
|
||||
helper.createDebitJournalEntryForLoanProduct(office, incomeFromPenaltiesAccount, loanId, transactionId, transactionDate,
|
||||
penaltiesAmount);
|
||||
} else {
|
||||
helper.createCreditJournalEntryForLoanProduct(office, incomeFromPenaltiesAccount, loanId, transactionId, transactionDate,
|
||||
penaltiesAmount);
|
||||
}
|
||||
}
|
||||
final GLAccount fundSourceAccount = helper.getLinkedAccrualAccountsForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF);
|
||||
helper.createDebitJournalEntryForLoanProduct(office, fundSourceAccount, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||
if (isReversed) {
|
||||
helper.createCreditJournalEntryForLoanProduct(office, fundSourceAccount, loanId, transactionId, transactionDate,
|
||||
totalDebitAmount);
|
||||
} else {
|
||||
helper.createDebitJournalEntryForLoanProduct(office, fundSourceAccount, loanId, transactionId, transactionDate,
|
||||
totalDebitAmount);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+14
-2
@@ -251,6 +251,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
private boolean accountNumberRequiresAutoGeneration = false;
|
||||
@Transient
|
||||
private LoanRepaymentScheduleTransactionProcessorFactory transactionProcessorFactory;
|
||||
|
||||
@Transient
|
||||
private LoanLifecycleStateMachine loanLifecycleStateMachine;
|
||||
@Transient
|
||||
@@ -532,7 +533,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
public LoanTransaction waiveLoanCharge(final LoanCharge loanCharge, final LoanLifecycleStateMachine loanLifecycleStateMachine,
|
||||
final Map<String, Object> changes) {
|
||||
final Map<String, Object> changes, final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds) {
|
||||
|
||||
validateLoanIsNotClosed(loanCharge);
|
||||
|
||||
@@ -553,6 +554,9 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
|
||||
|
||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||
|
||||
final LoanTransaction waiveLoanChargeTransaction = LoanTransaction.waiveLoanCharge(this, amountWaived, transactionDate,
|
||||
feeChargesWaived, penaltyChargesWaived);
|
||||
@@ -1319,13 +1323,17 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
updateLoanSummaryDerivedFields();
|
||||
}
|
||||
|
||||
public LoanTransaction waiveInterest(final JsonCommand command, final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
||||
public LoanTransaction waiveInterest(final JsonCommand command, final LoanLifecycleStateMachine loanLifecycleStateMachine,final List<Long> existingTransactionIds,
|
||||
final List<Long> existingReversedTransactionIds) {
|
||||
|
||||
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
|
||||
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
|
||||
|
||||
final Money amountToWaive = Money.of(loanCurrency(), transactionAmount);
|
||||
final LoanTransaction waiveInterestTransaction = LoanTransaction.waiver(this, amountToWaive, transactionDate);
|
||||
|
||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||
|
||||
handleRepaymentOrWaiverTransaction(waiveInterestTransaction, loanLifecycleStateMachine, null);
|
||||
|
||||
@@ -2060,6 +2068,10 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
public Staff getLoanOfficer() {
|
||||
return this.loanOfficer;
|
||||
}
|
||||
|
||||
public LoanSummary getSummary() {
|
||||
return this.summary;
|
||||
}
|
||||
|
||||
public Map<String, Object> deriveAccountingBridgeData(final CurrencyData currencyData, final List<Long> existingTransactionIds,
|
||||
final List<Long> existingReversedTransactionIds) {
|
||||
|
||||
+38
-22
@@ -122,9 +122,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
|
||||
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(currency.toData(), existingTransactionIds,
|
||||
existingReversedTransactionIds);
|
||||
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
@@ -145,6 +143,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
context.authenticatedUser();
|
||||
|
||||
final Loan loan = retrieveLoanBy(loanId);
|
||||
final BigDecimal totalInterestCharged = loan.getSummary().getTotalInterestCharged();
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
@@ -161,6 +160,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getCurrencyCode());
|
||||
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(currency.toData(), existingTransactionIds,
|
||||
existingReversedTransactionIds);
|
||||
// add the previously calculated net charged interest back to
|
||||
// accountingBridgedate, this would not work if interest
|
||||
// recalculation in introduced
|
||||
accountingBridgeData.put("calculatedInterest", totalInterestCharged);
|
||||
|
||||
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||
}
|
||||
|
||||
@@ -209,10 +213,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
|
||||
final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getCurrencyCode());
|
||||
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(currency.toData(), existingTransactionIds,
|
||||
existingReversedTransactionIds);
|
||||
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
@@ -266,10 +267,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
|
||||
final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getCurrencyCode());
|
||||
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(currency.toData(), existingTransactionIds,
|
||||
existingReversedTransactionIds);
|
||||
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
@@ -298,7 +296,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
final Loan loan = retrieveLoanBy(loanId);
|
||||
|
||||
final LoanTransaction waiveTransaction = loan.waiveInterest(command, defaultLoanLifecycleStateMachine());
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
final LoanTransaction waiveTransaction = loan.waiveInterest(command, defaultLoanLifecycleStateMachine(), existingTransactionIds,
|
||||
existingReversedTransactionIds);
|
||||
|
||||
this.loanTransactionRepository.save(waiveTransaction);
|
||||
this.loanRepository.save(loan);
|
||||
@@ -309,6 +310,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final Note note = Note.loanTransactionNote(loan, waiveTransaction, noteText);
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
|
||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
@@ -350,10 +353,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
|
||||
final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getCurrencyCode());
|
||||
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(currency.toData(), existingTransactionIds,
|
||||
existingReversedTransactionIds);
|
||||
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
@@ -399,10 +399,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
}
|
||||
|
||||
if (possibleClosingTransaction != null) {
|
||||
final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getCurrencyCode());
|
||||
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(currency.toData(), existingTransactionIds,
|
||||
existingReversedTransactionIds);
|
||||
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||
}
|
||||
|
||||
CommandProcessingResult result = null;
|
||||
@@ -539,11 +536,16 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final LoanCharge loanCharge = retrieveLoanChargeBy(loanId, loanChargeId);
|
||||
|
||||
final Map<String, Object> changes = new LinkedHashMap<String, Object>(3);
|
||||
|
||||
final LoanTransaction waiveTransaction = loan.waiveLoanCharge(loanCharge, defaultLoanLifecycleStateMachine(), changes);
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
final LoanTransaction waiveTransaction = loan.waiveLoanCharge(loanCharge, defaultLoanLifecycleStateMachine(), changes,
|
||||
existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
this.loanTransactionRepository.save(waiveTransaction);
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
@@ -556,6 +558,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult deleteLoanCharge(final Long loanId, final Long loanChargeId, final JsonCommand command) {
|
||||
@@ -685,4 +688,17 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
.withLoanId(loanId) //
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param loan
|
||||
* @param existingTransactionIds
|
||||
* @param existingReversedTransactionIds
|
||||
*/
|
||||
private void postJournalEntries(final Loan loan, final List<Long> existingTransactionIds,
|
||||
final List<Long> existingReversedTransactionIds) {
|
||||
final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getCurrencyCode());
|
||||
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(currency.toData(), existingTransactionIds,
|
||||
existingReversedTransactionIds);
|
||||
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user