FINERACT-1784: Support undo waive charge for specific due date charges
This commit is contained in:
committed by
Arnold Gálovics
parent
8954de5ded
commit
2543e6f6a3
+2
-6
@@ -45,7 +45,6 @@ import org.springframework.batch.core.Job;
|
|||||||
import org.springframework.batch.core.configuration.JobLocator;
|
import org.springframework.batch.core.configuration.JobLocator;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.ApplicationListener;
|
import org.springframework.context.ApplicationListener;
|
||||||
import org.springframework.context.annotation.Lazy;
|
|
||||||
import org.springframework.context.event.ContextClosedEvent;
|
import org.springframework.context.event.ContextClosedEvent;
|
||||||
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
|
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
|
||||||
import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;
|
import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;
|
||||||
@@ -71,10 +70,6 @@ public class JobRegisterServiceImpl implements JobRegisterService, ApplicationLi
|
|||||||
|
|
||||||
private static final HashMap<String, Scheduler> SCHEDULERS = new HashMap<>(4);
|
private static final HashMap<String, Scheduler> SCHEDULERS = new HashMap<>(4);
|
||||||
|
|
||||||
@Autowired
|
|
||||||
@Lazy
|
|
||||||
private SchedulerStopListener schedulerStopListener;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private FineractProperties fineractProperties;
|
private FineractProperties fineractProperties;
|
||||||
|
|
||||||
@@ -99,6 +94,7 @@ public class JobRegisterServiceImpl implements JobRegisterService, ApplicationLi
|
|||||||
final JobDetail jobDetail = createJobDetail(scheduledJobDetail);
|
final JobDetail jobDetail = createJobDetail(scheduledJobDetail);
|
||||||
JobKey jobKey = jobDetail.getKey();
|
JobKey jobKey = jobDetail.getKey();
|
||||||
if (scheduler == null || !scheduler.checkExists(jobKey)) {
|
if (scheduler == null || !scheduler.checkExists(jobKey)) {
|
||||||
|
SchedulerStopListener schedulerStopListener = new SchedulerStopListener(this);
|
||||||
final String tempSchedulerName = "temp" + scheduledJobDetail.getId();
|
final String tempSchedulerName = "temp" + scheduledJobDetail.getId();
|
||||||
final Scheduler tempScheduler = createScheduler(tempSchedulerName, 1, schedulerJobListener, schedulerStopListener);
|
final Scheduler tempScheduler = createScheduler(tempSchedulerName, 1, schedulerJobListener, schedulerStopListener);
|
||||||
jobDataMap.put(SchedulerServiceConstants.SCHEDULER_NAME, tempSchedulerName);
|
jobDataMap.put(SchedulerServiceConstants.SCHEDULER_NAME, tempSchedulerName);
|
||||||
@@ -112,7 +108,7 @@ public class JobRegisterServiceImpl implements JobRegisterService, ApplicationLi
|
|||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
final String msg = "Job execution failed for job with id:" + scheduledJobDetail.getId();
|
final String msg = "Job execution failed for job with id:" + scheduledJobDetail.getId();
|
||||||
log.error("{}", msg, e);
|
log.error("{}", msg, e);
|
||||||
throw new PlatformInternalServerException("error.msg.sheduler.job.execution.failed", msg, scheduledJobDetail.getId(), e);
|
throw new PlatformInternalServerException("error.msg.scheduler.job.execution.failed", msg, scheduledJobDetail.getId(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-6
@@ -18,20 +18,16 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.infrastructure.jobs.service;
|
package org.apache.fineract.infrastructure.jobs.service;
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.quartz.JobExecutionContext;
|
import org.quartz.JobExecutionContext;
|
||||||
import org.quartz.JobExecutionException;
|
import org.quartz.JobExecutionException;
|
||||||
import org.quartz.JobListener;
|
import org.quartz.JobListener;
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Global job Listener class to Stop the temporary scheduler once job execution completes
|
* Global job Listener class to Stop the temporary scheduler once job execution completes
|
||||||
*/
|
*/
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class SchedulerStopListener implements JobListener {
|
public class SchedulerStopListener implements JobListener {
|
||||||
|
|
||||||
private static final String name = "Singlr Trigger Global Listener";
|
private static final String SINGLE_TRIGGER_GLOBAL_LISTENER = "Single Trigger Global Listener";
|
||||||
|
|
||||||
// MIFOSX-1184: This class cannot use constructor injection, because one of
|
// MIFOSX-1184: This class cannot use constructor injection, because one of
|
||||||
// its dependencies (SchedulerStopListener) has a circular dependency to
|
// its dependencies (SchedulerStopListener) has a circular dependency to
|
||||||
@@ -47,7 +43,7 @@ public class SchedulerStopListener implements JobListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return SINGLE_TRIGGER_GLOBAL_LISTENER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+4
@@ -26,6 +26,10 @@ import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourc
|
|||||||
*/
|
*/
|
||||||
public class LoanChargeNotFoundException extends AbstractPlatformResourceNotFoundException {
|
public class LoanChargeNotFoundException extends AbstractPlatformResourceNotFoundException {
|
||||||
|
|
||||||
|
public LoanChargeNotFoundException() {
|
||||||
|
super("error.msg.loanCharge.invalid", "Loan charge cannot be found");
|
||||||
|
}
|
||||||
|
|
||||||
public LoanChargeNotFoundException(final Long id) {
|
public LoanChargeNotFoundException(final Long id) {
|
||||||
super("error.msg.loanCharge.id.invalid", "Loan charge with identifier " + id + " does not exist", id);
|
super("error.msg.loanCharge.id.invalid", "Loan charge with identifier " + id + " does not exist", id);
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-15
@@ -29,38 +29,38 @@ public class LoanChargeWaiveCannotBeReversedException extends AbstractPlatformDo
|
|||||||
|
|
||||||
public String errorMessage() {
|
public String errorMessage() {
|
||||||
|
|
||||||
if (name().toString().equalsIgnoreCase("ALREADY_PAID")) {
|
if (name().equalsIgnoreCase("ALREADY_PAID")) {
|
||||||
return "This loan charge has been completely paid";
|
return "This loan charge has been completely paid";
|
||||||
} else if (name().toString().equalsIgnoreCase("ALREADY_WAIVED")) {
|
} else if (name().equalsIgnoreCase("ALREADY_WAIVED")) {
|
||||||
return "This loan charge has already been waived";
|
return "This loan charge has already been waived";
|
||||||
} else if (name().toString().equalsIgnoreCase("LOAN_INACTIVE")) {
|
} else if (name().equalsIgnoreCase("LOAN_INACTIVE")) {
|
||||||
return "This loan charge can be waived as the loan associated with it is currently inactive";
|
return "This loan charge can be waived as the loan associated with it is currently inactive";
|
||||||
} else if (name().toString().equalsIgnoreCase("WAIVE_NOT_ALLOWED_FOR_CHARGE")) {
|
} else if (name().equalsIgnoreCase("WAIVE_NOT_ALLOWED_FOR_CHARGE")) {
|
||||||
return "This loan charge can be waived";
|
return "This loan charge can be waived";
|
||||||
} else if (name().toString().equalsIgnoreCase("NOT_WAIVED")) {
|
} else if (name().equalsIgnoreCase("NOT_WAIVED")) {
|
||||||
return "This loan charge waive cannot be reversed as this charge is not waived";
|
return "This loan charge waive cannot be reversed as this charge is not waived";
|
||||||
} else if (name().toString().equalsIgnoreCase("ALREADY_REVERSED")) {
|
} else if (name().equalsIgnoreCase("ALREADY_REVERSED")) {
|
||||||
return "This loan charge waive cannot be reversed as this transaction is not reversed";
|
return "This loan charge waive cannot be reversed as this transaction is already reversed";
|
||||||
}
|
}
|
||||||
|
|
||||||
return name().toString();
|
return name();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String errorCode() {
|
public String errorCode() {
|
||||||
if (name().toString().equalsIgnoreCase("ALREADY_PAID")) {
|
if (name().equalsIgnoreCase("ALREADY_PAID")) {
|
||||||
return "error.msg.loan.charge.already.paid";
|
return "error.msg.loan.charge.already.paid";
|
||||||
} else if (name().toString().equalsIgnoreCase("ALREADY_WAIVED")) {
|
} else if (name().equalsIgnoreCase("ALREADY_WAIVED")) {
|
||||||
return "error.msg.loan.charge.already.waived";
|
return "error.msg.loan.charge.already.waived";
|
||||||
} else if (name().toString().equalsIgnoreCase("LOAN_INACTIVE")) {
|
} else if (name().equalsIgnoreCase("LOAN_INACTIVE")) {
|
||||||
return "error.msg.loan.charge.associated.loan.inactive";
|
return "error.msg.loan.charge.associated.loan.inactive";
|
||||||
} else if (name().toString().equalsIgnoreCase("WAIVE_NOT_ALLOWED_FOR_CHARGE")) {
|
} else if (name().equalsIgnoreCase("WAIVE_NOT_ALLOWED_FOR_CHARGE")) {
|
||||||
return "error.msg.loan.charge.waive.not.allowed";
|
return "error.msg.loan.charge.waive.not.allowed";
|
||||||
} else if (name().toString().equalsIgnoreCase("NOT_WAIVED")) {
|
} else if (name().equalsIgnoreCase("NOT_WAIVED")) {
|
||||||
return "error.msg.loan.charge.waive.cannot.undo";
|
return "error.msg.loan.charge.waive.cannot.undo";
|
||||||
} else if (name().toString().equalsIgnoreCase("ALREADY_REVERSED")) {
|
} else if (name().equalsIgnoreCase("ALREADY_REVERSED")) {
|
||||||
return "error.msg.transaction.cannot.reverse";
|
return "error.msg.transaction.cannot.reverse";
|
||||||
}
|
}
|
||||||
return name().toString();
|
return name();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+24
-26
@@ -35,6 +35,7 @@ import java.io.InputStream;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -208,10 +209,10 @@ import org.springframework.util.CollectionUtils;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class LoansApiResource {
|
public class LoansApiResource {
|
||||||
|
|
||||||
private final Set<String> loanDataParameters = new HashSet<>(Arrays.asList("id", "accountNo", "status", "externalId", "clientId",
|
private static final Set<String> LOAN_DATA_PARAMETERS = new HashSet<>(Arrays.asList("id", "accountNo", "status", "externalId",
|
||||||
"group", "loanProductId", "loanProductName", "loanProductDescription", "isLoanProductLinkedToFloatingRate", "fundId",
|
"clientId", "group", "loanProductId", "loanProductName", "loanProductDescription", "isLoanProductLinkedToFloatingRate",
|
||||||
"fundName", "loanPurposeId", "loanPurposeName", "loanOfficerId", "loanOfficerName", "currency", "principal", "totalOverpaid",
|
"fundId", "fundName", "loanPurposeId", "loanPurposeName", "loanOfficerId", "loanOfficerName", "currency", "principal",
|
||||||
"inArrearsTolerance", "termFrequency", "termPeriodFrequencyType", "numberOfRepayments", "repaymentEvery",
|
"totalOverpaid", "inArrearsTolerance", "termFrequency", "termPeriodFrequencyType", "numberOfRepayments", "repaymentEvery",
|
||||||
"interestRatePerPeriod", "annualInterestRate", "repaymentFrequencyType", "transactionProcessingStrategyId",
|
"interestRatePerPeriod", "annualInterestRate", "repaymentFrequencyType", "transactionProcessingStrategyId",
|
||||||
"transactionProcessingStrategyName", "interestRateFrequencyType", "amortizationType", "interestType",
|
"transactionProcessingStrategyName", "interestRateFrequencyType", "amortizationType", "interestType",
|
||||||
"interestCalculationPeriodType", LoanProductConstants.ALLOW_PARTIAL_PERIOD_INTEREST_CALCUALTION_PARAM_NAME,
|
"interestCalculationPeriodType", LoanProductConstants.ALLOW_PARTIAL_PERIOD_INTEREST_CALCUALTION_PARAM_NAME,
|
||||||
@@ -228,10 +229,10 @@ public class LoansApiResource {
|
|||||||
LoanApiConstants.datatables, LoanProductConstants.RATES_PARAM_NAME, LoanApiConstants.MULTIDISBURSE_DETAILS_PARAMNAME,
|
LoanApiConstants.datatables, LoanProductConstants.RATES_PARAM_NAME, LoanApiConstants.MULTIDISBURSE_DETAILS_PARAMNAME,
|
||||||
LoanApiConstants.EMI_AMOUNT_VARIATIONS_PARAMNAME, LoanApiConstants.COLLECTION_PARAMNAME));
|
LoanApiConstants.EMI_AMOUNT_VARIATIONS_PARAMNAME, LoanApiConstants.COLLECTION_PARAMNAME));
|
||||||
|
|
||||||
private final Set<String> loanApprovalDataParameters = new HashSet<>(Arrays.asList("approvalDate", "approvalAmount"));
|
private static final Set<String> LOAN_APPROVAL_DATA_PARAMETERS = new HashSet<>(Arrays.asList("approvalDate", "approvalAmount"));
|
||||||
final Set<String> glimAccountsDataParameters = new HashSet<>(Arrays.asList("glimId", "groupId", "clientId", "parentLoanAccountNo",
|
private static final Set<String> GLIM_ACCOUNTS_DATA_PARAMETERS = new HashSet<>(Arrays.asList("glimId", "groupId", "clientId",
|
||||||
"parentPrincipalAmount", "childLoanAccountNo", "childPrincipalAmount", "clientName"));
|
"parentLoanAccountNo", "parentPrincipalAmount", "childLoanAccountNo", "childPrincipalAmount", "clientName"));
|
||||||
private final String resourceNameForPermissions = "LOAN";
|
private static final String RESOURCE_NAME_FOR_PERMISSIONS = "LOAN";
|
||||||
|
|
||||||
private final PlatformSecurityContext context;
|
private final PlatformSecurityContext context;
|
||||||
private final LoanReadPlatformService loanReadPlatformService;
|
private final LoanReadPlatformService loanReadPlatformService;
|
||||||
@@ -281,7 +282,7 @@ public class LoansApiResource {
|
|||||||
@QueryParam("templateType") @Parameter(description = "templateType") final String templateType,
|
@QueryParam("templateType") @Parameter(description = "templateType") final String templateType,
|
||||||
@Context final UriInfo uriInfo) {
|
@Context final UriInfo uriInfo) {
|
||||||
|
|
||||||
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
|
this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
|
||||||
|
|
||||||
LoanApprovalData loanApprovalTemplate = null;
|
LoanApprovalData loanApprovalTemplate = null;
|
||||||
|
|
||||||
@@ -293,7 +294,7 @@ public class LoansApiResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||||
return this.loanApprovalDataToApiJsonSerializer.serialize(settings, loanApprovalTemplate, this.loanApprovalDataParameters);
|
return this.loanApprovalDataToApiJsonSerializer.serialize(settings, loanApprovalTemplate, LOAN_APPROVAL_DATA_PARAMETERS);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,7 +316,7 @@ public class LoansApiResource {
|
|||||||
@DefaultValue("false") @QueryParam("activeOnly") @Parameter(description = "activeOnly") final boolean onlyActive,
|
@DefaultValue("false") @QueryParam("activeOnly") @Parameter(description = "activeOnly") final boolean onlyActive,
|
||||||
@Context final UriInfo uriInfo) {
|
@Context final UriInfo uriInfo) {
|
||||||
|
|
||||||
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
|
this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
|
||||||
|
|
||||||
// template
|
// template
|
||||||
final Collection<LoanProductData> productOptions = this.loanProductReadPlatformService.retrieveAllLoanProductsForLookup(onlyActive);
|
final Collection<LoanProductData> productOptions = this.loanProductReadPlatformService.retrieveAllLoanProductsForLookup(onlyActive);
|
||||||
@@ -412,7 +413,7 @@ public class LoansApiResource {
|
|||||||
newLoanAccount.setDatatables(datatableTemplates);
|
newLoanAccount.setDatatables(datatableTemplates);
|
||||||
|
|
||||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||||
return this.toApiJsonSerializer.serialize(settings, newLoanAccount, this.loanDataParameters);
|
return this.toApiJsonSerializer.serialize(settings, newLoanAccount, LOAN_DATA_PARAMETERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Collection<PortfolioAccountData> getaccountLinkingOptions(final LoanAccountData newLoanAccount, final Long clientId,
|
private Collection<PortfolioAccountData> getaccountLinkingOptions(final LoanAccountData newLoanAccount, final Long clientId,
|
||||||
@@ -448,7 +449,7 @@ public class LoansApiResource {
|
|||||||
@QueryParam("exclude") @Parameter(in = ParameterIn.QUERY, name = "exclude", description = "Optional Loan object relation list to be filtered in the response", required = false, example = "guarantors,futureSchedule") final String exclude,
|
@QueryParam("exclude") @Parameter(in = ParameterIn.QUERY, name = "exclude", description = "Optional Loan object relation list to be filtered in the response", required = false, example = "guarantors,futureSchedule") final String exclude,
|
||||||
@QueryParam("fields") @Parameter(in = ParameterIn.QUERY, name = "fields", description = "Optional Loan attribute list to be in the response", required = false, example = "id,principal,annualInterestRate") final String fields,
|
@QueryParam("fields") @Parameter(in = ParameterIn.QUERY, name = "fields", description = "Optional Loan attribute list to be in the response", required = false, example = "id,principal,annualInterestRate") final String fields,
|
||||||
@Context final UriInfo uriInfo) {
|
@Context final UriInfo uriInfo) {
|
||||||
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
|
this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
|
||||||
|
|
||||||
LoanAccountData loanBasicDetails = this.loanReadPlatformService.retrieveOne(loanId);
|
LoanAccountData loanBasicDetails = this.loanReadPlatformService.retrieveOne(loanId);
|
||||||
if (loanBasicDetails.isInterestRecalculationEnabled()) {
|
if (loanBasicDetails.isInterestRecalculationEnabled()) {
|
||||||
@@ -492,7 +493,7 @@ public class LoansApiResource {
|
|||||||
PortfolioAccountData linkedAccount = null;
|
PortfolioAccountData linkedAccount = null;
|
||||||
Collection<DisbursementData> disbursementData = null;
|
Collection<DisbursementData> disbursementData = null;
|
||||||
Collection<LoanTermVariationsData> emiAmountVariations = null;
|
Collection<LoanTermVariationsData> emiAmountVariations = null;
|
||||||
Collection<LoanCollateralResponseData> loanCollateralManagements = null;
|
Collection<LoanCollateralResponseData> loanCollateralManagements;
|
||||||
Collection<LoanCollateralManagementData> loanCollateralManagementData = new ArrayList<>();
|
Collection<LoanCollateralManagementData> loanCollateralManagementData = new ArrayList<>();
|
||||||
CollectionData collectionData = CollectionData.template();
|
CollectionData collectionData = CollectionData.template();
|
||||||
|
|
||||||
@@ -574,9 +575,6 @@ public class LoansApiResource {
|
|||||||
for (LoanCollateralResponseData loanCollateralManagement : loanCollateralManagements) {
|
for (LoanCollateralResponseData loanCollateralManagement : loanCollateralManagements) {
|
||||||
loanCollateralManagementData.add(loanCollateralManagement.toCommand());
|
loanCollateralManagementData.add(loanCollateralManagement.toCommand());
|
||||||
}
|
}
|
||||||
if (CollectionUtils.isEmpty(loanCollateralManagements)) {
|
|
||||||
loanCollateralManagements = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (associationParameters.contains(DataTableApiConstant.meetingAssociateParamName)) {
|
if (associationParameters.contains(DataTableApiConstant.meetingAssociateParamName)) {
|
||||||
@@ -606,7 +604,7 @@ public class LoansApiResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Collection<LoanProductData> productOptions = null;
|
Collection<LoanProductData> productOptions = null;
|
||||||
LoanProductData product = null;
|
LoanProductData product;
|
||||||
Collection<EnumOptionData> loanTermFrequencyTypeOptions = null;
|
Collection<EnumOptionData> loanTermFrequencyTypeOptions = null;
|
||||||
Collection<EnumOptionData> repaymentFrequencyTypeOptions = null;
|
Collection<EnumOptionData> repaymentFrequencyTypeOptions = null;
|
||||||
Collection<EnumOptionData> repaymentFrequencyNthDayTypeOptions = null;
|
Collection<EnumOptionData> repaymentFrequencyNthDayTypeOptions = null;
|
||||||
@@ -624,7 +622,7 @@ public class LoansApiResource {
|
|||||||
Collection<CodeValueData> loanCollateralOptions = null;
|
Collection<CodeValueData> loanCollateralOptions = null;
|
||||||
Collection<CalendarData> calendarOptions = null;
|
Collection<CalendarData> calendarOptions = null;
|
||||||
Collection<PortfolioAccountData> accountLinkingOptions = null;
|
Collection<PortfolioAccountData> accountLinkingOptions = null;
|
||||||
PaidInAdvanceData paidInAdvanceTemplate = null;
|
PaidInAdvanceData paidInAdvanceTemplate;
|
||||||
Collection<LoanAccountSummaryData> clientActiveLoanOptions = null;
|
Collection<LoanAccountSummaryData> clientActiveLoanOptions = null;
|
||||||
|
|
||||||
final boolean template = ApiParameterHelper.template(uriInfo.getQueryParameters());
|
final boolean template = ApiParameterHelper.template(uriInfo.getQueryParameters());
|
||||||
@@ -640,7 +638,7 @@ public class LoansApiResource {
|
|||||||
|
|
||||||
amortizationTypeOptions = this.dropdownReadPlatformService.retrieveLoanAmortizationTypeOptions();
|
amortizationTypeOptions = this.dropdownReadPlatformService.retrieveLoanAmortizationTypeOptions();
|
||||||
if (product.isLinkedToFloatingInterestRates()) {
|
if (product.isLinkedToFloatingInterestRates()) {
|
||||||
interestTypeOptions = Arrays.asList(interestType(InterestMethod.DECLINING_BALANCE));
|
interestTypeOptions = Collections.singletonList(interestType(InterestMethod.DECLINING_BALANCE));
|
||||||
} else {
|
} else {
|
||||||
interestTypeOptions = this.dropdownReadPlatformService.retrieveLoanInterestTypeOptions();
|
interestTypeOptions = this.dropdownReadPlatformService.retrieveLoanInterestTypeOptions();
|
||||||
}
|
}
|
||||||
@@ -710,7 +708,7 @@ public class LoansApiResource {
|
|||||||
|
|
||||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters(),
|
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters(),
|
||||||
mandatoryResponseParameters);
|
mandatoryResponseParameters);
|
||||||
return this.toApiJsonSerializer.serialize(settings, loanAccount, this.loanDataParameters);
|
return this.toApiJsonSerializer.serialize(settings, loanAccount, LOAN_DATA_PARAMETERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@@ -731,7 +729,7 @@ public class LoansApiResource {
|
|||||||
@QueryParam("sortOrder") @Parameter(description = "sortOrder") final String sortOrder,
|
@QueryParam("sortOrder") @Parameter(description = "sortOrder") final String sortOrder,
|
||||||
@QueryParam("accountNo") @Parameter(description = "accountNo") final String accountNo) {
|
@QueryParam("accountNo") @Parameter(description = "accountNo") final String accountNo) {
|
||||||
|
|
||||||
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
|
this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
|
||||||
|
|
||||||
final SearchParameters searchParameters = SearchParameters.forLoans(sqlSearch, externalId, offset, limit, orderBy, sortOrder,
|
final SearchParameters searchParameters = SearchParameters.forLoans(sqlSearch, externalId, offset, limit, orderBy, sortOrder,
|
||||||
accountNo);
|
accountNo);
|
||||||
@@ -739,7 +737,7 @@ public class LoansApiResource {
|
|||||||
final Page<LoanAccountData> loanBasicDetails = this.loanReadPlatformService.retrieveAll(searchParameters);
|
final Page<LoanAccountData> loanBasicDetails = this.loanReadPlatformService.retrieveAll(searchParameters);
|
||||||
|
|
||||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||||
return this.toApiJsonSerializer.serialize(settings, loanBasicDetails, this.loanDataParameters);
|
return this.toApiJsonSerializer.serialize(settings, loanBasicDetails, LOAN_DATA_PARAMETERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
@@ -767,7 +765,7 @@ public class LoansApiResource {
|
|||||||
final LoanScheduleModel loanSchedule = this.calculationPlatformService.calculateLoanSchedule(query, true);
|
final LoanScheduleModel loanSchedule = this.calculationPlatformService.calculateLoanSchedule(query, true);
|
||||||
|
|
||||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||||
return this.loanScheduleToApiJsonSerializer.serialize(settings, loanSchedule.toData(), new HashSet<String>());
|
return this.loanScheduleToApiJsonSerializer.serialize(settings, loanSchedule.toData(), new HashSet<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().createLoanApplication().withJson(apiRequestBodyAsJson).build();
|
final CommandWrapper commandRequest = new CommandWrapperBuilder().createLoanApplication().withJson(apiRequestBodyAsJson).build();
|
||||||
@@ -889,10 +887,10 @@ public class LoansApiResource {
|
|||||||
@Consumes({ MediaType.APPLICATION_JSON })
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
@Produces({ MediaType.APPLICATION_JSON })
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
public String getGlimRepaymentTemplate(@PathParam("glimId") final Long glimId, @Context final UriInfo uriInfo) {
|
public String getGlimRepaymentTemplate(@PathParam("glimId") final Long glimId, @Context final UriInfo uriInfo) {
|
||||||
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
|
this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
|
||||||
Collection<GlimRepaymentTemplate> glimRepaymentTemplate = this.glimAccountInfoReadPlatformService.findglimRepaymentTemplate(glimId);
|
Collection<GlimRepaymentTemplate> glimRepaymentTemplate = this.glimAccountInfoReadPlatformService.findglimRepaymentTemplate(glimId);
|
||||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||||
return this.glimTemplateToApiJsonSerializer.serialize(settings, glimRepaymentTemplate, this.glimAccountsDataParameters);
|
return this.glimTemplateToApiJsonSerializer.serialize(settings, glimRepaymentTemplate, GLIM_ACCOUNTS_DATA_PARAMETERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
|
|||||||
+17
-8
@@ -567,9 +567,16 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
return this.summary;
|
return this.summary;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateLoanSummaryForUndoWaiveCharge(final BigDecimal amountWaived) {
|
public void updateLoanSummaryForUndoWaiveCharge(final BigDecimal amountWaived, final boolean isPenalty) {
|
||||||
this.summary.updateFeeChargesWaived(this.summary.getTotalFeeChargesWaived().subtract(amountWaived));
|
if (isPenalty) {
|
||||||
this.summary.updateFeeChargeOutstanding(this.summary.getTotalFeeChargesOutstanding().add(amountWaived));
|
this.summary.updatePenaltyChargesWaived(this.summary.getTotalPenaltyChargesWaived().subtract(amountWaived));
|
||||||
|
this.summary.updatePenaltyChargeOutstanding(this.summary.getTotalPenaltyChargesOutstanding().add(amountWaived));
|
||||||
|
} else {
|
||||||
|
this.summary.updateFeeChargesWaived(this.summary.getTotalFeeChargesWaived().subtract(amountWaived));
|
||||||
|
this.summary.updateFeeChargeOutstanding(this.summary.getTotalFeeChargesOutstanding().add(amountWaived));
|
||||||
|
}
|
||||||
|
this.summary.updateTotalOutstanding(this.summary.getTotalOutstanding().add(amountWaived));
|
||||||
|
this.summary.updateTotalWaived(this.summary.getTotalWaived().subtract(amountWaived));
|
||||||
}
|
}
|
||||||
|
|
||||||
private BigDecimal deriveSumTotalOfChargesDueAtDisbursement() {
|
private BigDecimal deriveSumTotalOfChargesDueAtDisbursement() {
|
||||||
@@ -1377,7 +1384,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
|
|
||||||
final Money principal = this.loanRepaymentScheduleDetail.getPrincipal();
|
final Money principal = this.loanRepaymentScheduleDetail.getPrincipal();
|
||||||
this.summary.updateSummary(loanCurrency(), principal, getRepaymentScheduleInstallments(), this.loanSummaryWrapper,
|
this.summary.updateSummary(loanCurrency(), principal, getRepaymentScheduleInstallments(), this.loanSummaryWrapper,
|
||||||
isDisbursed(), this.charges);
|
this.charges);
|
||||||
updateLoanOutstandingBalances();
|
updateLoanOutstandingBalances();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2051,20 +2058,22 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
|
|
||||||
if (submittedOn.isAfter(DateUtils.getBusinessLocalDate())) {
|
if (submittedOn.isAfter(DateUtils.getBusinessLocalDate())) {
|
||||||
final String errorMessage = "The date on which a loan is submitted cannot be in the future.";
|
final String errorMessage = "The date on which a loan is submitted cannot be in the future.";
|
||||||
throw new InvalidLoanStateTransitionException("submittal", "cannot.be.a.future.date", errorMessage, submittedOn);
|
throw new InvalidLoanStateTransitionException("submittal", "cannot.be.a.future.date", errorMessage, submittedOn,
|
||||||
|
DateUtils.getBusinessLocalDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.client != null && this.client.isActivatedAfter(submittedOn)) {
|
if (this.client != null && this.client.isActivatedAfter(submittedOn)) {
|
||||||
final String errorMessage = "The date on which a loan is submitted cannot be earlier than client's activation date.";
|
final String errorMessage = "The date on which a loan is submitted cannot be earlier than client's activation date.";
|
||||||
throw new InvalidLoanStateTransitionException("submittal", "cannot.be.before.client.activation.date", errorMessage,
|
throw new InvalidLoanStateTransitionException("submittal", "cannot.be.before.client.activation.date", errorMessage, submittedOn,
|
||||||
submittedOn);
|
client.getActivationLocalDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_CREATED, submittedOn);
|
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_CREATED, submittedOn);
|
||||||
|
|
||||||
if (this.group != null && this.group.isActivatedAfter(submittedOn)) {
|
if (this.group != null && this.group.isActivatedAfter(submittedOn)) {
|
||||||
final String errorMessage = "The date on which a loan is submitted cannot be earlier than groups's activation date.";
|
final String errorMessage = "The date on which a loan is submitted cannot be earlier than groups's activation date.";
|
||||||
throw new InvalidLoanStateTransitionException("submittal", "cannot.be.before.group.activation.date", errorMessage, submittedOn);
|
throw new InvalidLoanStateTransitionException("submittal", "cannot.be.before.group.activation.date", errorMessage, submittedOn,
|
||||||
|
group.getActivationLocalDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (submittedOn.isAfter(getExpectedDisbursedOnLocalDate())) {
|
if (submittedOn.isAfter(getExpectedDisbursedOnLocalDate())) {
|
||||||
|
|||||||
+12
-8
@@ -358,7 +358,7 @@ public class LoanCharge extends AbstractPersistableCustom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetOutstandingAmount(final BigDecimal amountOutstanding) {
|
public void setOutstandingAmount(final BigDecimal amountOutstanding) {
|
||||||
this.amountOutstanding = amountOutstanding;
|
this.amountOutstanding = amountOutstanding;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -659,7 +659,7 @@ public class LoanCharge extends AbstractPersistableCustom {
|
|||||||
* amount is within min and max cap
|
* amount is within min and max cap
|
||||||
*/
|
*/
|
||||||
private BigDecimal minimumAndMaximumCap(final BigDecimal percentageOf) {
|
private BigDecimal minimumAndMaximumCap(final BigDecimal percentageOf) {
|
||||||
BigDecimal minMaxCap = BigDecimal.ZERO;
|
BigDecimal minMaxCap;
|
||||||
if (this.minCap != null) {
|
if (this.minCap != null) {
|
||||||
final int minimumCap = percentageOf.compareTo(this.minCap);
|
final int minimumCap = percentageOf.compareTo(this.minCap);
|
||||||
if (minimumCap == -1) {
|
if (minimumCap == -1) {
|
||||||
@@ -789,7 +789,7 @@ public class LoanCharge extends AbstractPersistableCustom {
|
|||||||
* @return Actual amount paid on this charge
|
* @return Actual amount paid on this charge
|
||||||
*/
|
*/
|
||||||
public Money updatePaidAmountBy(final Money incrementBy, final Integer installmentNumber, final Money feeAmount) {
|
public Money updatePaidAmountBy(final Money incrementBy, final Integer installmentNumber, final Money feeAmount) {
|
||||||
Money processAmount = Money.zero(incrementBy.getCurrency());
|
Money processAmount;
|
||||||
if (isInstalmentFee()) {
|
if (isInstalmentFee()) {
|
||||||
if (installmentNumber == null) {
|
if (installmentNumber == null) {
|
||||||
processAmount = getUnpaidInstallmentLoanCharge().updatePaidAmountBy(incrementBy, feeAmount);
|
processAmount = getUnpaidInstallmentLoanCharge().updatePaidAmountBy(incrementBy, feeAmount);
|
||||||
@@ -802,7 +802,7 @@ public class LoanCharge extends AbstractPersistableCustom {
|
|||||||
Money amountPaidToDate = Money.of(processAmount.getCurrency(), this.amountPaid);
|
Money amountPaidToDate = Money.of(processAmount.getCurrency(), this.amountPaid);
|
||||||
final Money amountOutstanding = Money.of(processAmount.getCurrency(), this.amountOutstanding);
|
final Money amountOutstanding = Money.of(processAmount.getCurrency(), this.amountOutstanding);
|
||||||
|
|
||||||
Money amountPaidOnThisCharge = Money.zero(processAmount.getCurrency());
|
Money amountPaidOnThisCharge;
|
||||||
if (processAmount.isGreaterThanOrEqualTo(amountOutstanding)) {
|
if (processAmount.isGreaterThanOrEqualTo(amountOutstanding)) {
|
||||||
amountPaidOnThisCharge = amountOutstanding;
|
amountPaidOnThisCharge = amountOutstanding;
|
||||||
amountPaidToDate = amountPaidToDate.plus(amountOutstanding);
|
amountPaidToDate = amountPaidToDate.plus(amountOutstanding);
|
||||||
@@ -890,7 +890,7 @@ public class LoanCharge extends AbstractPersistableCustom {
|
|||||||
|
|
||||||
public LoanInstallmentCharge getInstallmentLoanCharge(final Integer installmentNumber) {
|
public LoanInstallmentCharge getInstallmentLoanCharge(final Integer installmentNumber) {
|
||||||
for (final LoanInstallmentCharge loanChargePerInstallment : this.loanInstallmentCharge) {
|
for (final LoanInstallmentCharge loanChargePerInstallment : this.loanInstallmentCharge) {
|
||||||
if (installmentNumber.equals(loanChargePerInstallment.getRepaymentInstallment().getInstallmentNumber().intValue())) {
|
if (installmentNumber.equals(loanChargePerInstallment.getRepaymentInstallment().getInstallmentNumber())) {
|
||||||
return loanChargePerInstallment;
|
return loanChargePerInstallment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -900,7 +900,7 @@ public class LoanCharge extends AbstractPersistableCustom {
|
|||||||
public void setInstallmentLoanCharge(final LoanInstallmentCharge loanInstallmentCharge, final Integer installmentNumber) {
|
public void setInstallmentLoanCharge(final LoanInstallmentCharge loanInstallmentCharge, final Integer installmentNumber) {
|
||||||
LoanInstallmentCharge loanInstallmentChargeToBeRemoved = null;
|
LoanInstallmentCharge loanInstallmentChargeToBeRemoved = null;
|
||||||
for (final LoanInstallmentCharge loanChargePerInstallment : this.loanInstallmentCharge) {
|
for (final LoanInstallmentCharge loanChargePerInstallment : this.loanInstallmentCharge) {
|
||||||
if (installmentNumber.equals(loanChargePerInstallment.getRepaymentInstallment().getInstallmentNumber().intValue())) {
|
if (installmentNumber.equals(loanChargePerInstallment.getRepaymentInstallment().getInstallmentNumber())) {
|
||||||
loanInstallmentChargeToBeRemoved = loanChargePerInstallment;
|
loanInstallmentChargeToBeRemoved = loanChargePerInstallment;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1017,7 +1017,7 @@ public class LoanCharge extends AbstractPersistableCustom {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Money undoPaidOrPartiallyAmountBy(final Money incrementBy, final Integer installmentNumber, final Money feeAmount) {
|
public Money undoPaidOrPartiallyAmountBy(final Money incrementBy, final Integer installmentNumber, final Money feeAmount) {
|
||||||
Money processAmount = Money.zero(incrementBy.getCurrency());
|
Money processAmount;
|
||||||
if (isInstalmentFee()) {
|
if (isInstalmentFee()) {
|
||||||
if (installmentNumber == null) {
|
if (installmentNumber == null) {
|
||||||
processAmount = getLastPaidOrPartiallyPaidInstallmentLoanCharge(incrementBy.getCurrency()).undoPaidAmountBy(incrementBy,
|
processAmount = getLastPaidOrPartiallyPaidInstallmentLoanCharge(incrementBy.getCurrency()).undoPaidAmountBy(incrementBy,
|
||||||
@@ -1030,7 +1030,7 @@ public class LoanCharge extends AbstractPersistableCustom {
|
|||||||
}
|
}
|
||||||
Money amountPaidToDate = Money.of(processAmount.getCurrency(), this.amountPaid);
|
Money amountPaidToDate = Money.of(processAmount.getCurrency(), this.amountPaid);
|
||||||
|
|
||||||
Money amountDeductedOnThisCharge = Money.zero(processAmount.getCurrency());
|
Money amountDeductedOnThisCharge;
|
||||||
if (processAmount.isGreaterThanOrEqualTo(amountPaidToDate)) {
|
if (processAmount.isGreaterThanOrEqualTo(amountPaidToDate)) {
|
||||||
amountDeductedOnThisCharge = amountPaidToDate;
|
amountDeductedOnThisCharge = amountPaidToDate;
|
||||||
amountPaidToDate = Money.zero(processAmount.getCurrency());
|
amountPaidToDate = Money.zero(processAmount.getCurrency());
|
||||||
@@ -1097,4 +1097,8 @@ public class LoanCharge extends AbstractPersistableCustom {
|
|||||||
this.externalId = externalId;
|
this.externalId = externalId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ChargeTimeType getChargeTimeType() {
|
||||||
|
return ChargeTimeType.fromInt(this.chargeTime);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -185,7 +185,7 @@ public class LoanInstallmentCharge extends AbstractPersistableCustom implements
|
|||||||
Money amountPaidToDate = Money.of(incrementBy.getCurrency(), this.amountPaid);
|
Money amountPaidToDate = Money.of(incrementBy.getCurrency(), this.amountPaid);
|
||||||
final Money amountOutstanding = Money.of(incrementBy.getCurrency(), this.amountOutstanding);
|
final Money amountOutstanding = Money.of(incrementBy.getCurrency(), this.amountOutstanding);
|
||||||
Money amountPaidPreviously = amountPaidToDate;
|
Money amountPaidPreviously = amountPaidToDate;
|
||||||
Money amountPaidOnThisCharge = Money.zero(incrementBy.getCurrency());
|
Money amountPaidOnThisCharge;
|
||||||
if (incrementBy.isGreaterThanOrEqualTo(amountOutstanding)) {
|
if (incrementBy.isGreaterThanOrEqualTo(amountOutstanding)) {
|
||||||
amountPaidOnThisCharge = amountOutstanding;
|
amountPaidOnThisCharge = amountOutstanding;
|
||||||
amountPaidToDate = amountPaidToDate.plus(amountOutstanding);
|
amountPaidToDate = amountPaidToDate.plus(amountOutstanding);
|
||||||
@@ -226,7 +226,7 @@ public class LoanInstallmentCharge extends AbstractPersistableCustom implements
|
|||||||
this.paid = false;
|
this.paid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetAmountWaived(final BigDecimal amountWaived) {
|
public void setAmountWaived(final BigDecimal amountWaived) {
|
||||||
this.amountWaived = amountWaived;
|
this.amountWaived = amountWaived;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,7 +234,7 @@ public class LoanInstallmentCharge extends AbstractPersistableCustom implements
|
|||||||
this.waived = false;
|
this.waived = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetOutstandingAmount(final BigDecimal amountOutstanding) {
|
public void setOutstandingAmount(final BigDecimal amountOutstanding) {
|
||||||
this.amountOutstanding = amountOutstanding;
|
this.amountOutstanding = amountOutstanding;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,7 +293,7 @@ public class LoanInstallmentCharge extends AbstractPersistableCustom implements
|
|||||||
|
|
||||||
Money amountPaidToDate = Money.of(incrementBy.getCurrency(), this.amountPaid);
|
Money amountPaidToDate = Money.of(incrementBy.getCurrency(), this.amountPaid);
|
||||||
|
|
||||||
Money amountToDeductOnThisCharge = Money.zero(incrementBy.getCurrency());
|
Money amountToDeductOnThisCharge;
|
||||||
if (incrementBy.isGreaterThanOrEqualTo(amountPaidToDate)) {
|
if (incrementBy.isGreaterThanOrEqualTo(amountPaidToDate)) {
|
||||||
amountToDeductOnThisCharge = amountPaidToDate;
|
amountToDeductOnThisCharge = amountPaidToDate;
|
||||||
amountPaidToDate = Money.zero(incrementBy.getCurrency());
|
amountPaidToDate = Money.zero(incrementBy.getCurrency());
|
||||||
|
|||||||
+8
-14
@@ -20,7 +20,6 @@ package org.apache.fineract.portfolio.loanaccount.domain;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.persistence.CascadeType;
|
import javax.persistence.CascadeType;
|
||||||
@@ -716,15 +715,6 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Comparator<LoanRepaymentScheduleInstallment> installmentNumberComparator = new Comparator<LoanRepaymentScheduleInstallment>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compare(LoanRepaymentScheduleInstallment arg0, LoanRepaymentScheduleInstallment arg1) {
|
|
||||||
|
|
||||||
return arg0.getInstallmentNumber().compareTo(arg1.getInstallmentNumber());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public BigDecimal getTotalPaidInAdvance() {
|
public BigDecimal getTotalPaidInAdvance() {
|
||||||
return this.totalPaidInAdvance;
|
return this.totalPaidInAdvance;
|
||||||
}
|
}
|
||||||
@@ -742,7 +732,7 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
|||||||
public Money unpayPenaltyChargesComponent(final LocalDate transactionDate, final Money transactionAmountRemaining) {
|
public Money unpayPenaltyChargesComponent(final LocalDate transactionDate, final Money transactionAmountRemaining) {
|
||||||
|
|
||||||
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||||
Money penaltyPortionOfTransactionDeducted = Money.zero(currency);
|
Money penaltyPortionOfTransactionDeducted;
|
||||||
|
|
||||||
final Money penaltyChargesCompleted = getPenaltyChargesPaid(currency);
|
final Money penaltyChargesCompleted = getPenaltyChargesPaid(currency);
|
||||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(penaltyChargesCompleted)) {
|
if (transactionAmountRemaining.isGreaterThanOrEqualTo(penaltyChargesCompleted)) {
|
||||||
@@ -761,7 +751,7 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
|||||||
public Money unpayFeeChargesComponent(final LocalDate transactionDate, final Money transactionAmountRemaining) {
|
public Money unpayFeeChargesComponent(final LocalDate transactionDate, final Money transactionAmountRemaining) {
|
||||||
|
|
||||||
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||||
Money feePortionOfTransactionDeducted = Money.zero(currency);
|
Money feePortionOfTransactionDeducted;
|
||||||
|
|
||||||
final Money feeChargesCompleted = getFeeChargesPaid(currency);
|
final Money feeChargesCompleted = getFeeChargesPaid(currency);
|
||||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(feeChargesCompleted)) {
|
if (transactionAmountRemaining.isGreaterThanOrEqualTo(feeChargesCompleted)) {
|
||||||
@@ -782,7 +772,7 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
|||||||
public Money unpayInterestComponent(final LocalDate transactionDate, final Money transactionAmountRemaining) {
|
public Money unpayInterestComponent(final LocalDate transactionDate, final Money transactionAmountRemaining) {
|
||||||
|
|
||||||
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||||
Money interestPortionOfTransactionDeducted = Money.zero(currency);
|
Money interestPortionOfTransactionDeducted;
|
||||||
|
|
||||||
final Money interestCompleted = getInterestPaid(currency);
|
final Money interestCompleted = getInterestPaid(currency);
|
||||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(interestCompleted)) {
|
if (transactionAmountRemaining.isGreaterThanOrEqualTo(interestCompleted)) {
|
||||||
@@ -803,7 +793,7 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
|||||||
public Money unpayPrincipalComponent(final LocalDate transactionDate, final Money transactionAmountRemaining) {
|
public Money unpayPrincipalComponent(final LocalDate transactionDate, final Money transactionAmountRemaining) {
|
||||||
|
|
||||||
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||||
Money principalPortionOfTransactionDeducted = Money.zero(currency);
|
Money principalPortionOfTransactionDeducted;
|
||||||
|
|
||||||
final Money principalCompleted = getPrincipalCompleted(currency);
|
final Money principalCompleted = getPrincipalCompleted(currency);
|
||||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(principalCompleted)) {
|
if (transactionAmountRemaining.isGreaterThanOrEqualTo(principalCompleted)) {
|
||||||
@@ -882,6 +872,10 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
|||||||
this.feeChargesWaived = newFeeChargesCharged;
|
this.feeChargesWaived = newFeeChargesCharged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPenaltyChargesWaived(final BigDecimal newPenaltyChargesCharged) {
|
||||||
|
this.penaltyChargesWaived = newPenaltyChargesCharged;
|
||||||
|
}
|
||||||
|
|
||||||
public Set<LoanInstallmentCharge> getInstallmentCharges() {
|
public Set<LoanInstallmentCharge> getInstallmentCharges() {
|
||||||
return installmentCharges;
|
return installmentCharges;
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-3
@@ -35,7 +35,7 @@ import org.apache.fineract.organisation.monetary.domain.Money;
|
|||||||
*/
|
*/
|
||||||
@Embeddable
|
@Embeddable
|
||||||
@Getter
|
@Getter
|
||||||
public final class LoanSummary {
|
public class LoanSummary {
|
||||||
|
|
||||||
// derived totals fields
|
// derived totals fields
|
||||||
@Column(name = "principal_disbursed_derived", scale = 6, precision = 19)
|
@Column(name = "principal_disbursed_derived", scale = 6, precision = 19)
|
||||||
@@ -126,7 +126,7 @@ public final class LoanSummary {
|
|||||||
return new LoanSummary(totalFeeChargesDueAtDisbursement);
|
return new LoanSummary(totalFeeChargesDueAtDisbursement);
|
||||||
}
|
}
|
||||||
|
|
||||||
LoanSummary() {
|
protected LoanSummary() {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,10 +150,18 @@ public final class LoanSummary {
|
|||||||
this.totalFeeChargesOutstanding = totalFeeChargesOutstanding;
|
this.totalFeeChargesOutstanding = totalFeeChargesOutstanding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updatePenaltyChargeOutstanding(final BigDecimal totalPenaltyChargesOutstanding) {
|
||||||
|
this.totalPenaltyChargesOutstanding = totalPenaltyChargesOutstanding;
|
||||||
|
}
|
||||||
|
|
||||||
public void updateFeeChargesWaived(final BigDecimal totalFeeChargesWaived) {
|
public void updateFeeChargesWaived(final BigDecimal totalFeeChargesWaived) {
|
||||||
this.totalFeeChargesWaived = totalFeeChargesWaived;
|
this.totalFeeChargesWaived = totalFeeChargesWaived;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updatePenaltyChargesWaived(final BigDecimal totalPenaltyChargesWaived) {
|
||||||
|
this.totalPenaltyChargesWaived = totalPenaltyChargesWaived;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isRepaidInFull(final MonetaryCurrency currency) {
|
public boolean isRepaidInFull(final MonetaryCurrency currency) {
|
||||||
return getTotalOutstanding(currency).isZero();
|
return getTotalOutstanding(currency).isZero();
|
||||||
}
|
}
|
||||||
@@ -182,6 +190,14 @@ public final class LoanSummary {
|
|||||||
return this.totalOutstanding;
|
return this.totalOutstanding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateTotalOutstanding(final BigDecimal newTotalOutstanding) {
|
||||||
|
this.totalOutstanding = newTotalOutstanding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateTotalWaived(final BigDecimal totalWaived) {
|
||||||
|
this.totalWaived = totalWaived;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All fields but <code>totalFeeChargesDueAtDisbursement</code> should be reset.
|
* All fields but <code>totalFeeChargesDueAtDisbursement</code> should be reset.
|
||||||
*/
|
*/
|
||||||
@@ -217,7 +233,7 @@ public final class LoanSummary {
|
|||||||
|
|
||||||
public void updateSummary(final MonetaryCurrency currency, final Money principal,
|
public void updateSummary(final MonetaryCurrency currency, final Money principal,
|
||||||
final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, final LoanSummaryWrapper summaryWrapper,
|
final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, final LoanSummaryWrapper summaryWrapper,
|
||||||
final Boolean disbursed, Set<LoanCharge> charges) {
|
Set<LoanCharge> charges) {
|
||||||
|
|
||||||
this.totalPrincipalDisbursed = principal.getAmount();
|
this.totalPrincipalDisbursed = principal.getAmount();
|
||||||
this.totalPrincipalAdjustments = summaryWrapper.calculateTotalPrincipalAdjusted(repaymentScheduleInstallments, currency)
|
this.totalPrincipalAdjustments = summaryWrapper.calculateTotalPrincipalAdjusted(repaymentScheduleInstallments, currency)
|
||||||
|
|||||||
+3
-1
@@ -18,9 +18,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.portfolio.loanaccount.domain;
|
package org.apache.fineract.portfolio.loanaccount.domain;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
|
||||||
public interface LoanTransactionRepository extends JpaRepository<LoanTransaction, Long>, JpaSpecificationExecutor<LoanTransaction> {
|
public interface LoanTransactionRepository extends JpaRepository<LoanTransaction, Long>, JpaSpecificationExecutor<LoanTransaction> {
|
||||||
// no added behaviour
|
|
||||||
|
Optional<LoanTransaction> findByIdAndLoanId(Long transactionId, Long loanId);
|
||||||
}
|
}
|
||||||
|
|||||||
+146
-141
@@ -234,6 +234,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatformService {
|
public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatformService {
|
||||||
|
|
||||||
|
public static final String AMOUNT = "amount";
|
||||||
private final PlatformSecurityContext context;
|
private final PlatformSecurityContext context;
|
||||||
private final LoanEventApiJsonValidator loanEventApiJsonValidator;
|
private final LoanEventApiJsonValidator loanEventApiJsonValidator;
|
||||||
private final LoanUpdateCommandFromApiJsonDeserializer loanUpdateCommandFromApiJsonDeserializer;
|
private final LoanUpdateCommandFromApiJsonDeserializer loanUpdateCommandFromApiJsonDeserializer;
|
||||||
@@ -278,6 +279,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
private final LoanDisbursementDetailsRepository loanDisbursementDetailsRepository;
|
private final LoanDisbursementDetailsRepository loanDisbursementDetailsRepository;
|
||||||
private final LoanRepaymentScheduleInstallmentRepository loanRepaymentScheduleInstallmentRepository;
|
private final LoanRepaymentScheduleInstallmentRepository loanRepaymentScheduleInstallmentRepository;
|
||||||
|
|
||||||
|
private static boolean isPartOfThisInstallment(LoanCharge loanCharge, LoanRepaymentScheduleInstallment e) {
|
||||||
|
return e.getFromDate().isBefore(loanCharge.getDueDate()) && !loanCharge.getDueDate().isAfter(e.getDueDate());
|
||||||
|
}
|
||||||
|
|
||||||
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
|
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
|
||||||
return new DefaultLoanLifecycleStateMachine(LoanStatus.values(), businessEventNotifierService);
|
return new DefaultLoanLifecycleStateMachine(LoanStatus.values(), businessEventNotifierService);
|
||||||
}
|
}
|
||||||
@@ -343,7 +348,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
final Set<LoanCollateralManagement> loanCollateralManagements = loan.getLoanCollateralManagements();
|
final Set<LoanCollateralManagement> loanCollateralManagements = loan.getLoanCollateralManagements();
|
||||||
|
|
||||||
// Get relevant loan collateral modules
|
// Get relevant loan collateral modules
|
||||||
if ((loanCollateralManagements != null && loanCollateralManagements.size() != 0)
|
if ((loanCollateralManagements != null && !loanCollateralManagements.isEmpty())
|
||||||
&& AccountType.fromInt(loan.getLoanType()).isIndividualAccount()) {
|
&& AccountType.fromInt(loan.getLoanType()).isIndividualAccount()) {
|
||||||
|
|
||||||
BigDecimal totalCollateral = BigDecimal.valueOf(0);
|
BigDecimal totalCollateral = BigDecimal.valueOf(0);
|
||||||
@@ -463,7 +468,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
loan.addLoanTransaction(disbursementTransaction);
|
loan.addLoanTransaction(disbursementTransaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loan.getRepaymentScheduleInstallments().size() == 0) {
|
if (loan.getRepaymentScheduleInstallments().isEmpty()) {
|
||||||
/*
|
/*
|
||||||
* If no schedule, generate one (applicable to non-tranche multi-disbursal loans)
|
* If no schedule, generate one (applicable to non-tranche multi-disbursal loans)
|
||||||
*/
|
*/
|
||||||
@@ -578,7 +583,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
*
|
*
|
||||||
* @param loan
|
* @param loan
|
||||||
* the disbursed loan
|
* the disbursed loan
|
||||||
*
|
|
||||||
**/
|
**/
|
||||||
private void createStandingInstruction(Loan loan) {
|
private void createStandingInstruction(Loan loan) {
|
||||||
|
|
||||||
@@ -877,15 +881,13 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||||
|
|
||||||
// Remove All the Disbursement Details If the Loan Product is disabled and exists one
|
// Remove All the Disbursement Details If the Loan Product is disabled and exists one
|
||||||
if (loan.loanProduct().isDisallowExpectedDisbursements()) {
|
if (loan.loanProduct().isDisallowExpectedDisbursements() && !loan.getDisbursementDetails().isEmpty()) {
|
||||||
if (!loan.getDisbursementDetails().isEmpty()) {
|
List<LoanDisbursementDetails> reversedDisbursementDetails = new ArrayList<>();
|
||||||
List<LoanDisbursementDetails> reversedDisbursementDetails = new ArrayList<LoanDisbursementDetails>();
|
for (LoanDisbursementDetails disbursementDetail : loan.getAllDisbursementDetails()) {
|
||||||
for (LoanDisbursementDetails disbursementDetail : loan.getAllDisbursementDetails()) {
|
disbursementDetail.reverse();
|
||||||
disbursementDetail.reverse();
|
reversedDisbursementDetails.add(disbursementDetail);
|
||||||
reversedDisbursementDetails.add(disbursementDetail);
|
|
||||||
}
|
|
||||||
this.loanDisbursementDetailsRepository.saveAllAndFlush(reversedDisbursementDetails);
|
|
||||||
}
|
}
|
||||||
|
this.loanDisbursementDetailsRepository.saveAllAndFlush(reversedDisbursementDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanUndoDisbursalBusinessEvent(loan));
|
businessEventNotifierService.notifyPostBusinessEvent(new LoanUndoDisbursalBusinessEvent(loan));
|
||||||
@@ -1924,10 +1926,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
final Integer installmentNumber = installmentChargeEntry.getRepaymentInstallment().getInstallmentNumber();
|
final Integer installmentNumber = installmentChargeEntry.getRepaymentInstallment().getInstallmentNumber();
|
||||||
chargeAmountPaid = installmentChargeEntry.getAmountPaid(loanCurrency).getAmount();
|
chargeAmountPaid = installmentChargeEntry.getAmountPaid(loanCurrency).getAmount();
|
||||||
for (LoanChargePaidBy loanChargePaidBy : loanCharge.getLoanChargePaidBySet()) {
|
for (LoanChargePaidBy loanChargePaidBy : loanCharge.getLoanChargePaidBySet()) {
|
||||||
if (installmentNumber.equals(loanChargePaidBy.getInstallmentNumber())) {
|
if (installmentNumber.equals(loanChargePaidBy.getInstallmentNumber()) && isRefundElementOfChargeRefund(loanChargePaidBy)) {
|
||||||
if (isRefundElementOfChargeRefund(loanChargePaidBy)) {
|
chargeAmountRefunded = chargeAmountRefunded.add(loanChargePaidBy.getAmount());
|
||||||
chargeAmountRefunded = chargeAmountRefunded.add(loanChargePaidBy.getAmount());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1947,12 +1947,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
}
|
}
|
||||||
|
|
||||||
BigDecimal refundableAmount = chargeAmountPaid.subtract(chargeAmountRefunded);
|
BigDecimal refundableAmount = chargeAmountPaid.subtract(chargeAmountRefunded);
|
||||||
if (transactionAmount != null) { // refund amount was provided.
|
// refund amount was provided.
|
||||||
if (transactionAmount.compareTo(refundableAmount) > 0) {
|
if (transactionAmount != null && transactionAmount.compareTo(refundableAmount) > 0) {
|
||||||
final String errorMessage = "loan.charge.transaction.amount.is.more.than.is.refundable";
|
final String errorMessage = "loan.charge.transaction.amount.is.more.than.is.refundable";
|
||||||
final String details = "transactionAmount: " + transactionAmount + " Refundable: " + refundableAmount;
|
final String details = "transactionAmount: " + transactionAmount + " Refundable: " + refundableAmount;
|
||||||
throw new LoanChargeRefundException(errorMessage, details);
|
throw new LoanChargeRefundException(errorMessage, details);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return refundableAmount;
|
return refundableAmount;
|
||||||
@@ -2022,145 +2021,155 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
@Override
|
@Override
|
||||||
public CommandProcessingResult undoWaiveLoanCharge(final JsonCommand command) {
|
public CommandProcessingResult undoWaiveLoanCharge(final JsonCommand command) {
|
||||||
|
|
||||||
LoanTransaction loanTransaction = this.loanTransactionRepository.findById(command.entityId())
|
LoanTransaction loanTransaction = this.loanTransactionRepository.findByIdAndLoanId(command.entityId(), command.getLoanId())
|
||||||
.orElseThrow(() -> new LoanTransactionNotFoundException(command.entityId()));
|
.orElseThrow(() -> new LoanTransactionNotFoundException(command.entityId(), command.getLoanId()));
|
||||||
|
|
||||||
if (!loanTransaction.getTypeOf().getCode().equals(LoanTransactionType.WAIVE_CHARGES.getCode())) {
|
if (!loanTransaction.getTypeOf().getCode().equals(LoanTransactionType.WAIVE_CHARGES.getCode())) {
|
||||||
throw new InvalidLoanTransactionTypeException("Undo Waive Charge", "Waive an Installment Charge First",
|
throw new InvalidLoanTransactionTypeException("transaction", "undo.waive.charge", "Transaction is not a waive charge type.");
|
||||||
"Transaction is not a waive charge type.");
|
}
|
||||||
|
if (!loanTransaction.isNotReversed()) {
|
||||||
|
throw new LoanChargeWaiveCannotBeReversedException(LoanChargeWaiveCannotUndoReason.ALREADY_REVERSED, loanTransaction.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<LoanChargePaidBy> loanChargePaidBySet = loanTransaction.getLoanChargesPaid();
|
Set<LoanChargePaidBy> loanChargePaidBySet = loanTransaction.getLoanChargesPaid();
|
||||||
Integer installmentNumber = null;
|
LoanChargePaidBy loanChargePaidBy = loanChargePaidBySet.stream().findFirst().orElseThrow(LoanChargeNotFoundException::new);
|
||||||
Long loanChargeId = null;
|
final LoanCharge loanCharge = loanChargePaidBy.getLoanCharge();
|
||||||
final Long loanId = loanTransaction.getLoan().getId();
|
// Validate loan charge is not already paid
|
||||||
|
if (loanCharge.isPaid()) {
|
||||||
for (LoanChargePaidBy loanChargePaidBy : loanChargePaidBySet) {
|
throw new LoanChargeWaiveCannotBeReversedException(LoanChargeWaiveCannotUndoReason.ALREADY_PAID, loanCharge.getId());
|
||||||
installmentNumber = loanChargePaidBy.getInstallmentNumber();
|
|
||||||
loanChargeId = loanChargePaidBy.getLoanCharge().getId();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final Long loanId = loanTransaction.getLoan().getId();
|
||||||
final Loan loan = this.loanAssembler.assembleFrom(loanId);
|
final Loan loan = this.loanAssembler.assembleFrom(loanId);
|
||||||
checkClientOrGroupActive(loan);
|
checkClientOrGroupActive(loan);
|
||||||
final LoanCharge loanCharge = retrieveLoanChargeBy(loanId, loanChargeId);
|
|
||||||
|
|
||||||
// Charges may be waived only when the loan associated with them are
|
// Charges may be waived only when the loan associated with them are
|
||||||
// active
|
// active
|
||||||
if (!loan.getStatus().isActive()) {
|
if (!loan.getStatus().isActive()) {
|
||||||
throw new LoanChargeWaiveCannotBeReversedException(LoanChargeWaiveCannotUndoReason.LOAN_INACTIVE, loanCharge.getId());
|
throw new LoanChargeWaiveCannotBeReversedException(LoanChargeWaiveCannotUndoReason.LOAN_INACTIVE, loanCharge.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate loan charge is not already paid
|
|
||||||
if (loanCharge.isPaid()) {
|
|
||||||
throw new LoanChargeWaiveCannotBeReversedException(LoanChargeWaiveCannotUndoReason.ALREADY_PAID, loanCharge.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
final Map<String, Object> changes = new LinkedHashMap<>(3);
|
final Map<String, Object> changes = new LinkedHashMap<>(3);
|
||||||
|
|
||||||
businessEventNotifierService.notifyPreBusinessEvent(new LoanWaiveChargeUndoBusinessEvent(loanCharge));
|
businessEventNotifierService.notifyPreBusinessEvent(new LoanWaiveChargeUndoBusinessEvent(loanCharge));
|
||||||
|
|
||||||
if (loanCharge.isInstalmentFee()) {
|
undoWaivedCharge(changes, loan, loanTransaction, loanChargePaidBy);
|
||||||
LoanInstallmentCharge chargePerInstallment;
|
|
||||||
|
|
||||||
// final Integer installmentNumber = command.integerValueOfParameterNamed("installmentNumber");
|
|
||||||
if (installmentNumber != null) {
|
|
||||||
|
|
||||||
// Get installment charge.
|
|
||||||
chargePerInstallment = loanCharge.getInstallmentLoanCharge(installmentNumber);
|
|
||||||
|
|
||||||
if (!loanTransaction.isNotReversed()) {
|
|
||||||
throw new LoanChargeWaiveCannotBeReversedException(LoanChargeWaiveCannotUndoReason.ALREADY_REVERSED,
|
|
||||||
loanTransaction.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reverse waived transaction
|
|
||||||
loanTransaction.setReversed();
|
|
||||||
|
|
||||||
// Get installment amount waived.
|
|
||||||
BigDecimal amountWaived = chargePerInstallment.getAmountWaived(loan.getCurrency()).getAmount();
|
|
||||||
|
|
||||||
// Set manually adjusted value to `1`
|
|
||||||
loanTransaction.setManuallyAdjustedOrReversed();
|
|
||||||
|
|
||||||
// Save updated data
|
|
||||||
this.loanTransactionRepository.saveAndFlush(loanTransaction);
|
|
||||||
|
|
||||||
// Get installment outstanding amount
|
|
||||||
BigDecimal amountOutstandingPerInstallment = chargePerInstallment.getAmountOutstanding();
|
|
||||||
|
|
||||||
// Check whether the installment charge is not waived. If so throw new error
|
|
||||||
if (!chargePerInstallment.isWaived() || amountWaived == null) {
|
|
||||||
throw new LoanChargeWaiveCannotBeReversedException(LoanChargeWaiveCannotUndoReason.NOT_WAIVED, loanChargeId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get loan charge total amount waived
|
|
||||||
BigDecimal totalAmountWaved = loanCharge.getAmountWaived(loan.getCurrency()).getAmount();
|
|
||||||
|
|
||||||
// Get loan charge outstanding amount
|
|
||||||
BigDecimal amountOutstanding = loanCharge.getAmountOutstanding(loan.getCurrency()).getAmount();
|
|
||||||
|
|
||||||
// Add the amount waived to outstanding amount
|
|
||||||
loanCharge.resetOutstandingAmount(amountOutstanding.add(amountWaived));
|
|
||||||
|
|
||||||
// Subtract the amount waived from the existing amount waived.
|
|
||||||
loanCharge.setAmountWaived(totalAmountWaved.subtract(amountWaived));
|
|
||||||
|
|
||||||
// Add the amount waived to the outstanding amount of the installment
|
|
||||||
chargePerInstallment.resetOutstandingAmount(amountOutstandingPerInstallment.add(amountWaived));
|
|
||||||
|
|
||||||
// Set the amount waived value to ZERO
|
|
||||||
chargePerInstallment.resetAmountWaived(BigDecimal.ZERO);
|
|
||||||
|
|
||||||
// Reset waived flag
|
|
||||||
chargePerInstallment.undoWaiveFlag();
|
|
||||||
|
|
||||||
// Get the fee charges waived amount per installment
|
|
||||||
BigDecimal feeChargesWaivedAmount = chargePerInstallment.getInstallment().getFeeChargesWaived(loan.getCurrency())
|
|
||||||
.getAmount();
|
|
||||||
|
|
||||||
// Subtract the amount waived from the existing fee charges waived amount.
|
|
||||||
chargePerInstallment.getInstallment().setFeeChargesWaived(feeChargesWaivedAmount.subtract(amountWaived));
|
|
||||||
|
|
||||||
// Update loan charge.
|
|
||||||
loanCharge.setInstallmentLoanCharge(chargePerInstallment, chargePerInstallment.getInstallment().getInstallmentNumber());
|
|
||||||
|
|
||||||
if (loanCharge.getAmount(loan.getCurrency()).compareTo(loanCharge.getAmountOutstanding(loan.getCurrency())) == 0
|
|
||||||
&& loanCharge.isWaived()) {
|
|
||||||
loanCharge.undoWaived();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.loanChargeRepository.saveAndFlush(loanCharge);
|
|
||||||
|
|
||||||
loan.updateLoanSummaryForUndoWaiveCharge(amountWaived);
|
|
||||||
|
|
||||||
changes.put("amount", amountWaived);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
throw new InstallmentNotFoundException(command.entityId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
saveLoanWithDataIntegrityViolationChecks(loan);
|
|
||||||
|
|
||||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanWaiveChargeUndoBusinessEvent(loanCharge));
|
businessEventNotifierService.notifyPostBusinessEvent(new LoanWaiveChargeUndoBusinessEvent(loanCharge));
|
||||||
|
|
||||||
LoanTransaction loanTransactionData = this.loanTransactionRepository.getReferenceById(command.entityId());
|
changes.put("principalPortion", loanTransaction.getPrincipalPortion());
|
||||||
changes.put("principalPortion", loanTransactionData.getPrincipalPortion());
|
changes.put("interestPortion", loanTransaction.getInterestPortion(loan.getCurrency()));
|
||||||
changes.put("interestPortion", loanTransactionData.getInterestPortion(loan.getCurrency()));
|
changes.put("feeChargesPortion", loanTransaction.getFeeChargesPortion(loan.getCurrency()));
|
||||||
changes.put("feeChargesPortion", loanTransactionData.getFeeChargesPortion(loan.getCurrency()));
|
changes.put("penaltyChargesPortion", loanTransaction.getPenaltyChargesPortion(loan.getCurrency()));
|
||||||
changes.put("penaltyChargesPortion", loanTransactionData.getPenaltyChargesPortion(loan.getCurrency()));
|
changes.put("outstandingLoanBalance", loanTransaction.getOutstandingLoanBalance());
|
||||||
changes.put("outstandingLoanBalance", loanTransactionData.getOutstandingLoanBalance());
|
changes.put("id", loanTransaction.getId());
|
||||||
changes.put("id", loanTransactionData.getId());
|
changes.put("date", loanTransaction.getTransactionDate());
|
||||||
changes.put("date", loanTransactionData.getTransactionDate());
|
|
||||||
|
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
.withCommandId(command.commandId()) //
|
.withCommandId(command.commandId()) //
|
||||||
.withEntityId(loanChargeId) //
|
.withEntityId(loanCharge.getId()) //
|
||||||
.withLoanId(loanId) //
|
.withLoanId(loanId) //
|
||||||
.with(changes).build();
|
.with(changes).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void undoWaivedCharge(final Map<String, Object> changes, final Loan loan, final LoanTransaction loanTransaction,
|
||||||
|
final LoanChargePaidBy loanChargePaidBy) {
|
||||||
|
switch (loanChargePaidBy.getLoanCharge().getChargeTimeType()) {
|
||||||
|
case SPECIFIED_DUE_DATE -> undoSpecifiedDueDateCharge(changes, loan, loanTransaction, loanChargePaidBy);
|
||||||
|
case INSTALMENT_FEE -> undoInstalmentFee(changes, loan, loanTransaction, loanChargePaidBy);
|
||||||
|
default -> throw new UnsupportedOperationException(
|
||||||
|
"Undo waive charge is not support for this charge: " + loanChargePaidBy.getLoanCharge().getChargeTimeType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void undoInstalmentFee(Map<String, Object> changes, Loan loan, LoanTransaction loanTransaction,
|
||||||
|
LoanChargePaidBy loanChargePaidBy) {
|
||||||
|
final List<Long> existingTransactionIds = loan.findExistingTransactionIds();
|
||||||
|
final List<Long> existingReversedTransactionIds = loan.findExistingReversedTransactionIds();
|
||||||
|
LoanCharge loanCharge = loanChargePaidBy.getLoanCharge();
|
||||||
|
final Integer installmentNumber = loanChargePaidBy.getInstallmentNumber();
|
||||||
|
LoanInstallmentCharge chargePerInstallment;
|
||||||
|
// final Integer installmentNumber = command.integerValueOfParameterNamed("installmentNumber");
|
||||||
|
if (installmentNumber != null) {
|
||||||
|
// Get installment charge.
|
||||||
|
chargePerInstallment = loanCharge.getInstallmentLoanCharge(installmentNumber);
|
||||||
|
// Get installment amount waived.
|
||||||
|
BigDecimal amountWaived = chargePerInstallment.getAmountWaived(loan.getCurrency()).getAmount();
|
||||||
|
// Check whether the installment charge is not waived. If so throw new error
|
||||||
|
if (!chargePerInstallment.isWaived() || amountWaived == null) {
|
||||||
|
throw new LoanChargeWaiveCannotBeReversedException(LoanChargeWaiveCannotUndoReason.NOT_WAIVED, loanCharge.getId());
|
||||||
|
}
|
||||||
|
// Reverse waived transaction
|
||||||
|
loanTransaction.reverse();
|
||||||
|
// Set manually adjusted value to `1`
|
||||||
|
loanTransaction.setManuallyAdjustedOrReversed();
|
||||||
|
// Get loan charge outstanding amount
|
||||||
|
BigDecimal amountOutstanding = loanCharge.getAmountOutstanding(loan.getCurrency()).getAmount();
|
||||||
|
// Add the amount waived to outstanding amount
|
||||||
|
loanCharge.setOutstandingAmount(amountOutstanding.add(amountWaived));
|
||||||
|
// Get loan charge total amount waived
|
||||||
|
BigDecimal totalAmountWaved = loanCharge.getAmountWaived(loan.getCurrency()).getAmount();
|
||||||
|
// Subtract the amount waived from the existing amount waived.
|
||||||
|
loanCharge.setAmountWaived(totalAmountWaved.subtract(amountWaived));
|
||||||
|
// Get installment outstanding amount
|
||||||
|
BigDecimal amountOutstandingPerInstallment = chargePerInstallment.getAmountOutstanding();
|
||||||
|
// Add the amount waived to the outstanding amount of the installment
|
||||||
|
chargePerInstallment.setOutstandingAmount(amountOutstandingPerInstallment.add(amountWaived));
|
||||||
|
// Set the amount waived value to ZERO
|
||||||
|
chargePerInstallment.setAmountWaived(null);
|
||||||
|
// Reset waived flag
|
||||||
|
chargePerInstallment.undoWaiveFlag();
|
||||||
|
// Update installment balances
|
||||||
|
updateRepaymentInstalmentWithWaivedAmount(loanCharge, chargePerInstallment.getInstallment(), amountWaived);
|
||||||
|
// Update loan charge.
|
||||||
|
loanCharge.setInstallmentLoanCharge(chargePerInstallment, chargePerInstallment.getInstallment().getInstallmentNumber());
|
||||||
|
if (loanCharge.amount().compareTo(loanCharge.amountOutstanding()) == 0 && loanCharge.isWaived()) {
|
||||||
|
loanCharge.undoWaived();
|
||||||
|
}
|
||||||
|
loan.updateLoanSummaryForUndoWaiveCharge(amountWaived, loanCharge.isPenaltyCharge());
|
||||||
|
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||||
|
changes.put(AMOUNT, amountWaived);
|
||||||
|
} else {
|
||||||
|
throw new InstallmentNotFoundException(loanTransaction.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void undoSpecifiedDueDateCharge(final Map<String, Object> changes, final Loan loan, final LoanTransaction loanTransaction,
|
||||||
|
final LoanChargePaidBy loanChargePaidBy) {
|
||||||
|
|
||||||
|
final List<Long> existingTransactionIds = loan.findExistingTransactionIds();
|
||||||
|
final List<Long> existingReversedTransactionIds = loan.findExistingReversedTransactionIds();
|
||||||
|
LoanCharge loanCharge = loanChargePaidBy.getLoanCharge();
|
||||||
|
BigDecimal amountWaived = loanCharge.getAmountWaived(loan.getCurrency()).getAmount();
|
||||||
|
if (!loanCharge.isWaived() || amountWaived == null) {
|
||||||
|
throw new LoanChargeWaiveCannotBeReversedException(LoanChargeWaiveCannotUndoReason.NOT_WAIVED, loanCharge.getId());
|
||||||
|
}
|
||||||
|
loanTransaction.reverse();
|
||||||
|
loanTransaction.setManuallyAdjustedOrReversed();
|
||||||
|
loanCharge.setOutstandingAmount(loanCharge.amountOutstanding().add(amountWaived));
|
||||||
|
loanCharge.setAmountWaived(null);
|
||||||
|
loanCharge.undoWaived();
|
||||||
|
LoanRepaymentScheduleInstallment installment = loan.getRepaymentScheduleInstallments().stream()
|
||||||
|
.filter(e -> isPartOfThisInstallment(loanCharge, e)).findFirst().orElseThrow();
|
||||||
|
updateRepaymentInstalmentWithWaivedAmount(loanCharge, installment, amountWaived);
|
||||||
|
loan.updateLoanSummaryForUndoWaiveCharge(amountWaived, loanCharge.isPenaltyCharge());
|
||||||
|
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||||
|
changes.put(AMOUNT, amountWaived);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateRepaymentInstalmentWithWaivedAmount(final LoanCharge loanCharge, final LoanRepaymentScheduleInstallment installment,
|
||||||
|
final BigDecimal amountWaived) {
|
||||||
|
if (loanCharge.isPenaltyCharge()) {
|
||||||
|
// Get the penalty charges waived amount per installment
|
||||||
|
BigDecimal penaltyChargesWaivedAmount = installment.getPenaltyChargesWaived(loanCharge.getLoan().getCurrency()).getAmount();
|
||||||
|
// Subtract the amount waived from the existing fee charges waived amount.
|
||||||
|
installment.setPenaltyChargesWaived(penaltyChargesWaivedAmount.subtract(amountWaived));
|
||||||
|
} else {
|
||||||
|
// Get the fee charges waived amount per installment
|
||||||
|
BigDecimal feeChargesWaivedAmount = installment.getFeeChargesWaived(loanCharge.getLoan().getCurrency()).getAmount();
|
||||||
|
// Subtract the amount waived from the existing fee charges waived amount.
|
||||||
|
installment.setFeeChargesWaived(feeChargesWaivedAmount.subtract(amountWaived));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@Override
|
@Override
|
||||||
public CommandProcessingResult waiveLoanCharge(final Long loanId, final Long loanChargeId, final JsonCommand command) {
|
public CommandProcessingResult waiveLoanCharge(final Long loanId, final Long loanChargeId, final JsonCommand command) {
|
||||||
@@ -2829,16 +2838,12 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
|
|
||||||
private void checkClientOrGroupActive(final Loan loan) {
|
private void checkClientOrGroupActive(final Loan loan) {
|
||||||
final Client client = loan.client();
|
final Client client = loan.client();
|
||||||
if (client != null) {
|
if (client != null && client.isNotActive()) {
|
||||||
if (client.isNotActive()) {
|
throw new ClientNotActiveException(client.getId());
|
||||||
throw new ClientNotActiveException(client.getId());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
final Group group = loan.group();
|
final Group group = loan.group();
|
||||||
if (group != null) {
|
if (group != null && group.isNotActive()) {
|
||||||
if (group.isNotActive()) {
|
throw new GroupNotActiveException(group.getId());
|
||||||
throw new GroupNotActiveException(group.getId());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2950,7 +2955,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
if (diff < 1) {
|
if (diff < 1) {
|
||||||
diff = 1L;
|
diff = 1L;
|
||||||
}
|
}
|
||||||
LocalDate startDate = dueDate.plusDays(penaltyWaitPeriodValue.intValue() + 1);
|
LocalDate startDate = dueDate.plusDays(penaltyWaitPeriodValue + 1L);
|
||||||
int frequencyNumber = 1;
|
int frequencyNumber = 1;
|
||||||
if (feeFrequency == null) {
|
if (feeFrequency == null) {
|
||||||
scheduleDates.put(frequencyNumber++, startDate.minusDays(diff));
|
scheduleDates.put(frequencyNumber++, startDate.minusDays(diff));
|
||||||
|
|||||||
+323
-3
@@ -35,6 +35,8 @@ import java.text.DateFormat;
|
|||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.DateTimeFormatterBuilder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
@@ -94,6 +96,8 @@ public class ClientLoanIntegrationTest {
|
|||||||
private SavingsAccountHelper savingsAccountHelper;
|
private SavingsAccountHelper savingsAccountHelper;
|
||||||
private AccountTransferHelper accountTransferHelper;
|
private AccountTransferHelper accountTransferHelper;
|
||||||
|
|
||||||
|
private DateTimeFormatter dateFormatter = new DateTimeFormatterBuilder().appendPattern("dd MMMM yyyy").toFormatter();
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
Utils.initializeRESTAssured();
|
Utils.initializeRESTAssured();
|
||||||
@@ -104,6 +108,9 @@ public class ClientLoanIntegrationTest {
|
|||||||
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
|
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
|
||||||
this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec);
|
this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec);
|
||||||
this.schedulerJobHelper = new SchedulerJobHelper(this.requestSpec);
|
this.schedulerJobHelper = new SchedulerJobHelper(this.requestSpec);
|
||||||
|
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
|
||||||
|
this.periodicAccrualAccountingHelper = new PeriodicAccrualAccountingHelper(this.requestSpec, this.responseSpec);
|
||||||
|
this.journalEntryHelper = new JournalEntryHelper(this.requestSpec, this.responseSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -815,7 +822,7 @@ public class ClientLoanIntegrationTest {
|
|||||||
map.put("id", transId.toString());
|
map.put("id", transId.toString());
|
||||||
map.put("loanId", loanID.toString());
|
map.put("loanId", loanID.toString());
|
||||||
final String putBody = gson.toJson(map);
|
final String putBody = gson.toJson(map);
|
||||||
chargeId = this.loanTransactionHelper.undoWaiveChargesForLoan(loanID, transId, putBody);
|
chargeId = this.loanTransactionHelper.undoWaiveChargesForLoanReturnResourceId(loanID, transId, putBody);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1551,7 +1558,6 @@ public class ClientLoanIntegrationTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void loanWithFlatCahargesAndCashBasedAccountingEnabled() {
|
public void loanWithFlatCahargesAndCashBasedAccountingEnabled() {
|
||||||
this.journalEntryHelper = new JournalEntryHelper(this.requestSpec, this.responseSpec);
|
|
||||||
|
|
||||||
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||||
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
|
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
|
||||||
@@ -1739,7 +1745,6 @@ public class ClientLoanIntegrationTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void loanWithCahargesOfTypeAmountPercentageAndCashBasedAccountingEnabled() {
|
public void loanWithCahargesOfTypeAmountPercentageAndCashBasedAccountingEnabled() {
|
||||||
this.journalEntryHelper = new JournalEntryHelper(this.requestSpec, this.responseSpec);
|
|
||||||
|
|
||||||
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||||
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
|
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
|
||||||
@@ -5976,6 +5981,321 @@ public class ClientLoanIntegrationTest {
|
|||||||
assertEquals(clientCollateralId, clientCollateralIdResult);
|
assertEquals(clientCollateralId, clientCollateralIdResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void undoWaivedChargeTransactionDoesNotExist() {
|
||||||
|
ResponseSpecification responseSpec = new ResponseSpecBuilder().expectStatusCode(404).build();
|
||||||
|
LoanTransactionHelper loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, responseSpec);
|
||||||
|
HashMap response = loanTransactionHelper.undoWaiveChargesForLoan(-1, -2, "");
|
||||||
|
assertEquals("error.msg.loan.id.invalid", ((Map) ((List) response.get("errors")).get(0)).get("userMessageGlobalisationCode"));
|
||||||
|
assertEquals("Transaction with identifier -2 does not exist for loan with identifier -1.",
|
||||||
|
((Map) ((List) response.get("errors")).get(0)).get("defaultUserMessage"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void undoWaivedChargeWaiveTransactionDoesNotExist() {
|
||||||
|
final Account assetAccount = this.accountHelper.createAssetAccount();
|
||||||
|
final Account incomeAccount = this.accountHelper.createIncomeAccount();
|
||||||
|
final Account expenseAccount = this.accountHelper.createExpenseAccount();
|
||||||
|
final Account overpaymentAccount = this.accountHelper.createLiabilityAccount();
|
||||||
|
|
||||||
|
final Integer loanProductID = createLoanProductWithPeriodicAccrualAccountingNoInterest(assetAccount, incomeAccount, expenseAccount,
|
||||||
|
overpaymentAccount);
|
||||||
|
|
||||||
|
final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec, "01 January 2011");
|
||||||
|
|
||||||
|
final Integer loanID = applyForLoanApplication(clientID, loanProductID);
|
||||||
|
|
||||||
|
HashMap<String, Object> loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
||||||
|
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||||
|
|
||||||
|
loanStatusHashMap = this.loanTransactionHelper.approveLoan("02 September 2022", loanID);
|
||||||
|
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
||||||
|
LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
|
||||||
|
|
||||||
|
loanStatusHashMap = this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount("03 September 2022", loanID, "1000");
|
||||||
|
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
||||||
|
String loanDetails = this.loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID);
|
||||||
|
final Integer loanTransactionId = (Integer) ((Map) ((List) JsonPath.from(loanDetails).get("transactions")).get(0)).get("id");
|
||||||
|
|
||||||
|
ResponseSpecification responseSpec = new ResponseSpecBuilder().expectStatusCode(403).build();
|
||||||
|
LoanTransactionHelper loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, responseSpec);
|
||||||
|
HashMap response = loanTransactionHelper.undoWaiveChargesForLoan(loanID, loanTransactionId, "");
|
||||||
|
assertEquals("error.msg.loan.transaction.undo.waive.charge",
|
||||||
|
((Map) ((List) response.get("errors")).get(0)).get("userMessageGlobalisationCode"));
|
||||||
|
assertEquals("Transaction is not a waive charge type.", ((Map) ((List) response.get("errors")).get(0)).get("defaultUserMessage"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void undoWaivedCharge() {
|
||||||
|
final Account assetAccount = this.accountHelper.createAssetAccount();
|
||||||
|
final Account incomeAccount = this.accountHelper.createIncomeAccount();
|
||||||
|
final Account expenseAccount = this.accountHelper.createExpenseAccount();
|
||||||
|
final Account overpaymentAccount = this.accountHelper.createLiabilityAccount();
|
||||||
|
|
||||||
|
Integer penalty = ChargesHelper.createCharges(requestSpec, responseSpec,
|
||||||
|
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "10", true));
|
||||||
|
final Integer loanProductID = createLoanProductWithPeriodicAccrualAccountingNoInterest(assetAccount, incomeAccount, expenseAccount,
|
||||||
|
overpaymentAccount);
|
||||||
|
|
||||||
|
final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec, "01 January 2011");
|
||||||
|
|
||||||
|
final Integer loanID = applyForLoanApplication(clientID, loanProductID);
|
||||||
|
|
||||||
|
HashMap<String, Object> loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
||||||
|
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||||
|
|
||||||
|
loanStatusHashMap = this.loanTransactionHelper.approveLoan("02 September 2022", loanID);
|
||||||
|
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
||||||
|
LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
|
||||||
|
|
||||||
|
loanStatusHashMap = this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount("03 September 2022", loanID, "1000");
|
||||||
|
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
||||||
|
|
||||||
|
ArrayList<HashMap> loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, responseSpec, loanID);
|
||||||
|
assertEquals(2, loanSchedule.size());
|
||||||
|
assertEquals(0, loanSchedule.get(1).get("feeChargesDue"));
|
||||||
|
assertEquals(0, loanSchedule.get(1).get("feeChargesOutstanding"));
|
||||||
|
assertEquals(0, loanSchedule.get(1).get("penaltyChargesDue"));
|
||||||
|
assertEquals(0, loanSchedule.get(1).get("penaltyChargesOutstanding"));
|
||||||
|
assertEquals(1000.0f, loanSchedule.get(1).get("totalDueForPeriod"));
|
||||||
|
assertEquals(1000.0f, loanSchedule.get(1).get("totalOutstandingForPeriod"));
|
||||||
|
LocalDate targetDate = LocalDate.of(2022, 9, 7);
|
||||||
|
final String penaltyCharge1AddedDate = dateFormatter.format(targetDate);
|
||||||
|
Integer penalty1LoanChargeId = this.loanTransactionHelper.addChargesForLoan(loanID,
|
||||||
|
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(penalty), penaltyCharge1AddedDate, "10"));
|
||||||
|
|
||||||
|
this.loanTransactionHelper.noAccrualTransactionForRepayment(loanID);
|
||||||
|
|
||||||
|
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, responseSpec, loanID);
|
||||||
|
assertEquals(2, loanSchedule.size());
|
||||||
|
assertEquals(0, loanSchedule.get(1).get("feeChargesDue"));
|
||||||
|
assertEquals(0, loanSchedule.get(1).get("feeChargesOutstanding"));
|
||||||
|
assertEquals(10.0f, loanSchedule.get(1).get("penaltyChargesDue"));
|
||||||
|
assertEquals(10.0f, loanSchedule.get(1).get("penaltyChargesOutstanding"));
|
||||||
|
assertEquals(1010.0f, loanSchedule.get(1).get("totalDueForPeriod"));
|
||||||
|
assertEquals(1010.0f, loanSchedule.get(1).get("totalOutstandingForPeriod"));
|
||||||
|
assertEquals(0, loanSchedule.get(1).get("totalWaivedForPeriod"));
|
||||||
|
|
||||||
|
HashMap loanSummary = this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "summary");
|
||||||
|
assertEquals(10.0f, loanSummary.get("penaltyChargesCharged"));
|
||||||
|
assertEquals(10.0f, loanSummary.get("penaltyChargesOutstanding"));
|
||||||
|
assertEquals(0.0f, loanSummary.get("penaltyChargesWaived"));
|
||||||
|
assertEquals(0.0f, loanSummary.get("feeChargesCharged"));
|
||||||
|
assertEquals(0.0f, loanSummary.get("feeChargesOutstanding"));
|
||||||
|
assertEquals(0.0f, loanSummary.get("feeChargesWaived"));
|
||||||
|
assertEquals(1010.0f, loanSummary.get("totalOutstanding"));
|
||||||
|
assertEquals(0.0f, loanSummary.get("totalWaived"));
|
||||||
|
|
||||||
|
this.loanTransactionHelper.waiveChargesForLoan(loanID, penalty1LoanChargeId, "");
|
||||||
|
|
||||||
|
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, responseSpec, loanID);
|
||||||
|
assertEquals(2, loanSchedule.size());
|
||||||
|
assertEquals(0, loanSchedule.get(1).get("feeChargesDue"));
|
||||||
|
assertEquals(0, loanSchedule.get(1).get("feeChargesOutstanding"));
|
||||||
|
assertEquals(0, loanSchedule.get(1).get("feeChargesWaived"));
|
||||||
|
assertEquals(10.0f, loanSchedule.get(1).get("penaltyChargesDue"));
|
||||||
|
assertEquals(10.0f, loanSchedule.get(1).get("penaltyChargesWaived"));
|
||||||
|
assertEquals(0.0f, loanSchedule.get(1).get("penaltyChargesOutstanding"));
|
||||||
|
assertEquals(1010.0f, loanSchedule.get(1).get("totalDueForPeriod"));
|
||||||
|
assertEquals(1000.0f, loanSchedule.get(1).get("totalOutstandingForPeriod"));
|
||||||
|
assertEquals(10.0f, loanSchedule.get(1).get("totalWaivedForPeriod"));
|
||||||
|
|
||||||
|
loanSummary = this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "summary");
|
||||||
|
assertEquals(10.0f, loanSummary.get("penaltyChargesCharged"));
|
||||||
|
assertEquals(0.0f, loanSummary.get("penaltyChargesOutstanding"));
|
||||||
|
assertEquals(10.0f, loanSummary.get("penaltyChargesWaived"));
|
||||||
|
assertEquals(0.0f, loanSummary.get("feeChargesCharged"));
|
||||||
|
assertEquals(0.0f, loanSummary.get("feeChargesOutstanding"));
|
||||||
|
assertEquals(0.0f, loanSummary.get("feeChargesWaived"));
|
||||||
|
assertEquals(1000.0f, loanSummary.get("totalOutstanding"));
|
||||||
|
assertEquals(10.0f, loanSummary.get("totalWaived"));
|
||||||
|
|
||||||
|
List<HashMap> transactions = this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "transactions");
|
||||||
|
assertEquals(10.0f, (float) transactions.get(1).get("amount"));
|
||||||
|
assertEquals(9, (int) ((HashMap) transactions.get(1).get("type")).get("id"));
|
||||||
|
Integer waiveTransactionId = (int) transactions.get(1).get("id");
|
||||||
|
|
||||||
|
this.loanTransactionHelper.undoWaiveChargesForLoan(loanID, waiveTransactionId, "");
|
||||||
|
|
||||||
|
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, responseSpec, loanID);
|
||||||
|
assertEquals(2, loanSchedule.size());
|
||||||
|
assertEquals(0, loanSchedule.get(1).get("feeChargesDue"));
|
||||||
|
assertEquals(0, loanSchedule.get(1).get("feeChargesOutstanding"));
|
||||||
|
assertEquals(0, loanSchedule.get(1).get("feeChargesWaived"));
|
||||||
|
assertEquals(10.0f, loanSchedule.get(1).get("penaltyChargesDue"));
|
||||||
|
assertEquals(0.0f, loanSchedule.get(1).get("penaltyChargesWaived"));
|
||||||
|
assertEquals(10.0f, loanSchedule.get(1).get("penaltyChargesOutstanding"));
|
||||||
|
assertEquals(1010.0f, loanSchedule.get(1).get("totalDueForPeriod"));
|
||||||
|
assertEquals(1010.0f, loanSchedule.get(1).get("totalOutstandingForPeriod"));
|
||||||
|
assertEquals(0.0f, loanSchedule.get(1).get("totalWaivedForPeriod"));
|
||||||
|
|
||||||
|
loanSummary = this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "summary");
|
||||||
|
assertEquals(10.0f, loanSummary.get("penaltyChargesCharged"));
|
||||||
|
assertEquals(10.0f, loanSummary.get("penaltyChargesOutstanding"));
|
||||||
|
assertEquals(0.0f, loanSummary.get("penaltyChargesWaived"));
|
||||||
|
assertEquals(0.0f, loanSummary.get("feeChargesCharged"));
|
||||||
|
assertEquals(0.0f, loanSummary.get("feeChargesOutstanding"));
|
||||||
|
assertEquals(0.0f, loanSummary.get("feeChargesWaived"));
|
||||||
|
assertEquals(1010.0f, loanSummary.get("totalOutstanding"));
|
||||||
|
assertEquals(0.0f, loanSummary.get("totalWaived"));
|
||||||
|
|
||||||
|
transactions = this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "transactions");
|
||||||
|
assertEquals(10.0f, (float) transactions.get(1).get("amount"));
|
||||||
|
assertEquals(9, (int) ((HashMap) transactions.get(1).get("type")).get("id"));
|
||||||
|
assertEquals(true, transactions.get(1).get("manuallyReversed"));
|
||||||
|
|
||||||
|
Integer fee = ChargesHelper.createCharges(requestSpec, responseSpec,
|
||||||
|
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "10", false));
|
||||||
|
|
||||||
|
final String feeCharge1AddedDate = dateFormatter.format(targetDate);
|
||||||
|
Integer fee1LoanChargeId = this.loanTransactionHelper.addChargesForLoan(loanID,
|
||||||
|
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(fee), feeCharge1AddedDate, "10"));
|
||||||
|
|
||||||
|
this.periodicAccrualAccountingHelper.runPeriodicAccrualAccounting(feeCharge1AddedDate);
|
||||||
|
|
||||||
|
transactions = this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "transactions");
|
||||||
|
assertEquals(20.0f, (float) transactions.get(2).get("amount"));
|
||||||
|
assertEquals(10, (int) ((HashMap) transactions.get(2).get("type")).get("id"));
|
||||||
|
Integer accrualTransactionId = (int) transactions.get(2).get("id");
|
||||||
|
|
||||||
|
List<HashMap> journalEntries = this.journalEntryHelper.getJournalEntriesByTransactionId("L" + accrualTransactionId);
|
||||||
|
assertEquals(10.0f, (float) journalEntries.get(0).get("amount"));
|
||||||
|
assertEquals(incomeAccount.getAccountID(), (int) journalEntries.get(0).get("glAccountId"));
|
||||||
|
assertEquals("CREDIT", ((HashMap) journalEntries.get(0).get("entryType")).get("value"));
|
||||||
|
assertEquals(10.0f, (float) journalEntries.get(1).get("amount"));
|
||||||
|
assertEquals(assetAccount.getAccountID(), (int) journalEntries.get(1).get("glAccountId"));
|
||||||
|
assertEquals("DEBIT", ((HashMap) journalEntries.get(1).get("entryType")).get("value"));
|
||||||
|
assertEquals(10.0f, (float) journalEntries.get(2).get("amount"));
|
||||||
|
assertEquals(incomeAccount.getAccountID(), (int) journalEntries.get(2).get("glAccountId"));
|
||||||
|
assertEquals("CREDIT", ((HashMap) journalEntries.get(2).get("entryType")).get("value"));
|
||||||
|
assertEquals(10.0f, (float) journalEntries.get(3).get("amount"));
|
||||||
|
assertEquals(assetAccount.getAccountID(), (int) journalEntries.get(3).get("glAccountId"));
|
||||||
|
assertEquals("DEBIT", ((HashMap) journalEntries.get(3).get("entryType")).get("value"));
|
||||||
|
|
||||||
|
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, responseSpec, loanID);
|
||||||
|
assertEquals(2, loanSchedule.size());
|
||||||
|
assertEquals(10.0f, loanSchedule.get(1).get("feeChargesDue"));
|
||||||
|
assertEquals(10.0f, loanSchedule.get(1).get("feeChargesOutstanding"));
|
||||||
|
assertEquals(0, loanSchedule.get(1).get("feeChargesWaived"));
|
||||||
|
assertEquals(10.0f, loanSchedule.get(1).get("penaltyChargesDue"));
|
||||||
|
assertEquals(0, loanSchedule.get(1).get("penaltyChargesWaived"));
|
||||||
|
assertEquals(10.0f, loanSchedule.get(1).get("penaltyChargesOutstanding"));
|
||||||
|
assertEquals(1020.0f, loanSchedule.get(1).get("totalDueForPeriod"));
|
||||||
|
assertEquals(1020.0f, loanSchedule.get(1).get("totalOutstandingForPeriod"));
|
||||||
|
assertEquals(0, loanSchedule.get(1).get("totalWaivedForPeriod"));
|
||||||
|
|
||||||
|
loanSummary = this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "summary");
|
||||||
|
assertEquals(10.0f, loanSummary.get("penaltyChargesCharged"));
|
||||||
|
assertEquals(10.0f, loanSummary.get("penaltyChargesOutstanding"));
|
||||||
|
assertEquals(0.0f, loanSummary.get("penaltyChargesWaived"));
|
||||||
|
assertEquals(10.0f, loanSummary.get("feeChargesCharged"));
|
||||||
|
assertEquals(10.0f, loanSummary.get("feeChargesOutstanding"));
|
||||||
|
assertEquals(0.0f, loanSummary.get("feeChargesWaived"));
|
||||||
|
assertEquals(1020.0f, loanSummary.get("totalOutstanding"));
|
||||||
|
assertEquals(0.0f, loanSummary.get("totalWaived"));
|
||||||
|
|
||||||
|
this.loanTransactionHelper.waiveChargesForLoan(loanID, fee1LoanChargeId, "");
|
||||||
|
|
||||||
|
transactions = this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "transactions");
|
||||||
|
assertEquals(10.0f, (float) transactions.get(3).get("amount"));
|
||||||
|
assertEquals(9, (int) ((HashMap) transactions.get(3).get("type")).get("id"));
|
||||||
|
Integer waive2TransactionId = (int) transactions.get(3).get("id");
|
||||||
|
|
||||||
|
journalEntries = this.journalEntryHelper.getJournalEntriesByTransactionId("L" + waive2TransactionId);
|
||||||
|
assertEquals(10.0f, (float) journalEntries.get(0).get("amount"));
|
||||||
|
assertEquals(expenseAccount.getAccountID(), (int) journalEntries.get(0).get("glAccountId"));
|
||||||
|
assertEquals("DEBIT", ((HashMap) journalEntries.get(0).get("entryType")).get("value"));
|
||||||
|
assertEquals(10.0f, (float) journalEntries.get(1).get("amount"));
|
||||||
|
assertEquals(assetAccount.getAccountID(), (int) journalEntries.get(1).get("glAccountId"));
|
||||||
|
assertEquals("CREDIT", ((HashMap) journalEntries.get(1).get("entryType")).get("value"));
|
||||||
|
|
||||||
|
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, responseSpec, loanID);
|
||||||
|
assertEquals(2, loanSchedule.size());
|
||||||
|
assertEquals(10.0f, loanSchedule.get(1).get("feeChargesDue"));
|
||||||
|
assertEquals(0.0f, loanSchedule.get(1).get("feeChargesOutstanding"));
|
||||||
|
assertEquals(10.0f, loanSchedule.get(1).get("feeChargesWaived"));
|
||||||
|
assertEquals(10.0f, loanSchedule.get(1).get("penaltyChargesDue"));
|
||||||
|
assertEquals(0, loanSchedule.get(1).get("penaltyChargesWaived"));
|
||||||
|
assertEquals(10.0f, loanSchedule.get(1).get("penaltyChargesOutstanding"));
|
||||||
|
assertEquals(1020.0f, loanSchedule.get(1).get("totalDueForPeriod"));
|
||||||
|
assertEquals(1010.0f, loanSchedule.get(1).get("totalOutstandingForPeriod"));
|
||||||
|
assertEquals(10.0f, loanSchedule.get(1).get("totalWaivedForPeriod"));
|
||||||
|
|
||||||
|
loanSummary = this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "summary");
|
||||||
|
assertEquals(10.0f, loanSummary.get("penaltyChargesCharged"));
|
||||||
|
assertEquals(10.0f, loanSummary.get("penaltyChargesOutstanding"));
|
||||||
|
assertEquals(0.0f, loanSummary.get("penaltyChargesWaived"));
|
||||||
|
assertEquals(10.0f, loanSummary.get("feeChargesCharged"));
|
||||||
|
assertEquals(0.0f, loanSummary.get("feeChargesOutstanding"));
|
||||||
|
assertEquals(10.0f, loanSummary.get("feeChargesWaived"));
|
||||||
|
assertEquals(1010.0f, loanSummary.get("totalOutstanding"));
|
||||||
|
assertEquals(10.0f, loanSummary.get("totalWaived"));
|
||||||
|
|
||||||
|
this.loanTransactionHelper.undoWaiveChargesForLoan(loanID, waive2TransactionId, "");
|
||||||
|
|
||||||
|
transactions = this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "transactions");
|
||||||
|
assertEquals(10.0f, (float) transactions.get(3).get("amount"));
|
||||||
|
assertEquals(9, (int) ((HashMap) transactions.get(3).get("type")).get("id"));
|
||||||
|
assertEquals(true, transactions.get(3).get("manuallyReversed"));
|
||||||
|
|
||||||
|
journalEntries = this.journalEntryHelper.getJournalEntriesByTransactionId("L" + waive2TransactionId);
|
||||||
|
assertEquals(10.0f, (float) journalEntries.get(0).get("amount"));
|
||||||
|
assertEquals(expenseAccount.getAccountID(), (int) journalEntries.get(0).get("glAccountId"));
|
||||||
|
assertEquals("CREDIT", ((HashMap) journalEntries.get(0).get("entryType")).get("value"));
|
||||||
|
assertEquals(10.0f, (float) journalEntries.get(1).get("amount"));
|
||||||
|
assertEquals(assetAccount.getAccountID(), (int) journalEntries.get(1).get("glAccountId"));
|
||||||
|
assertEquals("DEBIT", ((HashMap) journalEntries.get(1).get("entryType")).get("value"));
|
||||||
|
assertEquals(10.0f, (float) journalEntries.get(2).get("amount"));
|
||||||
|
assertEquals(expenseAccount.getAccountID(), (int) journalEntries.get(2).get("glAccountId"));
|
||||||
|
assertEquals("DEBIT", ((HashMap) journalEntries.get(2).get("entryType")).get("value"));
|
||||||
|
assertEquals(10.0f, (float) journalEntries.get(3).get("amount"));
|
||||||
|
assertEquals(assetAccount.getAccountID(), (int) journalEntries.get(3).get("glAccountId"));
|
||||||
|
assertEquals("CREDIT", ((HashMap) journalEntries.get(3).get("entryType")).get("value"));
|
||||||
|
|
||||||
|
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, responseSpec, loanID);
|
||||||
|
assertEquals(2, loanSchedule.size());
|
||||||
|
assertEquals(10.0f, loanSchedule.get(1).get("feeChargesDue"));
|
||||||
|
assertEquals(10.0f, loanSchedule.get(1).get("feeChargesOutstanding"));
|
||||||
|
assertEquals(0.0f, loanSchedule.get(1).get("feeChargesWaived"));
|
||||||
|
assertEquals(10.0f, loanSchedule.get(1).get("penaltyChargesDue"));
|
||||||
|
assertEquals(0, loanSchedule.get(1).get("penaltyChargesWaived"));
|
||||||
|
assertEquals(10.0f, loanSchedule.get(1).get("penaltyChargesOutstanding"));
|
||||||
|
assertEquals(1020.0f, loanSchedule.get(1).get("totalDueForPeriod"));
|
||||||
|
assertEquals(1020.0f, loanSchedule.get(1).get("totalOutstandingForPeriod"));
|
||||||
|
assertEquals(0.0f, loanSchedule.get(1).get("totalWaivedForPeriod"));
|
||||||
|
|
||||||
|
loanSummary = this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "summary");
|
||||||
|
assertEquals(10.0f, loanSummary.get("penaltyChargesCharged"));
|
||||||
|
assertEquals(10.0f, loanSummary.get("penaltyChargesOutstanding"));
|
||||||
|
assertEquals(0.0f, loanSummary.get("penaltyChargesWaived"));
|
||||||
|
assertEquals(10.0f, loanSummary.get("feeChargesCharged"));
|
||||||
|
assertEquals(10.0f, loanSummary.get("feeChargesOutstanding"));
|
||||||
|
assertEquals(0.0f, loanSummary.get("feeChargesWaived"));
|
||||||
|
assertEquals(1020.0f, loanSummary.get("totalOutstanding"));
|
||||||
|
assertEquals(0.0f, loanSummary.get("totalWaived"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer applyForLoanApplication(final Integer clientID, final Integer loanProductID) {
|
||||||
|
LOG.info("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
|
||||||
|
final String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("1")
|
||||||
|
.withLoanTermFrequencyAsMonths().withNumberOfRepayments("1").withRepaymentEveryAfter("1")
|
||||||
|
.withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("0").withInterestTypeAsFlatBalance()
|
||||||
|
.withAmortizationTypeAsEqualPrincipalPayments().withInterestCalculationPeriodTypeSameAsRepaymentPeriod()
|
||||||
|
.withExpectedDisbursementDate("03 September 2022").withSubmittedOnDate("01 September 2022").withLoanType("individual")
|
||||||
|
.build(clientID.toString(), loanProductID.toString(), null);
|
||||||
|
return this.loanTransactionHelper.getLoanId(loanApplicationJSON);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer createLoanProductWithPeriodicAccrualAccountingNoInterest(final Account... accounts) {
|
||||||
|
LOG.info("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
|
||||||
|
final String loanProductJSON = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth()
|
||||||
|
.withRepaymentAfterEvery("1").withNumberOfRepayments("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0")
|
||||||
|
.withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsFlat()
|
||||||
|
.withAccountingRulePeriodicAccrual(accounts).withDaysInMonth("30").withDaysInYear("365").withMoratorium("0", "0")
|
||||||
|
.build(null);
|
||||||
|
return this.loanTransactionHelper.getLoanProductId(loanProductJSON);
|
||||||
|
}
|
||||||
|
|
||||||
private void validateIfValuesAreNotOverridden(Integer loanID, Integer loanProductID) {
|
private void validateIfValuesAreNotOverridden(Integer loanID, Integer loanProductID) {
|
||||||
String loanProductDetails = this.loanTransactionHelper.getLoanProductDetails(this.requestSpec, this.responseSpec, loanProductID);
|
String loanProductDetails = this.loanTransactionHelper.getLoanProductDetails(this.requestSpec, this.responseSpec, loanProductID);
|
||||||
String loanDetails = this.loanTransactionHelper.getLoanDetails(this.requestSpec, this.responseSpec, loanID);
|
String loanDetails = this.loanTransactionHelper.getLoanDetails(this.requestSpec, this.responseSpec, loanID);
|
||||||
|
|||||||
+8
-1
@@ -529,7 +529,14 @@ public class LoanTransactionHelper {
|
|||||||
return (Integer) response.get("resourceId");
|
return (Integer) response.get("resourceId");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer undoWaiveChargesForLoan(final Integer loanId, final Integer transactionId, final String body) {
|
public HashMap undoWaiveChargesForLoan(final Integer loanId, final Integer transactionId, final String body) {
|
||||||
|
log.info("--------------------------------- UNDO WAIVE CHARGES FOR LOAN --------------------------------");
|
||||||
|
final String TRANSAC_URL = "/fineract-provider/api/v1/loans/" + loanId + "/transactions/" + transactionId + "?"
|
||||||
|
+ Utils.TENANT_IDENTIFIER;
|
||||||
|
return Utils.performServerPut(requestSpec, responseSpec, TRANSAC_URL, body, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer undoWaiveChargesForLoanReturnResourceId(final Integer loanId, final Integer transactionId, final String body) {
|
||||||
log.info("--------------------------------- UNDO WAIVE CHARGES FOR LOAN --------------------------------");
|
log.info("--------------------------------- UNDO WAIVE CHARGES FOR LOAN --------------------------------");
|
||||||
final String TRANSAC_URL = "/fineract-provider/api/v1/loans/" + loanId + "/transactions/" + transactionId + "?"
|
final String TRANSAC_URL = "/fineract-provider/api/v1/loans/" + loanId + "/transactions/" + transactionId + "?"
|
||||||
+ Utils.TENANT_IDENTIFIER;
|
+ Utils.TENANT_IDENTIFIER;
|
||||||
|
|||||||
Reference in New Issue
Block a user