FINERACT-2060: Progressive loan - final accrual calculation on closed loan
This commit is contained in:
committed by
Arnold Gálovics
parent
c4cdd6f51a
commit
136bb0009a
+1
@@ -34,4 +34,5 @@ public class AccrualChargeData {
|
||||
private Money chargeAmount;
|
||||
private Money chargeAccruable;
|
||||
private Money chargeAccrued;
|
||||
private Money transactionAccrued;
|
||||
}
|
||||
|
||||
+10
@@ -68,10 +68,20 @@ public class AccrualPeriodData {
|
||||
return charges.stream().filter(charge -> !charge.isPenalty()).map(AccrualChargeData::getChargeAccrued).reduce(null, MathUtil::plus);
|
||||
}
|
||||
|
||||
public Money getFeeTransactionAccrued() {
|
||||
return charges.stream().filter(charge -> !charge.isPenalty()).map(AccrualChargeData::getTransactionAccrued).reduce(null,
|
||||
MathUtil::plus);
|
||||
}
|
||||
|
||||
public Money getPenaltyAccrued() {
|
||||
return charges.stream().filter(AccrualChargeData::isPenalty).map(AccrualChargeData::getChargeAccrued).reduce(null, MathUtil::plus);
|
||||
}
|
||||
|
||||
public Money getPenaltyTransactionAccrued() {
|
||||
return charges.stream().filter(AccrualChargeData::isPenalty).map(AccrualChargeData::getTransactionAccrued).reduce(null,
|
||||
MathUtil::plus);
|
||||
}
|
||||
|
||||
public Money getChargeAccruable() {
|
||||
return charges.stream().map(AccrualChargeData::getChargeAccruable).reduce(null, MathUtil::plus);
|
||||
}
|
||||
|
||||
-201
@@ -1,201 +0,0 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||
|
||||
public class LoanScheduleAccrualData {
|
||||
|
||||
private final Long loanId;
|
||||
private final Long officeId;
|
||||
private final LocalDate accruedTill;
|
||||
private final PeriodFrequencyType repaymentFrequency;
|
||||
private final Integer repayEvery;
|
||||
private final Integer installmentNumber;
|
||||
private final LocalDate dueDate;
|
||||
private final LocalDate fromDate;
|
||||
private final Long repaymentScheduleId;
|
||||
private final Long loanProductId;
|
||||
private final BigDecimal interestIncome;
|
||||
private final BigDecimal feeIncome;
|
||||
private final BigDecimal penaltyIncome;
|
||||
private final BigDecimal waivedInterestIncome;
|
||||
private final BigDecimal accruedInterestIncome;
|
||||
private final BigDecimal accruedFeeIncome;
|
||||
private final BigDecimal accruedPenaltyIncome;
|
||||
private final CurrencyData currencyData;
|
||||
private final LocalDate interestCalculatedFrom;
|
||||
|
||||
private Map<LoanChargeData, BigDecimal> applicableCharges;
|
||||
private BigDecimal dueDateFeeIncome;
|
||||
private BigDecimal dueDatePenaltyIncome;
|
||||
private BigDecimal accruableIncome;
|
||||
|
||||
private BigDecimal creditedFee;
|
||||
private BigDecimal creditedPenalty;
|
||||
|
||||
public LoanScheduleAccrualData(final Long loanId, final Long officeId, final Integer installmentNumber, final LocalDate accruedTill,
|
||||
final PeriodFrequencyType repaymentFrequency, final Integer repayEvery, final LocalDate dueDate, final LocalDate fromDate,
|
||||
final Long repaymentScheduleId, final Long loanProductId, final BigDecimal interestIncome, final BigDecimal feeIncome,
|
||||
final BigDecimal penaltyIncome, final BigDecimal accruedInterestIncome, final BigDecimal accruedFeeIncome,
|
||||
final BigDecimal accruedPenaltyIncome, final CurrencyData currencyData, final LocalDate interestCalculatedFrom,
|
||||
final BigDecimal waivedInterestIncome, BigDecimal creditedFee, BigDecimal creditedPenalty) {
|
||||
this.loanId = loanId;
|
||||
this.installmentNumber = installmentNumber;
|
||||
this.officeId = officeId;
|
||||
this.accruedTill = accruedTill;
|
||||
this.dueDate = dueDate;
|
||||
this.fromDate = fromDate;
|
||||
this.repaymentScheduleId = repaymentScheduleId;
|
||||
this.loanProductId = loanProductId;
|
||||
this.interestIncome = interestIncome;
|
||||
this.feeIncome = feeIncome;
|
||||
this.penaltyIncome = penaltyIncome;
|
||||
this.accruedFeeIncome = accruedFeeIncome;
|
||||
this.accruedInterestIncome = accruedInterestIncome;
|
||||
this.accruedPenaltyIncome = accruedPenaltyIncome;
|
||||
this.currencyData = currencyData;
|
||||
this.repaymentFrequency = repaymentFrequency;
|
||||
this.repayEvery = repayEvery;
|
||||
this.interestCalculatedFrom = interestCalculatedFrom;
|
||||
this.waivedInterestIncome = waivedInterestIncome;
|
||||
this.creditedFee = creditedFee;
|
||||
this.creditedPenalty = creditedPenalty;
|
||||
}
|
||||
|
||||
public Long getLoanId() {
|
||||
return this.loanId;
|
||||
}
|
||||
|
||||
public Long getOfficeId() {
|
||||
return this.officeId;
|
||||
}
|
||||
|
||||
public LocalDate getDueDate() {
|
||||
return this.dueDate;
|
||||
}
|
||||
|
||||
public LocalDate getDueDateAsLocaldate() {
|
||||
return this.dueDate;
|
||||
}
|
||||
|
||||
public Long getRepaymentScheduleId() {
|
||||
return this.repaymentScheduleId;
|
||||
}
|
||||
|
||||
public Long getLoanProductId() {
|
||||
return this.loanProductId;
|
||||
}
|
||||
|
||||
public BigDecimal getInterestIncome() {
|
||||
return this.interestIncome;
|
||||
}
|
||||
|
||||
public BigDecimal getFeeIncome() {
|
||||
return this.feeIncome;
|
||||
}
|
||||
|
||||
public BigDecimal getPenaltyIncome() {
|
||||
return this.penaltyIncome;
|
||||
}
|
||||
|
||||
public BigDecimal getAccruedInterestIncome() {
|
||||
return this.accruedInterestIncome;
|
||||
}
|
||||
|
||||
public BigDecimal getAccruedFeeIncome() {
|
||||
return this.accruedFeeIncome;
|
||||
}
|
||||
|
||||
public BigDecimal getAccruedPenaltyIncome() {
|
||||
return this.accruedPenaltyIncome;
|
||||
}
|
||||
|
||||
public CurrencyData getCurrencyData() {
|
||||
return this.currencyData;
|
||||
}
|
||||
|
||||
public LocalDate getAccruedTill() {
|
||||
return this.accruedTill;
|
||||
}
|
||||
|
||||
public LocalDate getFromDateAsLocaldate() {
|
||||
return this.fromDate;
|
||||
}
|
||||
|
||||
public PeriodFrequencyType getRepaymentFrequency() {
|
||||
return this.repaymentFrequency;
|
||||
}
|
||||
|
||||
public Integer getRepayEvery() {
|
||||
return this.repayEvery;
|
||||
}
|
||||
|
||||
public LocalDate getInterestCalculatedFrom() {
|
||||
return this.interestCalculatedFrom;
|
||||
}
|
||||
|
||||
public Integer getInstallmentNumber() {
|
||||
return this.installmentNumber;
|
||||
}
|
||||
|
||||
public Map<LoanChargeData, BigDecimal> getApplicableCharges() {
|
||||
return this.applicableCharges;
|
||||
}
|
||||
|
||||
public BigDecimal getDueDateFeeIncome() {
|
||||
return this.dueDateFeeIncome;
|
||||
}
|
||||
|
||||
public BigDecimal getDueDatePenaltyIncome() {
|
||||
return this.dueDatePenaltyIncome;
|
||||
}
|
||||
|
||||
public void updateChargeDetails(final Map<LoanChargeData, BigDecimal> applicableCharges, final BigDecimal dueDateFeeIncome,
|
||||
final BigDecimal dueDatePenaltyIncome) {
|
||||
this.applicableCharges = applicableCharges;
|
||||
this.dueDateFeeIncome = dueDateFeeIncome;
|
||||
this.dueDatePenaltyIncome = dueDatePenaltyIncome;
|
||||
}
|
||||
|
||||
public BigDecimal getWaivedInterestIncome() {
|
||||
return this.waivedInterestIncome;
|
||||
}
|
||||
|
||||
public BigDecimal getAccruableIncome() {
|
||||
return this.accruableIncome;
|
||||
}
|
||||
|
||||
public void updateAccruableIncome(BigDecimal accruableIncome) {
|
||||
this.accruableIncome = accruableIncome;
|
||||
}
|
||||
|
||||
public BigDecimal getCreditedFee() {
|
||||
return this.creditedFee;
|
||||
}
|
||||
|
||||
public BigDecimal getCreditedPenalty() {
|
||||
return this.creditedPenalty;
|
||||
}
|
||||
|
||||
}
|
||||
+10
-1
@@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.domain;
|
||||
|
||||
import static org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType.PROGRESSIVE;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
@@ -740,6 +742,9 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
* is lesser than todays date. If not, the transaction date is set to todays date
|
||||
*/
|
||||
public LoanTransaction handleChargeAppliedTransaction(final LoanCharge loanCharge, final LocalDate suppliedTransactionDate) {
|
||||
if (isProgressiveSchedule()) {
|
||||
return null;
|
||||
}
|
||||
final Money chargeAmount = loanCharge.getAmount(getCurrency());
|
||||
Money feeCharges = chargeAmount;
|
||||
Money penaltyCharges = Money.zero(getCurrency());
|
||||
@@ -1053,7 +1058,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
LoanCharge charge = loanCharge;
|
||||
// add new charges
|
||||
if (loanCharge.getId() == null) {
|
||||
LoanTrancheDisbursementCharge loanTrancheDisbursementCharge = null;
|
||||
LoanTrancheDisbursementCharge loanTrancheDisbursementCharge;
|
||||
loanCharge.update(this);
|
||||
if (this.loanProduct.isMultiDisburseLoan() && loanCharge.isTrancheDisbursementCharge()) {
|
||||
loanCharge.getTrancheDisbursementCharge().getloanDisbursementDetails().updateLoan(this);
|
||||
@@ -3563,4 +3568,8 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
public LoanRepaymentScheduleTransactionProcessor getTransactionProcessor() {
|
||||
return transactionProcessorFactory.determineProcessor(transactionProcessingStrategyCode);
|
||||
}
|
||||
|
||||
public boolean isProgressiveSchedule() {
|
||||
return getLoanProductRelatedDetail().getLoanScheduleType() == PROGRESSIVE;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-4
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.service;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.time.LocalDate;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -25,13 +26,13 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
public interface LoanAccrualActivityProcessingService {
|
||||
|
||||
@Transactional
|
||||
void makeAccrualActivityTransaction(Long loanId, LocalDate currentDate);
|
||||
void makeAccrualActivityTransaction(@NotNull Long loanId, @NotNull LocalDate currentDate);
|
||||
|
||||
Loan makeAccrualActivityTransaction(Loan loan, LocalDate currentDate);
|
||||
void makeAccrualActivityTransaction(@NotNull Loan loan, @NotNull LocalDate currentDate);
|
||||
|
||||
@Transactional
|
||||
void processAccrualActivityForLoanClosure(Loan loan);
|
||||
void processAccrualActivityForLoanClosure(@NotNull Loan loan);
|
||||
|
||||
@Transactional
|
||||
void processAccrualActivityForLoanReopen(Loan loan);
|
||||
void processAccrualActivityForLoanReopen(@NotNull Loan loan);
|
||||
}
|
||||
|
||||
+8
-2
@@ -20,7 +20,9 @@ package org.apache.fineract.portfolio.loanaccount.service;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanAccrualAdjustmentTransactionBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanAccrualTransactionCreatedBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanTransactionBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
@@ -33,8 +35,12 @@ public class LoanAccrualTransactionBusinessEventServiceImpl implements LoanAccru
|
||||
@Override
|
||||
public void raiseBusinessEventForAccrualTransactions(Loan loan, List<Long> existingTransactionIds) {
|
||||
for (final LoanTransaction transaction : loan.getLoanTransactions()) {
|
||||
if (transaction.isNotReversed() && transaction.isAccrual() && !existingTransactionIds.contains(transaction.getId())) {
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanAccrualTransactionCreatedBusinessEvent(transaction));
|
||||
if (transaction.isNotReversed() && (transaction.isAccrual() || transaction.isAccrualAdjustment())
|
||||
&& !existingTransactionIds.contains(transaction.getId())) {
|
||||
LoanTransactionBusinessEvent businessEvent = transaction.isAccrual()
|
||||
? new LoanAccrualTransactionCreatedBusinessEvent(transaction)
|
||||
: new LoanAccrualAdjustmentTransactionBusinessEvent(transaction);
|
||||
businessEventNotifierService.notifyPostBusinessEvent(businessEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-5
@@ -35,16 +35,14 @@ public interface LoanAccrualsProcessingService {
|
||||
|
||||
void reprocessExistingAccruals(@NotNull Loan loan);
|
||||
|
||||
void processAccrualsForInterestRecalculation(@NotNull Loan loan, boolean isInterestRecalculationEnabled);
|
||||
void processAccrualsOnInterestRecalculation(@NotNull Loan loan, boolean isInterestRecalculationEnabled, boolean addJournal);
|
||||
|
||||
void addIncomePostingAndAccruals(Long loanId) throws Exception;
|
||||
|
||||
void processIncomePostingAndAccruals(@NotNull Loan loan);
|
||||
|
||||
void addIncomeAndAccrualTransactions(Long loanId) throws Exception;
|
||||
|
||||
void processAccrualsOnLoanClosure(@NotNull Loan loan);
|
||||
|
||||
void processAccrualsOnLoanReopen(@NotNull Loan loan);
|
||||
|
||||
void processAccrualsOnLoanForeClosure(@NotNull Loan loan, @NotNull LocalDate foreClosureDate,
|
||||
@NotNull List<LoanTransaction> newAccrualTransactions);
|
||||
}
|
||||
|
||||
-11
@@ -30,7 +30,6 @@ import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
|
||||
import org.apache.fineract.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand;
|
||||
import org.apache.fineract.portfolio.collectionsheet.command.CollectionSheetBulkRepaymentCommand;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -53,16 +52,6 @@ public interface LoanWritePlatformService {
|
||||
CommandProcessingResult makeLoanRepaymentWithChargeRefundChargeType(LoanTransactionType repaymentTransactionType, Long loanId,
|
||||
JsonCommand command, boolean isRecoveryRepayment, String chargeRefundChargeType);
|
||||
|
||||
@Transactional
|
||||
Loan reverseReplayAccrualActivityTransaction(Loan loan, LoanTransaction loanTransaction, LoanRepaymentScheduleInstallment installment,
|
||||
LocalDate transactionDate);
|
||||
|
||||
@Transactional
|
||||
Loan makeAccrualActivityTransaction(Loan loan, LoanRepaymentScheduleInstallment installment, LocalDate transactionDate);
|
||||
|
||||
@Transactional
|
||||
Loan makeAccrualActivityTransaction(Loan loan, LoanTransaction accrualActivityTransaction);
|
||||
|
||||
@Transactional
|
||||
CommandProcessingResult makeInterestPaymentWaiver(JsonCommand command);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user