Skip to content

Commit

Permalink
FINERACT-2107: Loan transaction Interest Refund GL Entries
Browse files Browse the repository at this point in the history
  • Loading branch information
Jose Alberto Hernandez authored and adamsaghy committed Aug 22, 2024
1 parent 7304af5 commit 5ebd342
Show file tree
Hide file tree
Showing 10 changed files with 359 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* 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 lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class LoanRefundRequestData {

private final BigDecimal principal;
private final BigDecimal interest;
private final BigDecimal feeCharges;
private final BigDecimal penaltyCharges;
private final BigDecimal overpayment;

public BigDecimal getTotalAmount() {
return principal.add(interest).add(feeCharges).add(penaltyCharges);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public class LoanTransactionEnumData {
private final boolean reAge;
private final boolean reAmortize;
private final boolean accrualActivity;
private final boolean interestRefund;

public LoanTransactionEnumData(final Long id, final String code, final String value) {
this.id = id;
Expand Down Expand Up @@ -94,6 +95,7 @@ public LoanTransactionEnumData(final Long id, final String code, final String va
this.accrualActivity = Long.valueOf(32).equals(this.id);
this.reAge = Long.valueOf(LoanTransactionType.REAGE.getValue()).equals(this.id);
this.reAmortize = Long.valueOf(LoanTransactionType.REAMORTIZE.getValue()).equals(this.id);
this.interestRefund = Long.valueOf(LoanTransactionType.INTEREST_REFUND.getValue()).equals(this.id);
}

public boolean isRepaymentType() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.apache.fineract.infrastructure.core.domain.ExternalId;
import org.apache.fineract.portfolio.delinquency.validator.LoanDelinquencyActionData;
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
import org.apache.fineract.portfolio.loanaccount.data.LoanRefundRequestData;
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;

public interface LoanAccountDomainService {
Expand Down Expand Up @@ -93,4 +94,6 @@ LoanTransaction foreCloseLoan(Loan loan, LocalDate foreClourseDate, String noteT
LoanTransaction creditBalanceRefund(Loan loan, LocalDate transactionDate, BigDecimal transactionAmount, String noteText,
ExternalId externalId, PaymentDetail paymentDetail);

LoanTransaction applyInterestRefund(Loan loan, LoanRefundRequestData loanRefundRequest);

}
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,13 @@ public static LoanTransaction refundForActiveLoan(final Office office, final Mon
externalId);
}

public static LoanTransaction interestRefund(final Loan loan, final Office office, final BigDecimal amount, final BigDecimal principal,
final BigDecimal interest, final BigDecimal feeCharges, final BigDecimal penaltyCharges, final PaymentDetail paymentDetail,
final LocalDate refundDate, final ExternalId externalId) {
return new LoanTransaction(loan, office, LoanTransactionType.INTEREST_REFUND.getValue(), refundDate, amount, principal, interest,
feeCharges, penaltyCharges, amount, false, paymentDetail, externalId);
}

public static boolean transactionAmountsMatch(final MonetaryCurrency currency, final LoanTransaction loanTransaction,
final LoanTransaction newLoanTransaction) {
return loanTransaction.getAmount(currency).isEqualTo(newLoanTransaction.getAmount(currency))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,15 @@ else if (loanTransactionDTO.getTransactionType().isChargeoff()) {
createJournalEntriesForChargeOff(loanDTO, loanTransactionDTO, office);
}
// Logic for Interest Payment Waiver
else if (loanTransactionDTO.getTransactionType().isInterestPaymentWaiver()) {
createJournalEntriesForInterestPaymentWaiver(loanDTO, loanTransactionDTO, office);
else if (loanTransactionDTO.getTransactionType().isInterestPaymentWaiver()
|| loanTransactionDTO.getTransactionType().isInterestRefund()) {
createJournalEntriesForInterestPaymentWaiverOrInterestRefund(loanDTO, loanTransactionDTO, office);
}
}
}

private void createJournalEntriesForInterestPaymentWaiver(LoanDTO loanDTO, LoanTransactionDTO loanTransactionDTO, Office office) {
private void createJournalEntriesForInterestPaymentWaiverOrInterestRefund(LoanDTO loanDTO, LoanTransactionDTO loanTransactionDTO,
Office office) {
final Long loanProductId = loanDTO.getLoanProductId();
final Long loanId = loanDTO.getLoanId();
final String currencyCode = loanDTO.getCurrencyCode();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.LAST_MODIFIED_BY;
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.LAST_MODIFIED_DATE;

import com.google.gson.Gson;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
Expand All @@ -41,7 +43,9 @@
import org.apache.fineract.infrastructure.core.boot.FineractProfiles;
import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer;
import org.apache.fineract.portfolio.loanaccount.data.LoanRefundRequestData;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainService;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
Expand All @@ -64,6 +68,8 @@ public class InternalLoanInformationApiResource implements InitializingBean {
private final ToApiJsonSerializer<List> toApiJsonSerializerForList;
private final ApiRequestParameterHelper apiRequestParameterHelper;
private final AdvancedPaymentDataMapper advancedPaymentDataMapper;
private final LoanAccountDomainService loanAccountDomainService;
private final Gson gson = new Gson();

@Override
@SuppressFBWarnings("SLF4J_SIGN_ONLY_FORMAT")
Expand Down Expand Up @@ -152,4 +158,23 @@ public List<AdvancedPaymentData> getAdvancedPaymentAllocationRulesOfLoan(@Contex
final Loan loan = loanRepositoryWrapper.findOneWithNotFoundDetection(loanId);
return advancedPaymentDataMapper.mapLoanPaymentAllocationRule(loan.getPaymentAllocationRules());
}

@POST
@Path("{loanId}/apply-interest-refund")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@SuppressFBWarnings("SLF4J_SIGN_ONLY_FORMAT")
public Long applyInterestRefundToLoan(@Context final UriInfo uriInfo, @PathParam("loanId") Long loanId,
final String apiRequestBodyAsJson) {
log.warn("------------------------------------------------------------");
log.warn(" ");
log.warn(" Apply Loan Transaction to Interest Refund loanId {} ", loanId);
log.warn(" ");
log.warn("------------------------------------------------------------");
LoanRefundRequestData loanRefundRequestData = gson.fromJson(apiRequestBodyAsJson, LoanRefundRequestData.class);
final Loan loan = loanRepositoryWrapper.findOneWithNotFoundDetection(loanId);
final LoanTransaction loanTransaction = loanAccountDomainService.applyInterestRefund(loan, loanRefundRequestData);
return loanTransaction.getId();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@
import org.apache.fineract.organisation.holiday.domain.Holiday;
import org.apache.fineract.organisation.holiday.domain.HolidayRepository;
import org.apache.fineract.organisation.holiday.domain.HolidayStatusType;
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.organisation.workingdays.domain.WorkingDays;
Expand All @@ -87,6 +86,7 @@
import org.apache.fineract.portfolio.group.domain.Group;
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
import org.apache.fineract.portfolio.loanaccount.data.LoanRefundRequestData;
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
import org.apache.fineract.portfolio.loanaccount.service.LoanAccrualTransactionBusinessEventService;
Expand Down Expand Up @@ -120,7 +120,6 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
private final NoteRepository noteRepository;
private final AccountTransferRepository accountTransferRepository;
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository;
private final BusinessEventNotifierService businessEventNotifierService;
private final LoanUtilService loanUtilService;
private final StandingInstructionRepository standingInstructionRepository;
Expand Down Expand Up @@ -801,4 +800,26 @@ public void disableStandingInstructionsLinkedToClosedLoan(Loan loan) {
}
}

@Override
public LoanTransaction applyInterestRefund(final Loan loan, final LoanRefundRequestData loanRefundRequest) {
final PaymentDetail paymentDetail = null;
final LocalDate transactionDate = DateUtils.getBusinessLocalDate();
final BigDecimal refundAmount = loanRefundRequest.getTotalAmount();

final List<Long> existingTransactionIds = new ArrayList<>();
final List<Long> existingReversedTransactionIds = new ArrayList<>();
existingTransactionIds.addAll(loan.findExistingTransactionIds());
existingReversedTransactionIds.addAll(loan.findExistingReversedTransactionIds());

final LoanTransaction interestRefundTransaction = LoanTransaction.interestRefund(loan, loan.getOffice(), refundAmount,
loanRefundRequest.getPrincipal(), loanRefundRequest.getInterest(), loanRefundRequest.getFeeCharges(),
loanRefundRequest.getPenaltyCharges(), paymentDetail, transactionDate, externalIdFactory.create());
interestRefundTransaction.updateLoan(loan);
saveLoanTransactionWithDataIntegrityViolationChecks(interestRefundTransaction);
loan.addLoanTransaction(interestRefundTransaction);
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds, false);

return interestRefundTransaction;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.batch.domain.BatchRequest;
import org.apache.fineract.batch.domain.BatchResponse;
import org.apache.fineract.client.models.AdvancedPaymentData;
Expand Down Expand Up @@ -100,6 +101,7 @@
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.extension.ExtendWith;

@Slf4j
@ExtendWith(LoanTestLifecycleExtension.class)
public abstract class BaseLoanIntegrationTest {

Expand Down
Loading

0 comments on commit 5ebd342

Please sign in to comment.