-
Notifications
You must be signed in to change notification settings - Fork 0
feat(CRED-100): Adds penalty calculation and repayments logic for back dated transactions #79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
Fix merge conflict |
ca962d4
to
a3d1a16
Compare
...a/com/crediblex/fineract/portfolio/loanaccount/api/CredibleXLoanTransactionsApiResource.java
Outdated
Show resolved
Hide resolved
// Default to current date if no transactionDate is provided | ||
LocalDate transactionDate; | ||
if (transactionDateDateParam == null) { | ||
transactionDate = LocalDate.now(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use local date of tenant not local date.now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated!
...java/com/crediblex/fineract/portfolio/loanaccount/domain/CredibleXLoanPenaltyCalculator.java
Outdated
Show resolved
Hide resolved
|
||
LocalDate firstPendingInstallmentDate = loanInstallments.stream() | ||
.filter(p -> p.status != ExtendedLoanSchedulePeriodData.Status.PAID | ||
&& p.status != ExtendedLoanSchedulePeriodData.Status.SCHEDULED |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't disbursment be part of the status not included?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Napho - Didn't get this one! Can you please elaborate ?
// return date != null ? date.toLocaleString() : null; | ||
// } | ||
|
||
public String loanPaymentsSummarySchema() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to keep with the fineract coding standards, thse queries need to go to a read class or an actual jpa repository class
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved this logic to a separate DAO!
return super.makeLoanRepaymentWithChargeRefundChargeType(repaymentTransactionType, loanId, command, isRecoveryRepayment, chargeRefundChargeType); | ||
} | ||
|
||
private static final class LoanRepaymentsSummaryMapper implements RowMapper<LoanSchedulePeriodData> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move this out of the write platform service class
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved!
|
||
final LoanCurrencyDataMapper loanCurrencyDataMapper = new LoanCurrencyDataMapper(); | ||
final String loanCurrencySql = loanCurrencyDataMapper.loanPaymentsSummarySchema(); | ||
final CurrencyData currency = this.jdbcTemplate.queryForObject(loanCurrencySql, loanCurrencyDataMapper, loanId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When you fetch a loan object it wil have a currency data, you dont need to fetch one here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the currency access logic and accessed it via assembled loan!
…ased-on-transaction-date
|
||
if (result != null && result.getResourceId() != null && result.getResourceId() > 0L) { | ||
this.applyOverdueChargesForSingleLoan(loanId); | ||
} | ||
return result; | ||
} | ||
|
||
@Transactional(propagation = Propagation.REQUIRES_NEW) | ||
public void applyOverdueChargesForSingleLoan(Long loanId) { | ||
final Long penaltyWaitPeriodValue = configurationDomainService.retrievePenaltyWaitPeriod(); | ||
final Boolean backdatePenalties = configurationDomainService.isBackdatePenaltiesEnabled(); | ||
|
||
final Collection<OverdueLoanScheduleData> installmentsForLoan = | ||
this.credibleXLoanReadPlatformService.retrieveOverdueInstallmentsForLoan( | ||
loanId, penaltyWaitPeriodValue, backdatePenalties); | ||
|
||
if (installmentsForLoan.isEmpty()) { | ||
return; | ||
} | ||
|
||
try { | ||
this.credibleXLoanChargeWritePlatformService.applyOverdueChargesForLoan(loanId, installmentsForLoan); | ||
|
||
} catch (final PlatformApiDataValidationException e) { | ||
// Validation errors (e.g. bad data, config issues) | ||
for (final ApiParameterError error : e.getErrors()) { | ||
log.error("Apply overdue charges failed for loan {} with validation error: {}", | ||
loanId, error.getDeveloperMessage(), e); | ||
} | ||
throw e; // rethrow so caller knows it failed | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Napho - This is the code that I have added to apply penalties to a loan after repayment is actually done. This code runs that I have confirmed. But the changes do not reflect!
…ased-on-transaction-date
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This pull request implements penalty calculation and repayment logic for back-dated transactions in the Apache Fineract system. The changes add functionality to calculate penalties up to a specific transaction date rather than the posting date, handle penalty disabling during repayments, and provide API endpoints for retrieving penalty information.
- Adds penalty calculation logic for back-dated transactions with configurable wait periods
- Implements penalty disabling mechanism when processing repayments
- Introduces new API endpoint for retrieving accrued penalties up to a given date
Reviewed Changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.
Show a summary per file
File | Description |
---|---|
LoanWritePlatformServiceJpaRepositoryImpl.java | Changes field visibility from private to protected for inheritance |
LoanReadPlatformServiceImpl.java | Makes MusoniOverdueLoanScheduleMapper class public for external access |
LoanTransactionsApiResource.java | Updates field visibility to protected for inheritance |
CustomLoanWritePlatformServiceJpaRepositoryImpl.java | Implements custom repayment logic with penalty calculation and charge management |
CustomLoanChargeReadPlatformServiceImpl.java | Provides custom loan charge reading functionality |
CredXLoanReadPlatformServiceImpl.java | Extends loan reading service with penalty calculation capabilities |
LoanRepaymentsSummaryDAO.java | Data access object for loan repayment summary queries |
CustomLoanChargeRepository.java | Repository for custom loan charge operations |
OverdueChargeHelper.java | Helper class for applying overdue charges |
CredibleXLoanPenaltyCalculator.java | Core penalty calculation logic |
ExtendedLoanSchedulePeriodData.java | Extended data class with status field |
BackdatedRepaymentPenaltyDTO.java | Data transfer object for penalty information |
CredibleXLoanTransactionsApiResource.java | API resource for penalty-related endpoints |
dependencies.gradle | Adds required dependencies for JAX-RS and Swagger annotations |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
// This is a disbursement period has nusla | ||
// ll period value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment has a typo 'nusla' and is incorrectly split across two lines. It should read 'null' on a single line.
// This is a disbursement period has nusla | |
// ll period value | |
// This is a disbursement period and has null period value |
Copilot uses AI. Check for mistakes.
.filter(p -> p.status != ExtendedLoanSchedulePeriodData.Status.PAID | ||
&& p.status != ExtendedLoanSchedulePeriodData.Status.SCHEDULED | ||
&& p.status != ExtendedLoanSchedulePeriodData.Status.DUE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The status comparison logic is inverted and unclear. Consider using a positive filter with explicit status checks like p.status == Status.OVERDUE || p.status == Status.PARTIAL_PAID
for better readability.
.filter(p -> p.status != ExtendedLoanSchedulePeriodData.Status.PAID | |
&& p.status != ExtendedLoanSchedulePeriodData.Status.SCHEDULED | |
&& p.status != ExtendedLoanSchedulePeriodData.Status.DUE) | |
.filter(p -> p.status == ExtendedLoanSchedulePeriodData.Status.OVERDUE | |
|| p.status == ExtendedLoanSchedulePeriodData.Status.PARTIAL_PAID) |
Copilot uses AI. Check for mistakes.
implementation 'jakarta.ws.rs:jakarta.ws.rs-api:3.1.0' | ||
implementation "io.swagger.core.v3:swagger-annotations:2.2.12" | ||
implementation "org.springframework.security:spring-security-core:6.1.2" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Hard-coded dependency versions should be managed centrally. Consider using version variables or a dependency management platform to ensure consistency across the project.
Copilot uses AI. Check for mistakes.
} catch (Exception e) { | ||
// Catch-all for unexpected exceptions | ||
log.error("Apply overdue charges failed for loan {}", loanId, e); | ||
throw new RuntimeException("Unexpected error while applying overdue charges for loan " + loanId, e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Generic Exception catch-all should be avoided. Consider catching specific exceptions or using a more specific exception type rather than wrapping in RuntimeException.
} catch (Exception e) { | |
// Catch-all for unexpected exceptions | |
log.error("Apply overdue charges failed for loan {}", loanId, e); | |
throw new RuntimeException("Unexpected error while applying overdue charges for loan " + loanId, e); |
Copilot uses AI. Check for mistakes.
…d transactions
Description
Describe the changes made and why they were made.
Ignore if these details are present on the associated Apache Fineract JIRA ticket.
Checklist
Please make sure these boxes are checked before submitting your pull request - thanks!
Write the commit message as per https://github.com/apache/fineract/#pull-requests
Acknowledge that we will not review PRs that are not passing the build ("green") - it is your responsibility to get a proposed PR to pass the build, not primarily the project's maintainers.
Create/update unit or integration tests for verifying the changes made.
Follow coding conventions at https://cwiki.apache.org/confluence/display/FINERACT/Coding+Conventions.
Add required Swagger annotation and update API documentation at fineract-provider/src/main/resources/static/legacy-docs/apiLive.htm with details of any API changes
Submission is not a "code dump". (Large changes can be made "in repository" via a branch. Ask on the developer mailing list for guidance, if required.)
FYI our guidelines for code reviews are at https://cwiki.apache.org/confluence/display/FINERACT/Code+Review+Guide.