adamsaghy commented on code in PR #3983:
URL: https://github.com/apache/fineract/pull/3983#discussion_r1687609880


##########
fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualActivityProcessingServiceImpl.java:
##########
@@ -66,4 +76,98 @@ public Loan makeAccrualActivityTransaction(Loan loan, final 
LocalDate currentDat
         return loan;
     }
 
+    @Override
+    @Transactional
+    public void processAccrualActivityForLoanClosure(Loan loan) {
+        LocalDate date = loan.isOverPaid() ? loan.getOverpaidOnDate() : 
loan.getClosedOnDate();
+        List<LoanTransaction> accrualActivityTransaction = 
loan.getLoanTransactions().stream().filter(LoanTransaction::isNotReversed)
+                
.filter(LoanTransaction::isAccrualActivity).filter(loanTransaction -> 
loanTransaction.getDateOf().isAfter(date)).toList();
+        if (!accrualActivityTransaction.isEmpty()) {
+            
accrualActivityTransaction.forEach(this::reverseAccrualActivityTransaction);
+        }
+        LoanTransaction loanTransaction = 
assembleClosingAccrualActivityTransaction(loan, date);
+        if (!loanTransaction.getAmount().equals(BigDecimal.ZERO)) {
+            loanWritePlatformService.makeAccrualActivityTransaction(loan, 
loanTransaction);
+        }
+    }
+
+    private void reverseAccrualActivityTransaction(LoanTransaction 
loanTransaction) {
+        loanTransaction.reverse();
+        LoanAdjustTransactionBusinessEvent.Data data = new 
LoanAdjustTransactionBusinessEvent.Data(loanTransaction);
+        businessEventNotifierService.notifyPostBusinessEvent(new 
LoanAdjustTransactionBusinessEvent(data));
+    }
+
+    private LoanTransaction assembleClosingAccrualActivityTransaction(Loan 
loan, LocalDate date) {
+        // collect fees
+        BigDecimal feeChargesPortion = BigDecimal.ZERO;
+        // collect penalties
+        BigDecimal penaltyChargesPortion = BigDecimal.ZERO;
+        // collect interests
+        BigDecimal interestPortion = BigDecimal.ZERO;
+        var currency = loan.getCurrency();
+        // sum up all accruals
+        for (LoanRepaymentScheduleInstallment installment : 
loan.getRepaymentScheduleInstallments()) {
+            feeChargesPortion = 
installment.getFeeAccrued(currency).getAmount().add(feeChargesPortion);
+            penaltyChargesPortion = 
installment.getPenaltyAccrued(currency).getAmount().add(penaltyChargesPortion);
+            interestPortion = 
installment.getInterestAccrued(currency).getAmount().add(interestPortion);
+        }
+        List<LoanTransaction> accrualActivities = 
loan.getLoanTransactions().stream().filter(LoanTransaction::isAccrualActivity)
+                .filter(LoanTransaction::isNotReversed).toList();
+        // subtract already Posted accruals
+        for (LoanTransaction accrualActivity : accrualActivities) {
+            if (accrualActivity.getFeeChargesPortion() != null) {
+                feeChargesPortion = 
feeChargesPortion.subtract(accrualActivity.getFeeChargesPortion());
+            }
+            if (accrualActivity.getPenaltyChargesPortion() != null) {
+                penaltyChargesPortion = 
penaltyChargesPortion.subtract(accrualActivity.getPenaltyChargesPortion());
+            }
+            if (accrualActivity.getInterestPortion() != null) {
+                interestPortion = 
interestPortion.subtract(accrualActivity.getInterestPortion());
+            }
+        }
+
+        BigDecimal transactionAmount = 
feeChargesPortion.add(penaltyChargesPortion).add(interestPortion);
+        ExternalId externalId = externalIdFactory.create();
+
+        return new LoanTransaction(loan, loan.getOffice(), 
LoanTransactionType.ACCRUAL_ACTIVITY.getValue(), date, transactionAmount, null,
+                interestPortion, feeChargesPortion, penaltyChargesPortion, 
null, false, null, externalId);
+    }
+
+    @Override
+    @Transactional
+    public void processAccrualActivityForLoanReopen(Loan loan) {
+        LoanTransaction lastAccrualActivityMarkedToReverse = null;
+        List<LoanTransaction> accrualActivityTransaction = 
loan.getLoanTransactions().stream()
+                .filter(loanTransaction -> loanTransaction.isNotReversed() && 
loanTransaction.isAccrualActivity())
+                
.sorted(Comparator.comparing(LoanTransaction::getDateOf)).toList();
+        // grab the latest AccrualActivityTransaction
+        // it does not matter if it is on an installment due date or not 
because it was posted due to loan close
+        if (!accrualActivityTransaction.isEmpty()) {
+            lastAccrualActivityMarkedToReverse = 
accrualActivityTransaction.get(accrualActivityTransaction.size() - 1);
+        }
+        final LocalDate lastAccrualActivityTransactionDate = 
lastAccrualActivityMarkedToReverse == null ? null
+                : lastAccrualActivityMarkedToReverse.getDateOf();
+        LocalDate today = DateUtils.getBusinessLocalDate();
+        final List<LoanRepaymentScheduleInstallment> 
installmentsBetweenBusinessDateAndLastAccrualActivityTransactionDate = loan
+                .getRepaymentScheduleInstallments().stream()
+                .filter(installment -> 
installment.getDueDate().isBefore(today) && (lastAccrualActivityTransactionDate 
== null
+                        || 
installment.getDueDate().isAfter(lastAccrualActivityTransactionDate)
+                        // if close event happened on installment due date
+                        // we should reverse replay it to calculate 
installment related accrual parts only
+                        || 
installment.getDueDate().isEqual(lastAccrualActivityTransactionDate)))
+                
.sorted(Comparator.comparing(LoanRepaymentScheduleInstallment::getDueDate)).toList();
+        for (LoanRepaymentScheduleInstallment installment : 
installmentsBetweenBusinessDateAndLastAccrualActivityTransactionDate) {
+            if (lastAccrualActivityMarkedToReverse != null) {
+                
loanWritePlatformService.reverseReplayAccrualActivityTransaction(loan, 
lastAccrualActivityMarkedToReverse, installment,
+                        installment.getDueDate());
+                lastAccrualActivityMarkedToReverse = null;
+            } else {
+                loanWritePlatformService.makeAccrualActivityTransaction(loan, 
installment, installment.getDueDate());
+            }
+        }
+        if (lastAccrualActivityMarkedToReverse != null) {

Review Comment:
   Why do we need this extra reverse?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to