Skip to content

Conversation

hamzafarooqX
Copy link
Collaborator

…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.

@hamzafarooqX hamzafarooqX requested a review from Napho September 4, 2025 13:04
@caasiremos
Copy link

Fix merge conflict

@hamzafarooqX hamzafarooqX force-pushed the CRED-100-net-outstanding-to-get-updated-based-on-transaction-date branch 2 times, most recently from ca962d4 to a3d1a16 Compare September 8, 2025 08:32
// Default to current date if no transactionDate is provided
LocalDate transactionDate;
if (transactionDateDateParam == null) {
transactionDate = LocalDate.now();
Copy link

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

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated!


LocalDate firstPendingInstallmentDate = loanInstallments.stream()
.filter(p -> p.status != ExtendedLoanSchedulePeriodData.Status.PAID
&& p.status != ExtendedLoanSchedulePeriodData.Status.SCHEDULED
Copy link

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?

Copy link
Collaborator Author

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() {
Copy link

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

Copy link
Collaborator Author

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> {
Copy link

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

Copy link
Collaborator Author

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);
Copy link

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

Copy link
Collaborator Author

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!

Comment on lines 728 to 758

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

Copy link
Collaborator Author

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!

@Copilot Copilot AI review requested due to automatic review settings September 18, 2025 15:05
Copy link

@Copilot Copilot AI left a 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.

Comment on lines +223 to +224
// This is a disbursement period has nusla
// ll period value
Copy link
Preview

Copilot AI Sep 18, 2025

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.

Suggested change
// 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.

Comment on lines +65 to +67
.filter(p -> p.status != ExtendedLoanSchedulePeriodData.Status.PAID
&& p.status != ExtendedLoanSchedulePeriodData.Status.SCHEDULED
&& p.status != ExtendedLoanSchedulePeriodData.Status.DUE)
Copy link
Preview

Copilot AI Sep 18, 2025

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.

Suggested change
.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.

Comment on lines +39 to +41
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"
Copy link
Preview

Copilot AI Sep 18, 2025

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.

Comment on lines +1033 to +1036
} 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);
Copy link
Preview

Copilot AI Sep 18, 2025

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.

Suggested change
} 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants