Merge pull request #1541 from rajuan/FloatingRates
Floating Rates Feature
This commit is contained in:
+16
@@ -2529,4 +2529,20 @@ public class CommandWrapperBuilder {
|
|||||||
this.href = "/provisioningentries/"+entryId;
|
this.href = "/provisioningentries/"+entryId;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CommandWrapperBuilder createFloatingRate() {
|
||||||
|
this.actionName = "CREATE";
|
||||||
|
this.entityName = "FLOATINGRATE";
|
||||||
|
this.entityId = null;
|
||||||
|
this.href = "/floatingrates";
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandWrapperBuilder updateFloatingRate(final Long floatingRateId) {
|
||||||
|
this.actionName = "UPDATE";
|
||||||
|
this.entityName = "FLOATINGRATE";
|
||||||
|
this.entityId = floatingRateId;
|
||||||
|
this.href = "/floatingrates/"+floatingRateId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+129
@@ -0,0 +1,129 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.floatingrates.api;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
|
import javax.ws.rs.PUT;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.core.Context;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.UriInfo;
|
||||||
|
|
||||||
|
import org.mifosplatform.commands.domain.CommandWrapper;
|
||||||
|
import org.mifosplatform.commands.service.CommandWrapperBuilder;
|
||||||
|
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||||
|
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
|
||||||
|
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
|
||||||
|
import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||||
|
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRateData;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Scope;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Path("/floatingrates")
|
||||||
|
@Component
|
||||||
|
@Scope("singleton")
|
||||||
|
public class FloatingRatesApiResource {
|
||||||
|
|
||||||
|
private static final String RESOURCE_NAME = "FLOATINGRATE";
|
||||||
|
private static final Set<String> LIST_FLOATING_RATES_PARAMETERS = new HashSet<>(
|
||||||
|
Arrays.asList("id", "name", "isBaseLendingRate", "isActive",
|
||||||
|
"createdby", "createdOn", "modifiedBy", "modifiedOn"));
|
||||||
|
private static final Set<String> INDIVIDUAL_FLOATING_RATES_PARAMETERS = new HashSet<>(
|
||||||
|
Arrays.asList("id", "name", "isBaseLendingRate", "isActive",
|
||||||
|
"createdBy", "createdOn", "modifiedBy", "modifiedOn",
|
||||||
|
"ratePeriods"));
|
||||||
|
private final PlatformSecurityContext context;
|
||||||
|
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
|
||||||
|
private final DefaultToApiJsonSerializer<FloatingRateData> toApiJsonSerializer;
|
||||||
|
private final FloatingRatesReadPlatformService floatingRatesReadPlatformService;
|
||||||
|
private final ApiRequestParameterHelper apiRequestParameterHelper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public FloatingRatesApiResource(
|
||||||
|
final PlatformSecurityContext context,
|
||||||
|
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
|
||||||
|
final DefaultToApiJsonSerializer<FloatingRateData> toApiJsonSerializer,
|
||||||
|
final ApiRequestParameterHelper apiRequestParameterHelper,
|
||||||
|
final FloatingRatesReadPlatformService floatingRatesReadPlatformService) {
|
||||||
|
this.context = context;
|
||||||
|
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
|
||||||
|
this.toApiJsonSerializer = toApiJsonSerializer;
|
||||||
|
this.apiRequestParameterHelper = apiRequestParameterHelper;
|
||||||
|
this.floatingRatesReadPlatformService = floatingRatesReadPlatformService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
|
public String createFloatingRate(final String apiRequestBodyAsJson) {
|
||||||
|
|
||||||
|
final CommandWrapper commandRequest = new CommandWrapperBuilder()
|
||||||
|
.createFloatingRate().withJson(apiRequestBodyAsJson).build();
|
||||||
|
final CommandProcessingResult result = this.commandsSourceWritePlatformService
|
||||||
|
.logCommandSource(commandRequest);
|
||||||
|
return this.toApiJsonSerializer.serialize(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
|
public String retrieveAll(@Context final UriInfo uriInfo) {
|
||||||
|
this.context.authenticatedUser().validateHasReadPermission(
|
||||||
|
RESOURCE_NAME);
|
||||||
|
final List<FloatingRateData> floatingRates = this.floatingRatesReadPlatformService
|
||||||
|
.retrieveAll();
|
||||||
|
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper
|
||||||
|
.process(uriInfo.getQueryParameters());
|
||||||
|
return this.toApiJsonSerializer.serialize(settings, floatingRates,
|
||||||
|
FloatingRatesApiResource.LIST_FLOATING_RATES_PARAMETERS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("{floatingRateId}")
|
||||||
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
|
public String retrieveOne(
|
||||||
|
@PathParam("floatingRateId") final Long floatingRateId,
|
||||||
|
@Context final UriInfo uriInfo) {
|
||||||
|
this.context.authenticatedUser().validateHasReadPermission(
|
||||||
|
RESOURCE_NAME);
|
||||||
|
final FloatingRateData floatingRates = this.floatingRatesReadPlatformService
|
||||||
|
.retrieveOne(floatingRateId);
|
||||||
|
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper
|
||||||
|
.process(uriInfo.getQueryParameters());
|
||||||
|
return this.toApiJsonSerializer.serialize(settings, floatingRates,
|
||||||
|
FloatingRatesApiResource.INDIVIDUAL_FLOATING_RATES_PARAMETERS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Path("{floatingRateId}")
|
||||||
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
|
public String updateFloatingRate(
|
||||||
|
@PathParam("floatingRateId") final Long floatingRateId,
|
||||||
|
final String apiRequestBodyAsJson) {
|
||||||
|
final CommandWrapper commandRequest = new CommandWrapperBuilder()
|
||||||
|
.updateFloatingRate(floatingRateId)
|
||||||
|
.withJson(apiRequestBodyAsJson).build();
|
||||||
|
final CommandProcessingResult result = this.commandsSourceWritePlatformService
|
||||||
|
.logCommandSource(commandRequest);
|
||||||
|
return this.toApiJsonSerializer.serialize(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+60
@@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.floatingrates.data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.joda.time.LocalDate;
|
||||||
|
|
||||||
|
public class FloatingRateDTO {
|
||||||
|
|
||||||
|
private final boolean isFloatingInterestRate;
|
||||||
|
private final LocalDate startDate;
|
||||||
|
private BigDecimal interestRateDiff;
|
||||||
|
private final Collection<FloatingRatePeriodData> baseLendingRatePeriods;
|
||||||
|
|
||||||
|
public FloatingRateDTO(final boolean isFloatingInterestRate,
|
||||||
|
final LocalDate startDate, final BigDecimal interestRateDiff,
|
||||||
|
final Collection<FloatingRatePeriodData> baseLendingRatePeriods) {
|
||||||
|
this.isFloatingInterestRate = isFloatingInterestRate;
|
||||||
|
this.startDate = startDate;
|
||||||
|
this.interestRateDiff = interestRateDiff;
|
||||||
|
this.baseLendingRatePeriods = baseLendingRatePeriods;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal fetchBaseRate(LocalDate date) {
|
||||||
|
BigDecimal rate = null;
|
||||||
|
for (FloatingRatePeriodData periodData : this.baseLendingRatePeriods) {
|
||||||
|
if (date.isBefore(new LocalDate(periodData.getFromDate()))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rate = periodData.getInterestRate();
|
||||||
|
}
|
||||||
|
return rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addInterestRateDiff(final BigDecimal diff) {
|
||||||
|
this.interestRateDiff = this.interestRateDiff.add(diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFloatingInterestRate() {
|
||||||
|
return this.isFloatingInterestRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getStartDate() {
|
||||||
|
return this.startDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getInterestRateDiff() {
|
||||||
|
return this.interestRateDiff;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<FloatingRatePeriodData> getBaseLendingRatePeriods() {
|
||||||
|
return this.baseLendingRatePeriods;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+132
@@ -0,0 +1,132 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.floatingrates.data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.builder.CompareToBuilder;
|
||||||
|
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||||
|
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||||
|
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||||
|
|
||||||
|
public class FloatingRateData implements Comparable<FloatingRateData> {
|
||||||
|
|
||||||
|
private final Long id;
|
||||||
|
private final String name;
|
||||||
|
private final boolean isBaseLendingRate;
|
||||||
|
private final boolean isActive;
|
||||||
|
private final String createdBy;
|
||||||
|
private final Date createdOn;
|
||||||
|
private final String modifiedBy;
|
||||||
|
private final Date modifiedOn;
|
||||||
|
private final List<FloatingRatePeriodData> ratePeriods;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final List<EnumOptionData> interestRateFrequencyTypeOptions;
|
||||||
|
|
||||||
|
public FloatingRateData(Long id, String name, boolean isBaseLendingRate,
|
||||||
|
boolean isActive, String createdBy, Date createdOn,
|
||||||
|
String modifiedBy, Date modifiedOn,
|
||||||
|
List<FloatingRatePeriodData> ratePeriods,
|
||||||
|
List<EnumOptionData> interestRateFrequencyTypeOptions) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.isBaseLendingRate = isBaseLendingRate;
|
||||||
|
this.isActive = isActive;
|
||||||
|
this.createdBy = createdBy;
|
||||||
|
this.createdOn = createdOn;
|
||||||
|
this.modifiedBy = modifiedBy;
|
||||||
|
this.modifiedOn = modifiedOn;
|
||||||
|
this.ratePeriods = ratePeriods;
|
||||||
|
this.interestRateFrequencyTypeOptions = interestRateFrequencyTypeOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBaseLendingRate() {
|
||||||
|
return this.isBaseLendingRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isActive() {
|
||||||
|
return this.isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCreatedBy() {
|
||||||
|
return this.createdBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreatedOn() {
|
||||||
|
return this.createdOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModifiedBy() {
|
||||||
|
return this.modifiedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getModifiedOn() {
|
||||||
|
return this.modifiedOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<FloatingRatePeriodData> getRatePeriods() {
|
||||||
|
return this.ratePeriods;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(final FloatingRateData obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return new CompareToBuilder() //
|
||||||
|
.append(this.id, obj.id) //
|
||||||
|
.append(this.name, obj.name) //
|
||||||
|
.append(this.isBaseLendingRate, obj.isBaseLendingRate) //
|
||||||
|
.append(this.isActive, obj.isActive) //
|
||||||
|
.toComparison();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (obj == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj.getClass() != getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final FloatingRateData rhs = (FloatingRateData) obj;
|
||||||
|
return new EqualsBuilder() //
|
||||||
|
.append(this.id, rhs.id) //
|
||||||
|
.append(this.name, rhs.name) //
|
||||||
|
.append(this.isBaseLendingRate, rhs.isBaseLendingRate) //
|
||||||
|
.append(this.isActive, rhs.isActive) //
|
||||||
|
.isEquals();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return new HashCodeBuilder(17, 37) //
|
||||||
|
.append(this.id) //
|
||||||
|
.append(this.name) //
|
||||||
|
.append(this.isBaseLendingRate) //
|
||||||
|
.append(this.isActive) //
|
||||||
|
.toHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FloatingRateData toTemplate(
|
||||||
|
List<EnumOptionData> interestRateFrequencyTypeOptions) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return new FloatingRateData(null, null, false, true, null, null, null,
|
||||||
|
null, null, interestRateFrequencyTypeOptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
+123
@@ -0,0 +1,123 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.floatingrates.data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.builder.CompareToBuilder;
|
||||||
|
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||||
|
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||||
|
import org.joda.time.LocalDate;
|
||||||
|
|
||||||
|
public class FloatingRatePeriodData implements
|
||||||
|
Comparable<FloatingRatePeriodData> {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private Date fromDate;
|
||||||
|
private BigDecimal interestRate;
|
||||||
|
private boolean isDifferentialToBaseLendingRate;
|
||||||
|
private boolean isActive;
|
||||||
|
private String createdBy;
|
||||||
|
private Date createdOn;
|
||||||
|
private String modifiedBy;
|
||||||
|
private Date modifiedOn;
|
||||||
|
|
||||||
|
public FloatingRatePeriodData(Long id, Date fromDate,
|
||||||
|
BigDecimal interestRate, boolean isDifferentialToBaseLendingRate,
|
||||||
|
boolean isActive, String createdBy, Date createdOn,
|
||||||
|
String modifiedBy, Date modifiedOn) {
|
||||||
|
this.id = id;
|
||||||
|
this.fromDate = fromDate;
|
||||||
|
this.interestRate = interestRate;
|
||||||
|
this.isDifferentialToBaseLendingRate = isDifferentialToBaseLendingRate;
|
||||||
|
this.isActive = isActive;
|
||||||
|
this.createdBy = createdBy;
|
||||||
|
this.createdOn = createdOn;
|
||||||
|
this.modifiedBy = modifiedBy;
|
||||||
|
this.modifiedOn = modifiedOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getFromDate() {
|
||||||
|
return this.fromDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getFromDateAsLocalDate() {
|
||||||
|
return new LocalDate(this.fromDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getInterestRate() {
|
||||||
|
return this.interestRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDifferentialToBaseLendingRate() {
|
||||||
|
return this.isDifferentialToBaseLendingRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isActive() {
|
||||||
|
return this.isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCreatedBy() {
|
||||||
|
return this.createdBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreatedOn() {
|
||||||
|
return this.createdOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModifiedBy() {
|
||||||
|
return this.modifiedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getModifiedOn() {
|
||||||
|
return this.modifiedOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(final FloatingRatePeriodData obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return new CompareToBuilder() //
|
||||||
|
.append(this.id, obj.id) //
|
||||||
|
.append(this.fromDate, obj.fromDate) //
|
||||||
|
.append(this.isActive, obj.isActive) //
|
||||||
|
.toComparison();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (obj == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj.getClass() != getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final FloatingRatePeriodData rhs = (FloatingRatePeriodData) obj;
|
||||||
|
return new EqualsBuilder() //
|
||||||
|
.append(this.id, rhs.id) //
|
||||||
|
.append(this.fromDate, rhs.fromDate) //
|
||||||
|
.append(this.isActive, rhs.isActive) //
|
||||||
|
.isEquals();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return new HashCodeBuilder(17, 37) //
|
||||||
|
.append(this.id) //
|
||||||
|
.append(this.fromDate) //
|
||||||
|
.append(this.isActive) //
|
||||||
|
.toHashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
+81
@@ -0,0 +1,81 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.floatingrates.data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class InterestRatePeriodData {
|
||||||
|
|
||||||
|
private Date fromDate;
|
||||||
|
private final BigDecimal interestRate;
|
||||||
|
private final boolean isDifferentialToBLR;
|
||||||
|
private final Date blrFromDate;
|
||||||
|
private final BigDecimal blrInterestRate;
|
||||||
|
private BigDecimal loanDifferentialInterestRate;
|
||||||
|
private BigDecimal loanProductDifferentialInterestRate;
|
||||||
|
private BigDecimal effectiveInterestRate;
|
||||||
|
|
||||||
|
public InterestRatePeriodData(Date fromDate, BigDecimal interestRate,
|
||||||
|
boolean isDifferentialToBLR, Date blrFromDate,
|
||||||
|
BigDecimal blrInterestRate) {
|
||||||
|
this.fromDate = fromDate;
|
||||||
|
this.interestRate = interestRate;
|
||||||
|
this.isDifferentialToBLR = isDifferentialToBLR;
|
||||||
|
this.blrFromDate = blrFromDate;
|
||||||
|
this.blrInterestRate = blrInterestRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getFromDate() {
|
||||||
|
return this.fromDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFromDate(Date fromDate) {
|
||||||
|
this.fromDate = fromDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getInterestRate() {
|
||||||
|
return this.interestRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDifferentialToBLR() {
|
||||||
|
return this.isDifferentialToBLR;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getBlrFromDate() {
|
||||||
|
return this.blrFromDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getBlrInterestRate() {
|
||||||
|
return this.blrInterestRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getLoanDifferentialInterestRate() {
|
||||||
|
return this.loanDifferentialInterestRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLoanDifferentialInterestRate(
|
||||||
|
BigDecimal loanDifferentialInterestRate) {
|
||||||
|
this.loanDifferentialInterestRate = loanDifferentialInterestRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getLoanProductDifferentialInterestRate() {
|
||||||
|
return this.loanProductDifferentialInterestRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLoanProductDifferentialInterestRate(
|
||||||
|
BigDecimal loanProductDifferentialInterestRate) {
|
||||||
|
this.loanProductDifferentialInterestRate = loanProductDifferentialInterestRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getEffectiveInterestRate() {
|
||||||
|
return this.effectiveInterestRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEffectiveInterestRate(BigDecimal effectiveInterestRate) {
|
||||||
|
this.effectiveInterestRate = effectiveInterestRate;
|
||||||
|
}
|
||||||
|
}
|
||||||
+269
@@ -0,0 +1,269 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.floatingrates.domain;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.persistence.CascadeType;
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
|
import javax.persistence.OrderBy;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.UniqueConstraint;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.LazyCollection;
|
||||||
|
import org.hibernate.annotations.LazyCollectionOption;
|
||||||
|
import org.joda.time.LocalDate;
|
||||||
|
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.mifosplatform.infrastructure.core.serialization.JsonParserHelper;
|
||||||
|
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRateDTO;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRatePeriodData;
|
||||||
|
import org.mifosplatform.useradministration.domain.AppUser;
|
||||||
|
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "m_floating_rates", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "unq_name") })
|
||||||
|
public class FloatingRate extends AbstractPersistable<Long> {
|
||||||
|
|
||||||
|
@Column(name = "name", length = 200, unique = true, nullable = false)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Column(name = "is_base_lending_rate", nullable = false)
|
||||||
|
private boolean isBaseLendingRate;
|
||||||
|
|
||||||
|
@Column(name = "is_active", nullable = false)
|
||||||
|
private boolean isActive;
|
||||||
|
|
||||||
|
@OrderBy(value = "fromDate,id")
|
||||||
|
@LazyCollection(LazyCollectionOption.FALSE)
|
||||||
|
@OneToMany(cascade = CascadeType.ALL, mappedBy = "floatingRate", orphanRemoval = true)
|
||||||
|
private Set<FloatingRatePeriod> floatingRatePeriods;
|
||||||
|
|
||||||
|
@ManyToOne(optional = true)
|
||||||
|
@JoinColumn(name = "createdby_id", nullable = false)
|
||||||
|
private AppUser createdBy;
|
||||||
|
|
||||||
|
@ManyToOne(optional = true)
|
||||||
|
@JoinColumn(name = "lastmodifiedby_id", nullable = false)
|
||||||
|
private AppUser modifiedBy;
|
||||||
|
|
||||||
|
@Column(name = "created_date", nullable = false)
|
||||||
|
private Date createdOn;
|
||||||
|
|
||||||
|
@Column(name = "lastmodified_date", nullable = false)
|
||||||
|
private Date modifiedOn;
|
||||||
|
|
||||||
|
public FloatingRate() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public FloatingRate(String name, boolean isBaseLendingRate,
|
||||||
|
boolean isActive, Set<FloatingRatePeriod> floatingRatePeriods,
|
||||||
|
AppUser createdBy, AppUser modifiedBy, Date createdOn,
|
||||||
|
Date modifiedOn) {
|
||||||
|
this.name = name;
|
||||||
|
this.isBaseLendingRate = isBaseLendingRate;
|
||||||
|
this.isActive = isActive;
|
||||||
|
this.floatingRatePeriods = floatingRatePeriods;
|
||||||
|
this.createdBy = createdBy;
|
||||||
|
this.createdOn = createdOn;
|
||||||
|
this.modifiedBy = modifiedBy;
|
||||||
|
this.modifiedOn = modifiedOn;
|
||||||
|
if (floatingRatePeriods != null) {
|
||||||
|
for (FloatingRatePeriod ratePeriod : floatingRatePeriods) {
|
||||||
|
ratePeriod.updateFloatingRate(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FloatingRate createNew(AppUser currentUser,
|
||||||
|
JsonCommand command) {
|
||||||
|
|
||||||
|
final String name = command.stringValueOfParameterNamed("name");
|
||||||
|
final boolean isBaseLendingRate = command
|
||||||
|
.parameterExists("isBaseLendingRate") ? command
|
||||||
|
.booleanPrimitiveValueOfParameterNamed("isBaseLendingRate")
|
||||||
|
: false;
|
||||||
|
final boolean isActive = command.parameterExists("isActive") ? command
|
||||||
|
.booleanPrimitiveValueOfParameterNamed("isActive") : true;
|
||||||
|
final Set<FloatingRatePeriod> floatingRatePeriods = getRatePeriods(
|
||||||
|
currentUser, command);
|
||||||
|
final LocalDate currentDate = DateUtils.getLocalDateOfTenant();
|
||||||
|
|
||||||
|
return new FloatingRate(name, isBaseLendingRate, isActive,
|
||||||
|
floatingRatePeriods, currentUser, currentUser,
|
||||||
|
currentDate.toDate(), currentDate.toDate());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<FloatingRatePeriod> getRatePeriods(
|
||||||
|
final AppUser currentUser, final JsonCommand command) {
|
||||||
|
if (!command.parameterExists("ratePeriods")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Set<FloatingRatePeriod> ratePeriods = new HashSet<>();
|
||||||
|
JsonArray arrayOfParameterNamed = command
|
||||||
|
.arrayOfParameterNamed("ratePeriods");
|
||||||
|
for (final JsonElement ratePeriod : arrayOfParameterNamed) {
|
||||||
|
final JsonObject ratePeriodObject = ratePeriod.getAsJsonObject();
|
||||||
|
final JsonParserHelper helper = new JsonParserHelper();
|
||||||
|
final Date fromDate = helper.extractLocalDateNamed("fromDate",
|
||||||
|
ratePeriod, new HashSet<String>()).toDate();
|
||||||
|
final BigDecimal interestRate = ratePeriodObject
|
||||||
|
.get("interestRate").getAsBigDecimal();
|
||||||
|
final boolean isDifferentialToBaseLendingRate = helper
|
||||||
|
.parameterExists("isDifferentialToBaseLendingRate",
|
||||||
|
ratePeriod) ? ratePeriodObject.get(
|
||||||
|
"isDifferentialToBaseLendingRate").getAsBoolean() : false;
|
||||||
|
final boolean isActive = true;
|
||||||
|
final Date currentDate = DateUtils.getDateOfTenant();
|
||||||
|
ratePeriods.add(new FloatingRatePeriod(fromDate, interestRate,
|
||||||
|
isDifferentialToBaseLendingRate, isActive, currentUser,
|
||||||
|
currentUser, currentDate, currentDate));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ratePeriods;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBaseLendingRate() {
|
||||||
|
return this.isBaseLendingRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isActive() {
|
||||||
|
return this.isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<FloatingRatePeriod> getFloatingRatePeriods() {
|
||||||
|
return this.floatingRatePeriods;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppUser getCreatedBy() {
|
||||||
|
return this.createdBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppUser getModifiedBy() {
|
||||||
|
return this.modifiedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreatedOn() {
|
||||||
|
return this.createdOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getModifiedOn() {
|
||||||
|
return this.modifiedOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> update(final JsonCommand command,
|
||||||
|
final AppUser appUser) {
|
||||||
|
|
||||||
|
final Map<String, Object> actualChanges = new LinkedHashMap<>(9);
|
||||||
|
|
||||||
|
if (command.isChangeInStringParameterNamed("name", this.name)) {
|
||||||
|
final String newValue = command.stringValueOfParameterNamed("name");
|
||||||
|
actualChanges.put("name", newValue);
|
||||||
|
this.name = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command.isChangeInBooleanParameterNamed("isBaseLendingRate",
|
||||||
|
this.isBaseLendingRate)) {
|
||||||
|
final boolean newValue = command
|
||||||
|
.booleanPrimitiveValueOfParameterNamed("isBaseLendingRate");
|
||||||
|
actualChanges.put("isBaseLendingRate", newValue);
|
||||||
|
this.isBaseLendingRate = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command.isChangeInBooleanParameterNamed("isActive", this.isActive)) {
|
||||||
|
final boolean newValue = command
|
||||||
|
.booleanPrimitiveValueOfParameterNamed("isActive");
|
||||||
|
actualChanges.put("isActive", newValue);
|
||||||
|
this.isActive = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Set<FloatingRatePeriod> newRatePeriods = getRatePeriods(appUser,
|
||||||
|
command);
|
||||||
|
if (newRatePeriods != null && !newRatePeriods.isEmpty()) {
|
||||||
|
updateRatePeriods(newRatePeriods, appUser);
|
||||||
|
actualChanges.put("ratePeriods",
|
||||||
|
command.jsonFragment("ratePeriods"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return actualChanges;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateRatePeriods(
|
||||||
|
final Set<FloatingRatePeriod> newRatePeriods, final AppUser appUser) {
|
||||||
|
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||||
|
if (this.floatingRatePeriods != null) {
|
||||||
|
for (FloatingRatePeriod ratePeriod : this.floatingRatePeriods) {
|
||||||
|
LocalDate fromDate = LocalDate.fromDateFields(ratePeriod
|
||||||
|
.getFromDate());
|
||||||
|
if (fromDate.isAfter(today)) {
|
||||||
|
ratePeriod.setActive(false);
|
||||||
|
ratePeriod.setModifiedBy(appUser);
|
||||||
|
ratePeriod.setModifiedOn(today.toDate());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (FloatingRatePeriod newRatePeriod : newRatePeriods) {
|
||||||
|
newRatePeriod.updateFloatingRate(this);
|
||||||
|
this.floatingRatePeriods.add(newRatePeriod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<FloatingRatePeriodData> fetchInterestRates(
|
||||||
|
final FloatingRateDTO floatingRateDTO) {
|
||||||
|
Collection<FloatingRatePeriodData> applicableRates = new ArrayList<>();
|
||||||
|
FloatingRatePeriod previousPeriod = null;
|
||||||
|
boolean addPeriodData = false;
|
||||||
|
for (FloatingRatePeriod floatingRatePeriod : this.floatingRatePeriods) {
|
||||||
|
if (floatingRatePeriod.isActive()) {
|
||||||
|
// will enter
|
||||||
|
if (applicableRates.isEmpty()
|
||||||
|
&& floatingRateDTO.getStartDate().isBefore(
|
||||||
|
floatingRatePeriod.fetchFromDate())) {
|
||||||
|
if (floatingRateDTO.isFloatingInterestRate()) {
|
||||||
|
addPeriodData = true;
|
||||||
|
}
|
||||||
|
if (previousPeriod != null) {
|
||||||
|
applicableRates.add(previousPeriod
|
||||||
|
.toData(floatingRateDTO));
|
||||||
|
} else if (!addPeriodData) {
|
||||||
|
applicableRates.add(floatingRatePeriod
|
||||||
|
.toData(floatingRateDTO));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (addPeriodData) {
|
||||||
|
applicableRates.add(floatingRatePeriod
|
||||||
|
.toData(floatingRateDTO));
|
||||||
|
}
|
||||||
|
previousPeriod = floatingRatePeriod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (applicableRates.isEmpty() && previousPeriod != null) {
|
||||||
|
applicableRates.add(previousPeriod.toData(floatingRateDTO));
|
||||||
|
}
|
||||||
|
return applicableRates;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+146
@@ -0,0 +1,146 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.floatingrates.domain;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.joda.time.LocalDate;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRateDTO;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRatePeriodData;
|
||||||
|
import org.mifosplatform.useradministration.domain.AppUser;
|
||||||
|
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "m_floating_rates_periods")
|
||||||
|
public class FloatingRatePeriod extends AbstractPersistable<Long> {
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "floating_rates_id", nullable = false)
|
||||||
|
private FloatingRate floatingRate;
|
||||||
|
|
||||||
|
@Column(name = "from_date", nullable = false)
|
||||||
|
private Date fromDate;
|
||||||
|
|
||||||
|
@Column(name = "interest_rate", scale = 6, precision = 19, nullable = false)
|
||||||
|
private BigDecimal interestRate;
|
||||||
|
|
||||||
|
@Column(name = "is_differential_to_base_lending_rate", nullable = false)
|
||||||
|
private boolean isDifferentialToBaseLendingRate;
|
||||||
|
|
||||||
|
@Column(name = "is_active", nullable = false)
|
||||||
|
private boolean isActive;
|
||||||
|
|
||||||
|
@ManyToOne(optional = true)
|
||||||
|
@JoinColumn(name = "createdby_id", nullable = false)
|
||||||
|
private AppUser createdBy;
|
||||||
|
|
||||||
|
@ManyToOne(optional = true)
|
||||||
|
@JoinColumn(name = "lastmodifiedby_id", nullable = false)
|
||||||
|
private AppUser modifiedBy;
|
||||||
|
|
||||||
|
@Column(name = "created_date", nullable = false)
|
||||||
|
private Date createdOn;
|
||||||
|
|
||||||
|
@Column(name = "lastmodified_date", nullable = false)
|
||||||
|
private Date modifiedOn;
|
||||||
|
|
||||||
|
public FloatingRatePeriod() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public FloatingRatePeriod(Date fromDate, BigDecimal interestRate,
|
||||||
|
boolean isDifferentialToBaseLendingRate, boolean isActive,
|
||||||
|
AppUser createdBy, AppUser modifiedBy, Date createdOn,
|
||||||
|
Date modifiedOn) {
|
||||||
|
this.fromDate = fromDate;
|
||||||
|
this.interestRate = interestRate;
|
||||||
|
this.isDifferentialToBaseLendingRate = isDifferentialToBaseLendingRate;
|
||||||
|
this.isActive = isActive;
|
||||||
|
this.createdBy = createdBy;
|
||||||
|
this.modifiedBy = modifiedBy;
|
||||||
|
this.createdOn = createdOn;
|
||||||
|
this.modifiedOn = modifiedOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateFloatingRate(FloatingRate floatingRate) {
|
||||||
|
this.floatingRate = floatingRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FloatingRate getFloatingRatesId() {
|
||||||
|
return this.floatingRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getFromDate() {
|
||||||
|
return this.fromDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getInterestRate() {
|
||||||
|
return this.interestRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDifferentialToBaseLendingRate() {
|
||||||
|
return this.isDifferentialToBaseLendingRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isActive() {
|
||||||
|
return this.isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppUser getCreatedBy() {
|
||||||
|
return this.createdBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppUser getModifiedBy() {
|
||||||
|
return this.modifiedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreatedOn() {
|
||||||
|
return this.createdOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getModifiedOn() {
|
||||||
|
return this.modifiedOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModifiedBy(AppUser modifiedBy) {
|
||||||
|
this.modifiedBy = modifiedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModifiedOn(Date modifiedOn) {
|
||||||
|
this.modifiedOn = modifiedOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setActive(boolean b) {
|
||||||
|
this.isActive = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate fetchFromDate() {
|
||||||
|
return new LocalDate(this.fromDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FloatingRatePeriodData toData(final FloatingRateDTO floatingRateDTO) {
|
||||||
|
|
||||||
|
BigDecimal interest = getInterestRate().add(
|
||||||
|
floatingRateDTO.getInterestRateDiff());
|
||||||
|
if (isDifferentialToBaseLendingRate()) {
|
||||||
|
interest = interest.add(floatingRateDTO
|
||||||
|
.fetchBaseRate(fetchFromDate()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new FloatingRatePeriodData(getId(), getFromDate(), interest,
|
||||||
|
isDifferentialToBaseLendingRate(), isActive(), getCreatedBy()
|
||||||
|
.getUsername(), getCreatedOn(), getModifiedBy()
|
||||||
|
.getUsername(), getModifiedOn());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.floatingrates.domain;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
|
||||||
|
public interface FloatingRateRepository extends
|
||||||
|
JpaRepository<FloatingRate, Long>,
|
||||||
|
JpaSpecificationExecutor<FloatingRate> {
|
||||||
|
|
||||||
|
@Query("from FloatingRate floatingRate where floatingRate.isBaseLendingRate = 1 and floatingRate.isActive = 1")
|
||||||
|
FloatingRate retrieveBaseLendingRate();
|
||||||
|
|
||||||
|
}
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.floatingrates.domain;
|
||||||
|
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.exception.FloatingRateNotFoundException;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class FloatingRateRepositoryWrapper {
|
||||||
|
|
||||||
|
private final FloatingRateRepository floatingRateRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public FloatingRateRepositoryWrapper(
|
||||||
|
final FloatingRateRepository floatingRateRepository) {
|
||||||
|
this.floatingRateRepository = floatingRateRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FloatingRate retrieveBaseLendingRate() {
|
||||||
|
return this.floatingRateRepository.retrieveBaseLendingRate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public FloatingRate findOneWithNotFoundDetection(final Long id) {
|
||||||
|
final FloatingRate floatingRate = this.floatingRateRepository
|
||||||
|
.findOne(id);
|
||||||
|
if (floatingRate == null) {
|
||||||
|
throw new FloatingRateNotFoundException(id);
|
||||||
|
}
|
||||||
|
return floatingRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save(FloatingRate newFloatingRate) {
|
||||||
|
this.floatingRateRepository.save(newFloatingRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveAndFlush(FloatingRate floatingRateForUpdate) {
|
||||||
|
this.floatingRateRepository.saveAndFlush(floatingRateForUpdate);
|
||||||
|
}
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.floatingrates.exception;
|
||||||
|
|
||||||
|
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
||||||
|
|
||||||
|
public class FloatingRateNotFoundException extends
|
||||||
|
AbstractPlatformResourceNotFoundException {
|
||||||
|
|
||||||
|
public FloatingRateNotFoundException(final Long id) {
|
||||||
|
super("error.msg.floatingrate.id.invalid",
|
||||||
|
"Floating Rate with identifier " + id + " does not exist", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FloatingRateNotFoundException(final String globalisationMessageCode) {
|
||||||
|
super(globalisationMessageCode, "Floating Rate does not exist");
|
||||||
|
}
|
||||||
|
}
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.floatingrates.handler;
|
||||||
|
|
||||||
|
import org.mifosplatform.commands.annotation.CommandType;
|
||||||
|
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
|
||||||
|
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.service.FloatingRateWritePlatformService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@CommandType(entity = "FLOATINGRATE", action = "CREATE")
|
||||||
|
public class CreateFloatingRateCommandHandler implements
|
||||||
|
NewCommandSourceHandler {
|
||||||
|
|
||||||
|
private final FloatingRateWritePlatformService writePlatformService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public CreateFloatingRateCommandHandler(
|
||||||
|
final FloatingRateWritePlatformService writePlatformService) {
|
||||||
|
this.writePlatformService = writePlatformService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||||
|
return this.writePlatformService.createFloatingRate(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.floatingrates.handler;
|
||||||
|
|
||||||
|
import org.mifosplatform.commands.annotation.CommandType;
|
||||||
|
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
|
||||||
|
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.service.FloatingRateWritePlatformService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@CommandType(entity = "FLOATINGRATE", action = "UPDATE")
|
||||||
|
public class UpdateFloatingRateCommandHandler implements
|
||||||
|
NewCommandSourceHandler {
|
||||||
|
|
||||||
|
private final FloatingRateWritePlatformService writePlatformService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public UpdateFloatingRateCommandHandler(
|
||||||
|
final FloatingRateWritePlatformService writePlatformService) {
|
||||||
|
this.writePlatformService = writePlatformService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||||
|
return this.writePlatformService.updateFloatingRate(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
+263
@@ -0,0 +1,263 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.floatingrates.serialization;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.joda.time.LocalDate;
|
||||||
|
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||||
|
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||||
|
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||||
|
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||||
|
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.domain.FloatingRate;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.domain.FloatingRateRepository;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class FloatingRateDataValidator {
|
||||||
|
|
||||||
|
private final Set<String> supportedParametersForFloatingRates = new HashSet<>(
|
||||||
|
Arrays.asList("name", "isBaseLendingRate", "isActive",
|
||||||
|
"ratePeriods"));
|
||||||
|
private final Set<String> supportedParametersForFloatingRatePeriods = new HashSet<>(
|
||||||
|
Arrays.asList("fromDate", "interestRate",
|
||||||
|
"isDifferentialToBaseLendingRate", "locale", "dateFormat"));
|
||||||
|
|
||||||
|
private final FromJsonHelper fromApiJsonHelper;
|
||||||
|
private final FloatingRateRepository floatingRateRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public FloatingRateDataValidator(final FromJsonHelper fromApiJsonHelper,
|
||||||
|
final FloatingRateRepository floatingRateRepository) {
|
||||||
|
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||||
|
this.floatingRateRepository = floatingRateRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validateForCreate(String json) {
|
||||||
|
final Type typeOfMap = new TypeToken<Map<String, Object>>() {
|
||||||
|
}.getType();
|
||||||
|
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json,
|
||||||
|
this.supportedParametersForFloatingRates);
|
||||||
|
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||||
|
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(
|
||||||
|
dataValidationErrors).resource("floatingrate");
|
||||||
|
|
||||||
|
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||||
|
|
||||||
|
final String name = this.fromApiJsonHelper.extractStringNamed("name",
|
||||||
|
element);
|
||||||
|
baseDataValidator.reset().parameter("name").value(name).notBlank()
|
||||||
|
.notExceedingLengthOf(200);
|
||||||
|
|
||||||
|
if (this.fromApiJsonHelper
|
||||||
|
.parameterExists("isBaseLendingRate", element)) {
|
||||||
|
final Boolean isBaseLendingRate = this.fromApiJsonHelper
|
||||||
|
.extractBooleanNamed("isBaseLendingRate", element);
|
||||||
|
|
||||||
|
baseDataValidator.reset().parameter("isBaseLendingRate")
|
||||||
|
.value(isBaseLendingRate).notNull();
|
||||||
|
if (isBaseLendingRate == null) {
|
||||||
|
baseDataValidator.reset().parameter("isBaseLendingRate")
|
||||||
|
.trueOrFalseRequired(false);
|
||||||
|
} else if (isBaseLendingRate) {
|
||||||
|
FloatingRate baseLendingRate = this.floatingRateRepository
|
||||||
|
.retrieveBaseLendingRate();
|
||||||
|
if (baseLendingRate != null) {
|
||||||
|
baseDataValidator
|
||||||
|
.reset()
|
||||||
|
.parameter("isBaseLendingRate")
|
||||||
|
.value(isBaseLendingRate)
|
||||||
|
.failWithCode("baselendingrate.duplicate",
|
||||||
|
"Base Lending Rate already exists");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.fromApiJsonHelper.parameterExists("isActive", element)) {
|
||||||
|
final Boolean isActive = this.fromApiJsonHelper
|
||||||
|
.extractBooleanNamed("isActive", element);
|
||||||
|
if (isActive == null) {
|
||||||
|
baseDataValidator.reset().parameter("isActive")
|
||||||
|
.trueOrFalseRequired(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validateRatePeriods(baseDataValidator, element);
|
||||||
|
|
||||||
|
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateRatePeriods(DataValidatorBuilder baseDataValidator,
|
||||||
|
JsonElement element) {
|
||||||
|
if (this.fromApiJsonHelper.parameterExists("ratePeriods", element)) {
|
||||||
|
final JsonArray ratePeriods = this.fromApiJsonHelper
|
||||||
|
.extractJsonArrayNamed("ratePeriods", element);
|
||||||
|
baseDataValidator.reset().parameter("ratePeriods")
|
||||||
|
.value(ratePeriods).notBlank().jsonArrayNotEmpty();
|
||||||
|
|
||||||
|
if (ratePeriods != null) {
|
||||||
|
List<LocalDate> fromDates = new ArrayList<>();
|
||||||
|
for (int i = 0; i < ratePeriods.size(); i++) {
|
||||||
|
final JsonElement ratePeriod = ratePeriods.get(i);
|
||||||
|
|
||||||
|
this.fromApiJsonHelper.checkForUnsupportedParameters(
|
||||||
|
ratePeriod.getAsJsonObject(),
|
||||||
|
this.supportedParametersForFloatingRatePeriods);
|
||||||
|
|
||||||
|
final LocalDate fromDate = this.fromApiJsonHelper
|
||||||
|
.extractLocalDateNamed("fromDate", ratePeriod);
|
||||||
|
baseDataValidator
|
||||||
|
.reset()
|
||||||
|
.parameter("fromDate")
|
||||||
|
.parameterAtIndexArray("fromDate", i + 1)
|
||||||
|
.value(fromDate)
|
||||||
|
.notBlank()
|
||||||
|
.validateDateAfter(
|
||||||
|
DateUtils.getLocalDateOfTenant()
|
||||||
|
.plusDays(1));
|
||||||
|
if (fromDate != null) {
|
||||||
|
fromDates.add(fromDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
final BigDecimal interestRatePerPeriod = this.fromApiJsonHelper
|
||||||
|
.extractBigDecimalWithLocaleNamed("interestRate",
|
||||||
|
ratePeriod);
|
||||||
|
baseDataValidator.reset().parameter("interestRate")
|
||||||
|
.parameterAtIndexArray("interestRate", i + 1)
|
||||||
|
.value(interestRatePerPeriod).notNull()
|
||||||
|
.zeroOrPositiveAmount();
|
||||||
|
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(
|
||||||
|
"isDifferentialToBaseLendingRate", ratePeriod)) {
|
||||||
|
final Boolean isDifferentialToBaseLendingRate = this.fromApiJsonHelper
|
||||||
|
.extractBooleanNamed(
|
||||||
|
"isDifferentialToBaseLendingRate",
|
||||||
|
ratePeriod);
|
||||||
|
if (isDifferentialToBaseLendingRate == null) {
|
||||||
|
baseDataValidator
|
||||||
|
.reset()
|
||||||
|
.parameter(
|
||||||
|
"isDifferentialToBaseLendingRate")
|
||||||
|
.parameterAtIndexArray(
|
||||||
|
"isDifferentialToBaseLendingRate",
|
||||||
|
i + 1).trueOrFalseRequired(false);
|
||||||
|
} else if (isDifferentialToBaseLendingRate) {
|
||||||
|
FloatingRate baseLendingRate = this.floatingRateRepository
|
||||||
|
.retrieveBaseLendingRate();
|
||||||
|
if (baseLendingRate == null) {
|
||||||
|
baseDataValidator
|
||||||
|
.reset()
|
||||||
|
.parameter(
|
||||||
|
"isDifferentialToBaseLendingRate")
|
||||||
|
.parameterAtIndexArray(
|
||||||
|
"isDifferentialToBaseLendingRate",
|
||||||
|
i + 1)
|
||||||
|
.value(isDifferentialToBaseLendingRate)
|
||||||
|
.failWithCode(
|
||||||
|
"no.baselending.rate.defined",
|
||||||
|
"Base Lending Rate doesn't exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Set<LocalDate> uniqueFromDates = new HashSet<>(fromDates);
|
||||||
|
if (fromDates.size() != uniqueFromDates.size()) {
|
||||||
|
baseDataValidator
|
||||||
|
.reset()
|
||||||
|
.parameter("fromDate")
|
||||||
|
.failWithCode("multiple.same.date",
|
||||||
|
"More than one entry in ratePeriods have same fromDate.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validateForUpdate(String json,
|
||||||
|
FloatingRate floatingRateForUpdate) {
|
||||||
|
final Type typeOfMap = new TypeToken<Map<String, Object>>() {
|
||||||
|
}.getType();
|
||||||
|
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json,
|
||||||
|
this.supportedParametersForFloatingRates);
|
||||||
|
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||||
|
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(
|
||||||
|
dataValidationErrors).resource("floatingrate");
|
||||||
|
|
||||||
|
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||||
|
|
||||||
|
if (this.fromApiJsonHelper.parameterExists("name", element)) {
|
||||||
|
final String name = this.fromApiJsonHelper.extractStringNamed(
|
||||||
|
"name", element);
|
||||||
|
baseDataValidator.reset().parameter("name").value(name).notBlank()
|
||||||
|
.notExceedingLengthOf(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.fromApiJsonHelper
|
||||||
|
.parameterExists("isBaseLendingRate", element)) {
|
||||||
|
final Boolean isBaseLendingRate = this.fromApiJsonHelper
|
||||||
|
.extractBooleanNamed("isBaseLendingRate", element);
|
||||||
|
|
||||||
|
baseDataValidator.reset().parameter("isBaseLendingRate")
|
||||||
|
.value(isBaseLendingRate).notNull();
|
||||||
|
if (isBaseLendingRate == null) {
|
||||||
|
baseDataValidator.reset().parameter("isBaseLendingRate")
|
||||||
|
.trueOrFalseRequired(false);
|
||||||
|
} else if (isBaseLendingRate) {
|
||||||
|
FloatingRate baseLendingRate = this.floatingRateRepository
|
||||||
|
.retrieveBaseLendingRate();
|
||||||
|
if (baseLendingRate != null
|
||||||
|
&& baseLendingRate.getId() != floatingRateForUpdate
|
||||||
|
.getId()) {
|
||||||
|
baseDataValidator
|
||||||
|
.reset()
|
||||||
|
.parameter("isBaseLendingRate")
|
||||||
|
.value(isBaseLendingRate)
|
||||||
|
.failWithCode("baselendingrate.duplicate",
|
||||||
|
"Base Lending Rate already exists");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.fromApiJsonHelper.parameterExists("isActive", element)) {
|
||||||
|
final Boolean isActive = this.fromApiJsonHelper
|
||||||
|
.extractBooleanNamed("isActive", element);
|
||||||
|
if (isActive == null) {
|
||||||
|
baseDataValidator.reset().parameter("isActive")
|
||||||
|
.trueOrFalseRequired(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validateRatePeriods(baseDataValidator, element);
|
||||||
|
|
||||||
|
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void throwExceptionIfValidationWarningsExist(
|
||||||
|
final List<ApiParameterError> dataValidationErrors) {
|
||||||
|
if (!dataValidationErrors.isEmpty()) {
|
||||||
|
throw new PlatformApiDataValidationException(
|
||||||
|
"validation.msg.validation.errors.exist",
|
||||||
|
"Validation errors exist.", dataValidationErrors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.floatingrates.service;
|
||||||
|
|
||||||
|
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
|
||||||
|
public interface FloatingRateWritePlatformService {
|
||||||
|
|
||||||
|
public CommandProcessingResult createFloatingRate(JsonCommand command);
|
||||||
|
|
||||||
|
public CommandProcessingResult updateFloatingRate(JsonCommand command);
|
||||||
|
}
|
||||||
+124
@@ -0,0 +1,124 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.floatingrates.service;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||||
|
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||||
|
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.domain.FloatingRate;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.domain.FloatingRateRepositoryWrapper;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.serialization.FloatingRateDataValidator;
|
||||||
|
import org.mifosplatform.useradministration.domain.AppUser;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class FloatingRateWritePlatformServiceImpl implements
|
||||||
|
FloatingRateWritePlatformService {
|
||||||
|
|
||||||
|
private final static Logger logger = LoggerFactory
|
||||||
|
.getLogger(FloatingRateWritePlatformServiceImpl.class);
|
||||||
|
private final PlatformSecurityContext context;
|
||||||
|
private final FloatingRateDataValidator fromApiJsonDeserializer;
|
||||||
|
private final FloatingRateRepositoryWrapper floatingRateRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public FloatingRateWritePlatformServiceImpl(
|
||||||
|
final PlatformSecurityContext context,
|
||||||
|
final FloatingRateDataValidator fromApiJsonDeserializer,
|
||||||
|
final FloatingRateRepositoryWrapper floatingRateRepository) {
|
||||||
|
this.context = context;
|
||||||
|
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||||
|
this.floatingRateRepository = floatingRateRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult createFloatingRate(final JsonCommand command) {
|
||||||
|
try {
|
||||||
|
this.fromApiJsonDeserializer.validateForCreate(command.json());
|
||||||
|
final AppUser currentUser = this.context.authenticatedUser();
|
||||||
|
final FloatingRate newFloatingRate = FloatingRate.createNew(
|
||||||
|
currentUser, command);
|
||||||
|
this.floatingRateRepository.save(newFloatingRate);
|
||||||
|
return new CommandProcessingResultBuilder() //
|
||||||
|
.withCommandId(command.commandId()) //
|
||||||
|
.withEntityId(newFloatingRate.getId()) //
|
||||||
|
.build();
|
||||||
|
} catch (final DataIntegrityViolationException dve) {
|
||||||
|
handleDataIntegrityIssues(command, dve);
|
||||||
|
return CommandProcessingResult.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult updateFloatingRate(final JsonCommand command) {
|
||||||
|
try {
|
||||||
|
final FloatingRate floatingRateForUpdate = this.floatingRateRepository
|
||||||
|
.findOneWithNotFoundDetection(command.entityId());
|
||||||
|
this.fromApiJsonDeserializer.validateForUpdate(command.json(),
|
||||||
|
floatingRateForUpdate);
|
||||||
|
final AppUser currentUser = this.context.authenticatedUser();
|
||||||
|
final Map<String, Object> changes = floatingRateForUpdate.update(
|
||||||
|
command, currentUser);
|
||||||
|
|
||||||
|
if (!changes.isEmpty()) {
|
||||||
|
this.floatingRateRepository.save(floatingRateForUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CommandProcessingResultBuilder() //
|
||||||
|
.withCommandId(command.commandId()) //
|
||||||
|
.withEntityId(command.entityId()) //
|
||||||
|
.with(changes) //
|
||||||
|
.build();
|
||||||
|
} catch (final DataIntegrityViolationException dve) {
|
||||||
|
handleDataIntegrityIssues(command, dve);
|
||||||
|
return CommandProcessingResult.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleDataIntegrityIssues(final JsonCommand command,
|
||||||
|
final DataIntegrityViolationException dve) {
|
||||||
|
final Throwable realCause = dve.getMostSpecificCause();
|
||||||
|
|
||||||
|
if (realCause.getMessage().contains("unq_name")) {
|
||||||
|
|
||||||
|
final String name = command.stringValueOfParameterNamed("name");
|
||||||
|
throw new PlatformDataIntegrityException(
|
||||||
|
"error.msg.floatingrates.duplicate.name",
|
||||||
|
"Floating Rate with name `" + name + "` already exists",
|
||||||
|
"name", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (realCause.getMessage().contains("unq_rate_period")) {
|
||||||
|
throw new PlatformDataIntegrityException(
|
||||||
|
"error.msg.floatingrates.duplicate.active.fromdate",
|
||||||
|
"Attempt to add multiple floating rate periods with same fromdate",
|
||||||
|
"fromdate", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
logAsErrorUnexpectedDataIntegrityException(dve);
|
||||||
|
throw new PlatformDataIntegrityException(
|
||||||
|
"error.msg.floatingrates.unknown.data.integrity.issue",
|
||||||
|
"Unknown data integrity issue with resource.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logAsErrorUnexpectedDataIntegrityException(
|
||||||
|
DataIntegrityViolationException dve) {
|
||||||
|
logger.error(dve.getMessage(), dve);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.floatingrates.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRateData;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.InterestRatePeriodData;
|
||||||
|
|
||||||
|
public interface FloatingRatesReadPlatformService {
|
||||||
|
|
||||||
|
List<FloatingRateData> retrieveAll();
|
||||||
|
|
||||||
|
List<FloatingRateData> retrieveLookupActive();
|
||||||
|
|
||||||
|
FloatingRateData retrieveOne(Long floatingRateId);
|
||||||
|
|
||||||
|
List<FloatingRateData> retrieveAllActive();
|
||||||
|
|
||||||
|
FloatingRateData retrieveBaseLendingRate();
|
||||||
|
|
||||||
|
List<InterestRatePeriodData> retrieveInterestRatePeriods(Long floatingRateId);
|
||||||
|
|
||||||
|
}
|
||||||
+279
@@ -0,0 +1,279 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.floatingrates.service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRateData;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRatePeriodData;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.InterestRatePeriodData;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.exception.FloatingRateNotFoundException;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.dao.EmptyResultDataAccessException;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.jdbc.core.RowMapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class FloatingRatesReadPlatformServiceImpl implements
|
||||||
|
FloatingRatesReadPlatformService {
|
||||||
|
|
||||||
|
private final JdbcTemplate jdbcTemplate;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public FloatingRatesReadPlatformServiceImpl(
|
||||||
|
final RoutingDataSource dataSource) {
|
||||||
|
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<FloatingRateData> retrieveAll() {
|
||||||
|
FloatingRateRowMapper rateMapper = new FloatingRateRowMapper(false);
|
||||||
|
final String sql = "select " + rateMapper.schema();
|
||||||
|
return this.jdbcTemplate.query(sql, rateMapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<FloatingRateData> retrieveAllActive() {
|
||||||
|
FloatingRateRowMapper rateMapper = new FloatingRateRowMapper(false);
|
||||||
|
final String sql = "select " + rateMapper.schema()
|
||||||
|
+ " where rate.is_active = 1 ";
|
||||||
|
return this.jdbcTemplate.query(sql, rateMapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<FloatingRateData> retrieveLookupActive() {
|
||||||
|
FloatingRateLookupMapper rateMapper = new FloatingRateLookupMapper();
|
||||||
|
final String sql = "select " + rateMapper.schema()
|
||||||
|
+ " where rate.is_active = 1 ";
|
||||||
|
return this.jdbcTemplate.query(sql, rateMapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FloatingRateData retrieveOne(final Long floatingRateId) {
|
||||||
|
try {
|
||||||
|
FloatingRateRowMapper rateMapper = new FloatingRateRowMapper(true);
|
||||||
|
final String sql = "select " + rateMapper.schema()
|
||||||
|
+ " where rate.id = ?";
|
||||||
|
return this.jdbcTemplate.queryForObject(sql, rateMapper,
|
||||||
|
new Object[] { floatingRateId });
|
||||||
|
} catch (final EmptyResultDataAccessException e) {
|
||||||
|
throw new FloatingRateNotFoundException(floatingRateId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<InterestRatePeriodData> retrieveInterestRatePeriods(
|
||||||
|
final Long floatingRateId) {
|
||||||
|
try {
|
||||||
|
FloatingInterestRatePeriodRowMapper mapper = new FloatingInterestRatePeriodRowMapper();
|
||||||
|
return this.jdbcTemplate.query(mapper.schema(), mapper,
|
||||||
|
new Object[] { floatingRateId });
|
||||||
|
} catch (final EmptyResultDataAccessException e) {
|
||||||
|
throw new FloatingRateNotFoundException(floatingRateId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FloatingRateData retrieveBaseLendingRate() {
|
||||||
|
try {
|
||||||
|
FloatingRateRowMapper rateMapper = new FloatingRateRowMapper(true);
|
||||||
|
final String sql = "select "
|
||||||
|
+ rateMapper.schema()
|
||||||
|
+ " where rate.is_base_lending_rate = 1 and rate.is_active = 1";
|
||||||
|
return this.jdbcTemplate.queryForObject(sql, rateMapper);
|
||||||
|
} catch (final EmptyResultDataAccessException e) {
|
||||||
|
throw new FloatingRateNotFoundException(
|
||||||
|
"error.msg.floatingrate.base.lending.rate.not.found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class FloatingRateRowMapper implements
|
||||||
|
RowMapper<FloatingRateData> {
|
||||||
|
|
||||||
|
private final boolean addRatePeriods;
|
||||||
|
|
||||||
|
private final StringBuilder sqlQuery = new StringBuilder()
|
||||||
|
.append("rate.id as id, ")
|
||||||
|
.append("rate.name as name, ")
|
||||||
|
.append("rate.is_base_lending_rate as isBaseLendingRate, ")
|
||||||
|
.append("rate.is_active as isActive, ")
|
||||||
|
.append("crappu.username as createdBy, ")
|
||||||
|
.append("rate.created_date as createdOn, ")
|
||||||
|
.append("moappu.username as modifiedBy, ")
|
||||||
|
.append("rate.lastmodified_date as modifiedOn ")
|
||||||
|
.append("FROM m_floating_rates as rate ")
|
||||||
|
.append("LEFT JOIN m_appuser as crappu on rate.createdby_id = crappu.id ")
|
||||||
|
.append("LEFT JOIN m_appuser as moappu on rate.lastmodifiedby_id = moappu.id ");
|
||||||
|
|
||||||
|
public FloatingRateRowMapper(final boolean addRatePeriods) {
|
||||||
|
this.addRatePeriods = addRatePeriods;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FloatingRateData mapRow(final ResultSet rs,
|
||||||
|
@SuppressWarnings("unused") final int rowNum)
|
||||||
|
throws SQLException {
|
||||||
|
final Long id = rs.getLong("id");
|
||||||
|
final String name = rs.getString("name");
|
||||||
|
final boolean isBaseLendingRate = rs
|
||||||
|
.getBoolean("isBaseLendingRate");
|
||||||
|
final boolean isActive = rs.getBoolean("isActive");
|
||||||
|
final String createdBy = rs.getString("createdBy");
|
||||||
|
final Date createdOn = rs.getDate("createdOn");
|
||||||
|
final String modifiedBy = rs.getString("modifiedBy");
|
||||||
|
final Date modifiedOn = rs.getDate("modifiedOn");
|
||||||
|
List<FloatingRatePeriodData> ratePeriods = null;
|
||||||
|
if (addRatePeriods) {
|
||||||
|
FloatingRatePeriodRowMapper ratePeriodMapper = new FloatingRatePeriodRowMapper();
|
||||||
|
final String sql = "select "
|
||||||
|
+ ratePeriodMapper.schema()
|
||||||
|
+ " where period.is_active = 1 and period.floating_rates_id = ? "
|
||||||
|
+ " order by period.from_date desc ";
|
||||||
|
ratePeriods = jdbcTemplate.query(sql, ratePeriodMapper,
|
||||||
|
new Object[] { id });
|
||||||
|
}
|
||||||
|
return new FloatingRateData(id, name, isBaseLendingRate, isActive,
|
||||||
|
createdBy, createdOn, modifiedBy, modifiedOn, ratePeriods,
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String schema() {
|
||||||
|
return sqlQuery.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class FloatingRatePeriodRowMapper implements
|
||||||
|
RowMapper<FloatingRatePeriodData> {
|
||||||
|
|
||||||
|
private final StringBuilder sqlQuery = new StringBuilder()
|
||||||
|
.append("period.id as id, ")
|
||||||
|
.append("period.from_date as fromDate, ")
|
||||||
|
.append("period.interest_rate as interestRate, ")
|
||||||
|
.append("period.is_differential_to_base_lending_rate as isDifferentialToBaseLendingRate, ")
|
||||||
|
.append("period.is_active as isActive, ")
|
||||||
|
.append("crappu.username as createdBy, ")
|
||||||
|
.append("period.created_date as createdOn, ")
|
||||||
|
.append("moappu.username as modifiedBy, ")
|
||||||
|
.append("period.lastmodified_date as modifiedOn ")
|
||||||
|
.append("FROM m_floating_rates_periods as period ")
|
||||||
|
.append("LEFT JOIN m_appuser as crappu on period.createdby_id = crappu.id ")
|
||||||
|
.append("LEFT JOIN m_appuser as moappu on period.lastmodifiedby_id = moappu.id ");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FloatingRatePeriodData mapRow(final ResultSet rs,
|
||||||
|
@SuppressWarnings("unused") final int rowNum)
|
||||||
|
throws SQLException {
|
||||||
|
final Long id = rs.getLong("id");
|
||||||
|
final Date fromDate = rs.getDate("fromDate");
|
||||||
|
final BigDecimal interestRate = rs.getBigDecimal("interestRate");
|
||||||
|
final boolean isDifferentialToBaseLendingRate = rs
|
||||||
|
.getBoolean("isDifferentialToBaseLendingRate");
|
||||||
|
final boolean isActive = rs.getBoolean("isActive");
|
||||||
|
final String createdBy = rs.getString("createdBy");
|
||||||
|
final Date createdOn = rs.getDate("createdOn");
|
||||||
|
final String modifiedBy = rs.getString("modifiedBy");
|
||||||
|
final Date modifiedOn = rs.getDate("modifiedOn");
|
||||||
|
return new FloatingRatePeriodData(id, fromDate, interestRate,
|
||||||
|
isDifferentialToBaseLendingRate, isActive, createdBy,
|
||||||
|
createdOn, modifiedBy, modifiedOn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String schema() {
|
||||||
|
return sqlQuery.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class FloatingRateLookupMapper implements
|
||||||
|
RowMapper<FloatingRateData> {
|
||||||
|
|
||||||
|
private final StringBuilder sqlQuery = new StringBuilder()
|
||||||
|
.append("rate.id as id, ").append("rate.name as name, ")
|
||||||
|
.append("rate.is_base_lending_rate as isBaseLendingRate ")
|
||||||
|
.append("FROM m_floating_rates as rate ");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FloatingRateData mapRow(final ResultSet rs,
|
||||||
|
@SuppressWarnings("unused") final int rowNum)
|
||||||
|
throws SQLException {
|
||||||
|
final Long id = rs.getLong("id");
|
||||||
|
final String name = rs.getString("name");
|
||||||
|
final boolean isBaseLendingRate = rs
|
||||||
|
.getBoolean("isBaseLendingRate");
|
||||||
|
return new FloatingRateData(id, name, isBaseLendingRate, true,
|
||||||
|
null, null, null, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String schema() {
|
||||||
|
return sqlQuery.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class FloatingInterestRatePeriodRowMapper implements
|
||||||
|
RowMapper<InterestRatePeriodData> {
|
||||||
|
|
||||||
|
private final StringBuilder sqlQuery = new StringBuilder()
|
||||||
|
.append("select ")
|
||||||
|
.append(" linkedrateperiods.from_date as linkedrateperiods_from_date, ")
|
||||||
|
.append(" linkedrateperiods.interest_rate as linkedrateperiods_interest_rate, ")
|
||||||
|
.append(" linkedrateperiods.is_differential_to_base_lending_rate as linkedrateperiods_is_differential_to_base_lending_rate, ")
|
||||||
|
.append(" baserate.from_date as baserate_from_date, ")
|
||||||
|
.append(" baserate.interest_rate as baserate_interest_rate ")
|
||||||
|
.append("from m_floating_rates as linkedrate ")
|
||||||
|
.append("left join m_floating_rates_periods as linkedrateperiods on (linkedrate.id = linkedrateperiods.floating_rates_id and linkedrateperiods.is_active = 1) ")
|
||||||
|
.append("left join ( ")
|
||||||
|
.append(" select blr.name, ")
|
||||||
|
.append(" blr.is_base_lending_rate, ")
|
||||||
|
.append(" blr.is_active, ")
|
||||||
|
.append(" blrperiods.from_date, ")
|
||||||
|
.append(" blrperiods.interest_rate ")
|
||||||
|
.append(" from m_floating_rates as blr ")
|
||||||
|
.append(" left join m_floating_rates_periods as blrperiods on (blr.id = blrperiods.floating_rates_id and blrperiods.is_active = 1) ")
|
||||||
|
.append(" where blr.is_base_lending_rate = 1 and blr.is_active = 1 ")
|
||||||
|
.append(") as baserate on (linkedrateperiods.is_differential_to_base_lending_rate = 1 and linkedrate.is_base_lending_rate = 0) ")
|
||||||
|
.append("where (baserate.from_date is null ")
|
||||||
|
.append(" or baserate.from_date = (select MAX(b.from_date) ")
|
||||||
|
.append(" from (select blr.name, ")
|
||||||
|
.append(" blr.is_base_lending_rate, ")
|
||||||
|
.append(" blr.is_active, ")
|
||||||
|
.append(" blrperiods.from_date, ")
|
||||||
|
.append(" blrperiods.interest_rate ")
|
||||||
|
.append(" from m_floating_rates as blr ")
|
||||||
|
.append(" left join m_floating_rates_periods as blrperiods on (blr.id = blrperiods.floating_rates_id and blrperiods.is_active = 1) ")
|
||||||
|
.append(" where blr.is_base_lending_rate = 1 and blr.is_active = 1 ")
|
||||||
|
.append(" ) as b ")
|
||||||
|
.append(" where b.from_date <= linkedrateperiods.from_date)) ")
|
||||||
|
.append("and linkedrate.id = ? ")
|
||||||
|
.append("order by linkedratePeriods_from_date desc ");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InterestRatePeriodData mapRow(final ResultSet rs,
|
||||||
|
@SuppressWarnings("unused") final int rowNum)
|
||||||
|
throws SQLException {
|
||||||
|
final Date fromDate = rs.getDate("linkedrateperiods_from_date");
|
||||||
|
final BigDecimal interestRate = rs
|
||||||
|
.getBigDecimal("linkedrateperiods_interest_rate");
|
||||||
|
final boolean isDifferentialToBLR = rs
|
||||||
|
.getBoolean("linkedrateperiods_is_differential_to_base_lending_rate");
|
||||||
|
final Date blrFromDate = rs.getDate("baserate_from_date");
|
||||||
|
final BigDecimal blrInterestRate = rs
|
||||||
|
.getBigDecimal("baserate_interest_rate");
|
||||||
|
|
||||||
|
return new InterestRatePeriodData(fromDate, interestRate,
|
||||||
|
isDifferentialToBLR, blrFromDate, blrInterestRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String schema() {
|
||||||
|
return sqlQuery.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+7
-1
@@ -34,6 +34,10 @@ public interface LoanApiConstants {
|
|||||||
public static final String interestRecalculationCompoundingMethodParameterName = "interestRecalculationCompoundingMethod";
|
public static final String interestRecalculationCompoundingMethodParameterName = "interestRecalculationCompoundingMethod";
|
||||||
public static final String rescheduleStrategyMethodParameterName = "rescheduleStrategyMethod";
|
public static final String rescheduleStrategyMethodParameterName = "rescheduleStrategyMethod";
|
||||||
|
|
||||||
|
// Floating interest rate related
|
||||||
|
public static final String interestRateDifferentialParameterName = "interestRateDifferential";
|
||||||
|
public static final String isFloatingInterestRateParameterName = "isFloatingInterestRate";
|
||||||
|
|
||||||
// Error codes
|
// Error codes
|
||||||
public static final String LOAN_CHARGE_CAN_NOT_BE_ADDED_WITH_INTEREST_CALCULATION_TYPE= "loancharge.with.calculation.type.interest.not.allowed";
|
public static final String LOAN_CHARGE_CAN_NOT_BE_ADDED_WITH_INTEREST_CALCULATION_TYPE= "loancharge.with.calculation.type.interest.not.allowed";
|
||||||
public static final String LOAN_CHARGE_CAN_NOT_BE_ADDED_WITH_PRINCIPAL_CALCULATION_TYPE= "loancharge.with.calculation.type.principal.not.allowed";
|
public static final String LOAN_CHARGE_CAN_NOT_BE_ADDED_WITH_PRINCIPAL_CALCULATION_TYPE= "loancharge.with.calculation.type.principal.not.allowed";
|
||||||
@@ -44,6 +48,8 @@ public interface LoanApiConstants {
|
|||||||
public static final String APPROVED_AMOUNT_IS_LESS_THAN_SUM_OF_TRANCHES = "sum.of.multi.disburse.amounts.must.be.equal.to.or.lesser.than.approved.principal";
|
public static final String APPROVED_AMOUNT_IS_LESS_THAN_SUM_OF_TRANCHES = "sum.of.multi.disburse.amounts.must.be.equal.to.or.lesser.than.approved.principal";
|
||||||
public static final String DISBURSEMENT_DATES_NOT_IN_ORDER = "disbursements.should.be.ordered.based.on.their.disbursement.dates";
|
public static final String DISBURSEMENT_DATES_NOT_IN_ORDER = "disbursements.should.be.ordered.based.on.their.disbursement.dates";
|
||||||
public static final String DISBURSEMENT_DATE_BEFORE_ERROR = "disbursement.date.of.tranche.cannot.be.before.expected.disbursement.date";
|
public static final String DISBURSEMENT_DATE_BEFORE_ERROR = "disbursement.date.of.tranche.cannot.be.before.expected.disbursement.date";
|
||||||
|
|
||||||
|
public static final String isFloatingInterestRate = "isFloatingInterestRate";
|
||||||
|
public static final String interestRateDifferential = "interestRateDifferential";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-4
@@ -5,6 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.mifosplatform.portfolio.loanaccount.api;
|
package org.mifosplatform.portfolio.loanaccount.api;
|
||||||
|
|
||||||
|
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.interestType;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -59,6 +61,7 @@ import org.mifosplatform.portfolio.charge.service.ChargeReadPlatformService;
|
|||||||
import org.mifosplatform.portfolio.client.data.ClientData;
|
import org.mifosplatform.portfolio.client.data.ClientData;
|
||||||
import org.mifosplatform.portfolio.collateral.data.CollateralData;
|
import org.mifosplatform.portfolio.collateral.data.CollateralData;
|
||||||
import org.mifosplatform.portfolio.collateral.service.CollateralReadPlatformService;
|
import org.mifosplatform.portfolio.collateral.service.CollateralReadPlatformService;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.InterestRatePeriodData;
|
||||||
import org.mifosplatform.portfolio.fund.data.FundData;
|
import org.mifosplatform.portfolio.fund.data.FundData;
|
||||||
import org.mifosplatform.portfolio.fund.service.FundReadPlatformService;
|
import org.mifosplatform.portfolio.fund.service.FundReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.group.data.GroupGeneralData;
|
import org.mifosplatform.portfolio.group.data.GroupGeneralData;
|
||||||
@@ -85,6 +88,7 @@ import org.mifosplatform.portfolio.loanaccount.service.LoanChargeReadPlatformSer
|
|||||||
import org.mifosplatform.portfolio.loanaccount.service.LoanReadPlatformService;
|
import org.mifosplatform.portfolio.loanaccount.service.LoanReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
|
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
|
||||||
import org.mifosplatform.portfolio.loanproduct.data.TransactionProcessingStrategyData;
|
import org.mifosplatform.portfolio.loanproduct.data.TransactionProcessingStrategyData;
|
||||||
|
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
|
||||||
import org.mifosplatform.portfolio.loanproduct.service.LoanDropdownReadPlatformService;
|
import org.mifosplatform.portfolio.loanproduct.service.LoanDropdownReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.loanproduct.service.LoanProductReadPlatformService;
|
import org.mifosplatform.portfolio.loanproduct.service.LoanProductReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.note.data.NoteData;
|
import org.mifosplatform.portfolio.note.data.NoteData;
|
||||||
@@ -105,7 +109,7 @@ import com.google.gson.JsonElement;
|
|||||||
public class LoansApiResource {
|
public class LoansApiResource {
|
||||||
|
|
||||||
private final Set<String> LOAN_DATA_PARAMETERS = new HashSet<>(Arrays.asList("id", "accountNo", "status", "externalId", "clientId",
|
private final Set<String> LOAN_DATA_PARAMETERS = new HashSet<>(Arrays.asList("id", "accountNo", "status", "externalId", "clientId",
|
||||||
"group", "loanProductId", "loanProductName", "loanProductDescription", "fundId", "fundName", "loanPurposeId",
|
"group", "loanProductId", "loanProductName", "loanProductDescription", "isLoanProductLinkedToFloatingRate", "fundId", "fundName", "loanPurposeId",
|
||||||
"loanPurposeName", "loanOfficerId", "loanOfficerName", "currency", "principal", "totalOverpaid", "inArrearsTolerance",
|
"loanPurposeName", "loanOfficerId", "loanOfficerName", "currency", "principal", "totalOverpaid", "inArrearsTolerance",
|
||||||
"termFrequency", "termPeriodFrequencyType", "numberOfRepayments", "repaymentEvery", "interestRatePerPeriod",
|
"termFrequency", "termPeriodFrequencyType", "numberOfRepayments", "repaymentEvery", "interestRatePerPeriod",
|
||||||
"annualInterestRate", "repaymentFrequencyType", "transactionProcessingStrategyId", "transactionProcessingStrategyName",
|
"annualInterestRate", "repaymentFrequencyType", "transactionProcessingStrategyId", "transactionProcessingStrategyName",
|
||||||
@@ -117,7 +121,7 @@ public class LoansApiResource {
|
|||||||
"repaymentFrequencyDaysOfWeekTypeOptions", "termFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions",
|
"repaymentFrequencyDaysOfWeekTypeOptions", "termFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions",
|
||||||
"repaymentStrategyOptions", "chargeOptions", "loanOfficerOptions", "loanPurposeOptions", "loanCollateralOptions",
|
"repaymentStrategyOptions", "chargeOptions", "loanOfficerOptions", "loanPurposeOptions", "loanCollateralOptions",
|
||||||
"chargeTemplate", "calendarOptions", "syncDisbursementWithMeeting", "loanCounter", "loanProductCounter", "notes",
|
"chargeTemplate", "calendarOptions", "syncDisbursementWithMeeting", "loanCounter", "loanProductCounter", "notes",
|
||||||
"accountLinkingOptions", "linkedAccount"));
|
"accountLinkingOptions", "linkedAccount", "interestRateDifferential", "isFloatingInterestRate", "interestRatesPeriods"));
|
||||||
|
|
||||||
private final Set<String> LOAN_APPROVAL_DATA_PARAMETERS = new HashSet<>(Arrays.asList("approvalDate", "approvalAmount"));
|
private final Set<String> LOAN_APPROVAL_DATA_PARAMETERS = new HashSet<>(Arrays.asList("approvalDate", "approvalAmount"));
|
||||||
private final String resourceNameForPermissions = "LOAN";
|
private final String resourceNameForPermissions = "LOAN";
|
||||||
@@ -354,6 +358,8 @@ public class LoansApiResource {
|
|||||||
compoundingCalendarData);
|
compoundingCalendarData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Collection<InterestRatePeriodData> interestRatesPeriods = this.loanReadPlatformService.retrieveLoanInterestRatePeriodData(loanId);
|
||||||
|
|
||||||
Collection<LoanTransactionData> loanRepayments = null;
|
Collection<LoanTransactionData> loanRepayments = null;
|
||||||
LoanScheduleData repaymentSchedule = null;
|
LoanScheduleData repaymentSchedule = null;
|
||||||
Collection<LoanChargeData> charges = null;
|
Collection<LoanChargeData> charges = null;
|
||||||
@@ -488,7 +494,11 @@ public class LoansApiResource {
|
|||||||
interestRateFrequencyTypeOptions = this.dropdownReadPlatformService.retrieveInterestRateFrequencyTypeOptions();
|
interestRateFrequencyTypeOptions = this.dropdownReadPlatformService.retrieveInterestRateFrequencyTypeOptions();
|
||||||
|
|
||||||
amortizationTypeOptions = this.dropdownReadPlatformService.retrieveLoanAmortizationTypeOptions();
|
amortizationTypeOptions = this.dropdownReadPlatformService.retrieveLoanAmortizationTypeOptions();
|
||||||
interestTypeOptions = this.dropdownReadPlatformService.retrieveLoanInterestTypeOptions();
|
if(product.isLinkedToFloatingInterestRates()){
|
||||||
|
interestTypeOptions = Arrays.asList(interestType(InterestMethod.DECLINING_BALANCE));
|
||||||
|
}else {
|
||||||
|
interestTypeOptions = this.dropdownReadPlatformService.retrieveLoanInterestTypeOptions();
|
||||||
|
}
|
||||||
interestCalculationPeriodTypeOptions = this.dropdownReadPlatformService.retrieveLoanInterestRateCalculatedInPeriodOptions();
|
interestCalculationPeriodTypeOptions = this.dropdownReadPlatformService.retrieveLoanInterestRateCalculatedInPeriodOptions();
|
||||||
|
|
||||||
fundOptions = this.fundReadPlatformService.retrieveAllFunds();
|
fundOptions = this.fundReadPlatformService.retrieveAllFunds();
|
||||||
@@ -537,7 +547,7 @@ public class LoansApiResource {
|
|||||||
null, null, repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
|
null, null, repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
|
||||||
interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers, loanPurposeOptions,
|
interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers, loanPurposeOptions,
|
||||||
loanCollateralOptions, calendarOptions, notes, accountLinkingOptions, linkedAccount, disbursementData, emiAmountVariations,
|
loanCollateralOptions, calendarOptions, notes, accountLinkingOptions, linkedAccount, disbursementData, emiAmountVariations,
|
||||||
overdueCharges, paidInAdvanceTemplate);
|
overdueCharges, paidInAdvanceTemplate, interestRatesPeriods);
|
||||||
|
|
||||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters(),
|
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters(),
|
||||||
mandatoryResponseParameters);
|
mandatoryResponseParameters);
|
||||||
|
|||||||
+86
-42
@@ -27,6 +27,7 @@ import org.mifosplatform.portfolio.account.data.PortfolioAccountData;
|
|||||||
import org.mifosplatform.portfolio.calendar.data.CalendarData;
|
import org.mifosplatform.portfolio.calendar.data.CalendarData;
|
||||||
import org.mifosplatform.portfolio.charge.data.ChargeData;
|
import org.mifosplatform.portfolio.charge.data.ChargeData;
|
||||||
import org.mifosplatform.portfolio.collateral.data.CollateralData;
|
import org.mifosplatform.portfolio.collateral.data.CollateralData;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.InterestRatePeriodData;
|
||||||
import org.mifosplatform.portfolio.fund.data.FundData;
|
import org.mifosplatform.portfolio.fund.data.FundData;
|
||||||
import org.mifosplatform.portfolio.group.data.GroupGeneralData;
|
import org.mifosplatform.portfolio.group.data.GroupGeneralData;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
|
||||||
@@ -64,6 +65,7 @@ public class LoanAccountData {
|
|||||||
private final Long loanProductId;
|
private final Long loanProductId;
|
||||||
private final String loanProductName;
|
private final String loanProductName;
|
||||||
private final String loanProductDescription;
|
private final String loanProductDescription;
|
||||||
|
private final boolean isLoanProductLinkedToFloatingRate;
|
||||||
private final Long fundId;
|
private final Long fundId;
|
||||||
private final String fundName;
|
private final String fundName;
|
||||||
private final Long loanPurposeId;
|
private final Long loanPurposeId;
|
||||||
@@ -88,6 +90,8 @@ public class LoanAccountData {
|
|||||||
private final BigDecimal interestRatePerPeriod;
|
private final BigDecimal interestRatePerPeriod;
|
||||||
private final EnumOptionData interestRateFrequencyType;
|
private final EnumOptionData interestRateFrequencyType;
|
||||||
private final BigDecimal annualInterestRate;
|
private final BigDecimal annualInterestRate;
|
||||||
|
private final boolean isFloatingInterestRate;
|
||||||
|
private final BigDecimal interestRateDifferential;
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
private final EnumOptionData amortizationType;
|
private final EnumOptionData amortizationType;
|
||||||
@@ -182,6 +186,8 @@ public class LoanAccountData {
|
|||||||
|
|
||||||
// Paid In Advance
|
// Paid In Advance
|
||||||
private final PaidInAdvanceData paidInAdvance;
|
private final PaidInAdvanceData paidInAdvance;
|
||||||
|
|
||||||
|
private final Collection<InterestRatePeriodData> interestRatesPeriods;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to produce a {@link LoanAccountData} with only collateral options
|
* Used to produce a {@link LoanAccountData} with only collateral options
|
||||||
@@ -200,6 +206,7 @@ public class LoanAccountData {
|
|||||||
final Long loanProductId = null;
|
final Long loanProductId = null;
|
||||||
final String loanProductName = null;
|
final String loanProductName = null;
|
||||||
final String loanProductDescription = null;
|
final String loanProductDescription = null;
|
||||||
|
final boolean isLoanProductLinkedToFloatingRate = false;
|
||||||
final Long fundId = null;
|
final Long fundId = null;
|
||||||
final String fundName = null;
|
final String fundName = null;
|
||||||
final Long loanPurposeId = null;
|
final Long loanPurposeId = null;
|
||||||
@@ -225,6 +232,8 @@ public class LoanAccountData {
|
|||||||
final EnumOptionData interestRateFrequencyType = null;
|
final EnumOptionData interestRateFrequencyType = null;
|
||||||
final BigDecimal annualInterestRate = null;
|
final BigDecimal annualInterestRate = null;
|
||||||
final EnumOptionData interestType = null;
|
final EnumOptionData interestType = null;
|
||||||
|
final boolean isFloatingInterestRate = false;
|
||||||
|
final BigDecimal interestRateDifferential = null;
|
||||||
final EnumOptionData interestCalculationPeriodType = null;
|
final EnumOptionData interestCalculationPeriodType = null;
|
||||||
final LocalDate expectedFirstRepaymentOnDate = null;
|
final LocalDate expectedFirstRepaymentOnDate = null;
|
||||||
final Integer graceOnPrincipalPayment = null;
|
final Integer graceOnPrincipalPayment = null;
|
||||||
@@ -283,13 +292,15 @@ public class LoanAccountData {
|
|||||||
final LoanScheduleData originalSchedule = null;
|
final LoanScheduleData originalSchedule = null;
|
||||||
final Boolean createStandingInstructionAtDisbursement = null;
|
final Boolean createStandingInstructionAtDisbursement = null;
|
||||||
final PaidInAdvanceData paidInAdvance = null;
|
final PaidInAdvanceData paidInAdvance = null;
|
||||||
|
final Collection<InterestRatePeriodData> interestRatesPeriods = null;
|
||||||
|
|
||||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
||||||
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
||||||
currencyData, proposedPrincipal, principal, principal, totalOverpaid, inArrearsTolerance, termFrequency,
|
currencyData, proposedPrincipal, principal, principal, totalOverpaid, inArrearsTolerance, termFrequency,
|
||||||
termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType,
|
termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType,
|
||||||
repaymentFrequencyDayOfWeekType, transactionProcessingStrategyId, transactionProcessingStrategyName, amortizationType,
|
repaymentFrequencyDayOfWeekType, transactionProcessingStrategyId, transactionProcessingStrategyName, amortizationType,
|
||||||
interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, interestCalculationPeriodType,
|
interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, isFloatingInterestRate,
|
||||||
|
interestRateDifferential, interestCalculationPeriodType,
|
||||||
expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged,
|
expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged,
|
||||||
interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions, charges,
|
interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions, charges,
|
||||||
collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions,
|
collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions,
|
||||||
@@ -300,7 +311,7 @@ public class LoanAccountData {
|
|||||||
disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, maxOutstandingLoanBalance,
|
disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, maxOutstandingLoanBalance,
|
||||||
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType,
|
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType,
|
||||||
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule,
|
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule,
|
||||||
createStandingInstructionAtDisbursement, paidInAdvance);
|
createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,6 +331,7 @@ public class LoanAccountData {
|
|||||||
final Long loanProductId = null;
|
final Long loanProductId = null;
|
||||||
final String loanProductName = null;
|
final String loanProductName = null;
|
||||||
final String loanProductDescription = null;
|
final String loanProductDescription = null;
|
||||||
|
final boolean isLoanProductLinkedToFloatingRate = false;
|
||||||
final Long fundId = null;
|
final Long fundId = null;
|
||||||
final String fundName = null;
|
final String fundName = null;
|
||||||
final Long loanPurposeId = null;
|
final Long loanPurposeId = null;
|
||||||
@@ -345,6 +357,8 @@ public class LoanAccountData {
|
|||||||
final EnumOptionData interestRateFrequencyType = null;
|
final EnumOptionData interestRateFrequencyType = null;
|
||||||
final BigDecimal annualInterestRate = null;
|
final BigDecimal annualInterestRate = null;
|
||||||
final EnumOptionData interestType = null;
|
final EnumOptionData interestType = null;
|
||||||
|
final boolean isFloatingInterestRate = false;
|
||||||
|
final BigDecimal interestRateDifferential = null;
|
||||||
final EnumOptionData interestCalculationPeriodType = null;
|
final EnumOptionData interestCalculationPeriodType = null;
|
||||||
final LocalDate expectedFirstRepaymentOnDate = null;
|
final LocalDate expectedFirstRepaymentOnDate = null;
|
||||||
final Integer graceOnPrincipalPayment = null;
|
final Integer graceOnPrincipalPayment = null;
|
||||||
@@ -404,13 +418,15 @@ public class LoanAccountData {
|
|||||||
final LoanScheduleData originalSchedule = null;
|
final LoanScheduleData originalSchedule = null;
|
||||||
final Boolean createStandingInstructionAtDisbursement = null;
|
final Boolean createStandingInstructionAtDisbursement = null;
|
||||||
final PaidInAdvanceData paidInAdvance = null;
|
final PaidInAdvanceData paidInAdvance = null;
|
||||||
|
final Collection<InterestRatePeriodData> interestRatesPeriods = null;
|
||||||
|
|
||||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
||||||
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
||||||
currencyData, proposedPrincipal, principal, principal, totalOverpaid, inArrearsTolerance, termFrequency,
|
currencyData, proposedPrincipal, principal, principal, totalOverpaid, inArrearsTolerance, termFrequency,
|
||||||
termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType,
|
termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType,
|
||||||
repaymentFrequencyDayOfWeekType, transactionProcessingStrategyId, transactionProcessingStrategyName, amortizationType,
|
repaymentFrequencyDayOfWeekType, transactionProcessingStrategyId, transactionProcessingStrategyName, amortizationType,
|
||||||
interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, interestCalculationPeriodType,
|
interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType,
|
||||||
|
isFloatingInterestRate, interestRateDifferential, interestCalculationPeriodType,
|
||||||
expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged,
|
expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged,
|
||||||
interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions, charges,
|
interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions, charges,
|
||||||
collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions,
|
collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions,
|
||||||
@@ -421,20 +437,21 @@ public class LoanAccountData {
|
|||||||
disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, maxOutstandingLoanBalance,
|
disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, maxOutstandingLoanBalance,
|
||||||
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType,
|
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType,
|
||||||
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule,
|
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule,
|
||||||
createStandingInstructionAtDisbursement, paidInAdvance);
|
createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData populateClientDefaults(final LoanAccountData acc, final LoanAccountData clientAcc) {
|
public static LoanAccountData populateClientDefaults(final LoanAccountData acc, final LoanAccountData clientAcc) {
|
||||||
|
|
||||||
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, clientAcc.clientId, clientAcc.clientName,
|
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, clientAcc.clientId, clientAcc.clientName,
|
||||||
clientAcc.clientOfficeId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription,
|
clientAcc.clientOfficeId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate,
|
||||||
acc.fundId, acc.fundName, acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency,
|
acc.fundId, acc.fundName, acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency,
|
||||||
acc.proposedPrincipal, acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency,
|
acc.proposedPrincipal, acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency,
|
||||||
acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType,
|
acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType,
|
||||||
acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId,
|
acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId,
|
||||||
acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType,
|
acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType,
|
||||||
acc.annualInterestRate, acc.interestType, acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate,
|
acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential,
|
||||||
|
acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate,
|
||||||
acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate,
|
acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate,
|
||||||
clientAcc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges,
|
clientAcc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges,
|
||||||
acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions,
|
acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions,
|
||||||
@@ -447,7 +464,7 @@ public class LoanAccountData {
|
|||||||
acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
|
acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
|
||||||
acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
||||||
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
||||||
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance);
|
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -467,6 +484,7 @@ public class LoanAccountData {
|
|||||||
final Long loanProductId = null;
|
final Long loanProductId = null;
|
||||||
final String loanProductName = null;
|
final String loanProductName = null;
|
||||||
final String loanProductDescription = null;
|
final String loanProductDescription = null;
|
||||||
|
final boolean isLoanProductLinkedToFloatingRate = false;
|
||||||
final Long fundId = null;
|
final Long fundId = null;
|
||||||
final String fundName = null;
|
final String fundName = null;
|
||||||
final Long loanPurposeId = null;
|
final Long loanPurposeId = null;
|
||||||
@@ -492,6 +510,8 @@ public class LoanAccountData {
|
|||||||
final EnumOptionData interestRateFrequencyType = null;
|
final EnumOptionData interestRateFrequencyType = null;
|
||||||
final BigDecimal annualInterestRate = null;
|
final BigDecimal annualInterestRate = null;
|
||||||
final EnumOptionData interestType = null;
|
final EnumOptionData interestType = null;
|
||||||
|
final boolean isFloatingInterestRate = false;
|
||||||
|
final BigDecimal interestRateDifferential = null;
|
||||||
final EnumOptionData interestCalculationPeriodType = null;
|
final EnumOptionData interestCalculationPeriodType = null;
|
||||||
final LocalDate expectedFirstRepaymentOnDate = null;
|
final LocalDate expectedFirstRepaymentOnDate = null;
|
||||||
final Integer graceOnPrincipalPayment = null;
|
final Integer graceOnPrincipalPayment = null;
|
||||||
@@ -551,13 +571,15 @@ public class LoanAccountData {
|
|||||||
final LoanScheduleData originalSchedule = null;
|
final LoanScheduleData originalSchedule = null;
|
||||||
final Boolean createStandingInstructionAtDisbursement = null;
|
final Boolean createStandingInstructionAtDisbursement = null;
|
||||||
final PaidInAdvanceData paidInAdvance = null;
|
final PaidInAdvanceData paidInAdvance = null;
|
||||||
|
final Collection<InterestRatePeriodData> interestRatesPeriods = null;
|
||||||
|
|
||||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
||||||
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
||||||
currencyData, proposedPrincipal, principal, principal, totalOverpaid, inArrearsTolerance, termFrequency,
|
currencyData, proposedPrincipal, principal, principal, totalOverpaid, inArrearsTolerance, termFrequency,
|
||||||
termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType,
|
termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType,
|
||||||
repaymentFrequencyDayOfWeekType, transactionProcessingStrategyId, transactionProcessingStrategyName, amortizationType,
|
repaymentFrequencyDayOfWeekType, transactionProcessingStrategyId, transactionProcessingStrategyName, amortizationType,
|
||||||
interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, interestCalculationPeriodType,
|
interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType,
|
||||||
|
isFloatingInterestRate, interestRateDifferential, interestCalculationPeriodType,
|
||||||
expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged,
|
expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged,
|
||||||
interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions, charges,
|
interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions, charges,
|
||||||
collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions,
|
collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions,
|
||||||
@@ -568,20 +590,21 @@ public class LoanAccountData {
|
|||||||
disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, maxOutstandingBalance,
|
disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, maxOutstandingBalance,
|
||||||
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType,
|
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType,
|
||||||
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule,
|
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule,
|
||||||
createStandingInstructionAtDisbursement, paidInAdvance);
|
createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData populateGroupDefaults(final LoanAccountData acc, final LoanAccountData groupAcc) {
|
public static LoanAccountData populateGroupDefaults(final LoanAccountData acc, final LoanAccountData groupAcc) {
|
||||||
|
|
||||||
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
|
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
|
||||||
groupAcc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.fundId, acc.fundName,
|
groupAcc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName,
|
||||||
acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal,
|
acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal,
|
||||||
acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency,
|
acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency,
|
||||||
acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType,
|
acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType,
|
||||||
acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId,
|
acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId,
|
||||||
acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType,
|
acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType,
|
||||||
acc.annualInterestRate, acc.interestType, acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate,
|
acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential,
|
||||||
|
acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate,
|
||||||
acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate,
|
acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate,
|
||||||
groupAcc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges,
|
groupAcc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges,
|
||||||
acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions,
|
acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions,
|
||||||
@@ -594,7 +617,7 @@ public class LoanAccountData {
|
|||||||
acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
|
acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
|
||||||
acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
||||||
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
||||||
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance);
|
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -712,14 +735,16 @@ public class LoanAccountData {
|
|||||||
final LoanScheduleData originalSchedule = null;
|
final LoanScheduleData originalSchedule = null;
|
||||||
final Boolean createStandingInstructionAtDisbursement = null;
|
final Boolean createStandingInstructionAtDisbursement = null;
|
||||||
final PaidInAdvanceData paidInAdvance = null;
|
final PaidInAdvanceData paidInAdvance = null;
|
||||||
|
final Collection<InterestRatePeriodData> interestRatesPeriods = null;
|
||||||
|
|
||||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType,
|
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType,
|
||||||
product.getId(), product.getName(), product.getDescription(), product.getFundId(), product.getFundName(), loanPurposeId,
|
product.getId(), product.getName(), product.getDescription(), product.isLinkedToFloatingInterestRates(), product.getFundId(), product.getFundName(), loanPurposeId,
|
||||||
loanPurposeName, loanOfficerId, loanOfficerName, product.getCurrency(), proposedPrincipal, principal, principal,
|
loanPurposeName, loanOfficerId, loanOfficerName, product.getCurrency(), proposedPrincipal, principal, principal,
|
||||||
totalOverpaid, product.getInArrearsTolerance(), termFrequency, termPeriodFrequencyType, numberOfRepayments,
|
totalOverpaid, product.getInArrearsTolerance(), termFrequency, termPeriodFrequencyType, numberOfRepayments,
|
||||||
product.getRepaymentEvery(), product.getRepaymentFrequencyType(), null, null, product.getTransactionProcessingStrategyId(),
|
product.getRepaymentEvery(), product.getRepaymentFrequencyType(), null, null, product.getTransactionProcessingStrategyId(),
|
||||||
transactionProcessingStrategyName, product.getAmortizationType(), interestRatePerPeriod,
|
transactionProcessingStrategyName, product.getAmortizationType(), interestRatePerPeriod,
|
||||||
product.getInterestRateFrequencyType(), product.getAnnualInterestRate(), product.getInterestType(),
|
product.getInterestRateFrequencyType(), product.getAnnualInterestRate(), product.getInterestType(),
|
||||||
|
product.isFloatingInterestRateCalculationAllowed(), product.getDefaultDifferentialLendingRate(),
|
||||||
product.getInterestCalculationPeriodType(), expectedFirstRepaymentOnDate, product.getGraceOnPrincipalPayment(),
|
product.getInterestCalculationPeriodType(), expectedFirstRepaymentOnDate, product.getGraceOnPrincipalPayment(),
|
||||||
product.getGraceOnInterestPayment(), product.getGraceOnInterestCharged(), interestChargedFromDate, timeline, summary,
|
product.getGraceOnInterestPayment(), product.getGraceOnInterestCharged(), interestChargedFromDate, timeline, summary,
|
||||||
feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, guarantors, calendarData,
|
feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, guarantors, calendarData,
|
||||||
@@ -732,7 +757,7 @@ public class LoanAccountData {
|
|||||||
product.getOutstandingLoanBalance(), emiAmountVariations, memberVariations, product, inArrears,
|
product.getOutstandingLoanBalance(), emiAmountVariations, memberVariations, product, inArrears,
|
||||||
product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), isNPA, product.getDaysInMonthType(),
|
product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), isNPA, product.getDaysInMonthType(),
|
||||||
product.getDaysInYearType(), product.isInterestRecalculationEnabled(), product.toLoanInterestRecalculationData(),
|
product.getDaysInYearType(), product.isInterestRecalculationEnabled(), product.toLoanInterestRecalculationData(),
|
||||||
originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance);
|
originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData populateLoanProductDefaults(final LoanAccountData acc, final LoanProductData product) {
|
public static LoanAccountData populateLoanProductDefaults(final LoanAccountData acc, final LoanProductData product) {
|
||||||
@@ -769,13 +794,14 @@ public class LoanAccountData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
|
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
|
||||||
acc.group, acc.loanType, product.getId(), product.getName(), product.getDescription(), product.getFundId(),
|
acc.group, acc.loanType, product.getId(), product.getName(), product.getDescription(), product.isLinkedToFloatingInterestRates(), product.getFundId(),
|
||||||
product.getFundName(), acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName,
|
product.getFundName(), acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName,
|
||||||
product.getCurrency(), product.getPrincipal(), product.getPrincipal(), product.getPrincipal(), acc.totalOverpaid,
|
product.getCurrency(), product.getPrincipal(), product.getPrincipal(), product.getPrincipal(), acc.totalOverpaid,
|
||||||
product.getInArrearsTolerance(), termFrequency, termPeriodFrequencyType, product.getNumberOfRepayments(),
|
product.getInArrearsTolerance(), termFrequency, termPeriodFrequencyType, product.getNumberOfRepayments(),
|
||||||
product.getRepaymentEvery(), product.getRepaymentFrequencyType(), null, null, product.getTransactionProcessingStrategyId(),
|
product.getRepaymentEvery(), product.getRepaymentFrequencyType(), null, null, product.getTransactionProcessingStrategyId(),
|
||||||
product.getTransactionProcessingStrategyName(), product.getAmortizationType(), product.getInterestRatePerPeriod(),
|
product.getTransactionProcessingStrategyName(), product.getAmortizationType(), product.getInterestRatePerPeriod(),
|
||||||
product.getInterestRateFrequencyType(), product.getAnnualInterestRate(), product.getInterestType(),
|
product.getInterestRateFrequencyType(), product.getAnnualInterestRate(), product.getInterestType(),
|
||||||
|
product.isFloatingInterestRateCalculationAllowed(), product.getDefaultDifferentialLendingRate(),
|
||||||
product.getInterestCalculationPeriodType(), acc.expectedFirstRepaymentOnDate, product.getGraceOnPrincipalPayment(),
|
product.getInterestCalculationPeriodType(), acc.expectedFirstRepaymentOnDate, product.getGraceOnPrincipalPayment(),
|
||||||
product.getGraceOnInterestPayment(), product.getGraceOnInterestCharged(), acc.interestChargedFromDate, acc.timeline,
|
product.getGraceOnInterestPayment(), product.getGraceOnInterestCharged(), acc.interestChargedFromDate, acc.timeline,
|
||||||
acc.summary, acc.feeChargesAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, guarantors,
|
acc.summary, acc.feeChargesAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, guarantors,
|
||||||
@@ -787,7 +813,8 @@ public class LoanAccountData {
|
|||||||
product.canDefineInstallmentAmount(), acc.fixedEmiAmount, product.getOutstandingLoanBalance(), acc.emiAmountVariations,
|
product.canDefineInstallmentAmount(), acc.fixedEmiAmount, product.getOutstandingLoanBalance(), acc.emiAmountVariations,
|
||||||
acc.memberVariations, product, acc.inArrears, product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), acc.isNPA,
|
acc.memberVariations, product, acc.inArrears, product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), acc.isNPA,
|
||||||
product.getDaysInMonthType(), product.getDaysInYearType(), product.isInterestRecalculationEnabled(),
|
product.getDaysInMonthType(), product.getDaysInYearType(), product.isInterestRecalculationEnabled(),
|
||||||
product.toLoanInterestRecalculationData(), acc.originalSchedule, acc.createStandingInstructionAtDisbursement, paidInAdvance);
|
product.toLoanInterestRecalculationData(), acc.originalSchedule, acc.createStandingInstructionAtDisbursement,
|
||||||
|
paidInAdvance, acc.interestRatesPeriods);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -798,6 +825,7 @@ public class LoanAccountData {
|
|||||||
public static LoanAccountData basicLoanDetails(final Long id, final String accountNo, final LoanStatusEnumData status,
|
public static LoanAccountData basicLoanDetails(final Long id, final String accountNo, final LoanStatusEnumData status,
|
||||||
final String externalId, final Long clientId, final String clientName, final Long clientOfficeId, final GroupGeneralData group,
|
final String externalId, final Long clientId, final String clientName, final Long clientOfficeId, final GroupGeneralData group,
|
||||||
final EnumOptionData loanType, final Long loanProductId, final String loanProductName, final String loanProductDescription,
|
final EnumOptionData loanType, final Long loanProductId, final String loanProductName, final String loanProductDescription,
|
||||||
|
final boolean isLoanProductLinkedToFloatingRate,
|
||||||
final Long fundId, final String fundName, final Long loanPurposeId, final String loanPurposeName, final Long loanOfficerId,
|
final Long fundId, final String fundName, final Long loanPurposeId, final String loanPurposeName, final Long loanOfficerId,
|
||||||
final String loanOfficerName, final CurrencyData currencyData, final BigDecimal proposedPrincipal, final BigDecimal principal,
|
final String loanOfficerName, final CurrencyData currencyData, final BigDecimal proposedPrincipal, final BigDecimal principal,
|
||||||
final BigDecimal approvedPrincipal, final BigDecimal totalOverpaid, final BigDecimal inArrearsTolerance,
|
final BigDecimal approvedPrincipal, final BigDecimal totalOverpaid, final BigDecimal inArrearsTolerance,
|
||||||
@@ -805,7 +833,8 @@ public class LoanAccountData {
|
|||||||
final Integer repaymentEvery, final EnumOptionData repaymentFrequencyType, EnumOptionData repaymentFrequencyNthDayType,
|
final Integer repaymentEvery, final EnumOptionData repaymentFrequencyType, EnumOptionData repaymentFrequencyNthDayType,
|
||||||
EnumOptionData repaymentFrequencyDayOfWeekType, final Long transactionStrategyId, final String transactionStrategyName,
|
EnumOptionData repaymentFrequencyDayOfWeekType, final Long transactionStrategyId, final String transactionStrategyName,
|
||||||
final EnumOptionData amortizationType, final BigDecimal interestRatePerPeriod, final EnumOptionData interestRateFrequencyType,
|
final EnumOptionData amortizationType, final BigDecimal interestRatePerPeriod, final EnumOptionData interestRateFrequencyType,
|
||||||
final BigDecimal annualInterestRate, final EnumOptionData interestType, final EnumOptionData interestCalculationPeriodType,
|
final BigDecimal annualInterestRate, final EnumOptionData interestType, final boolean isFloatingInterestRate,
|
||||||
|
final BigDecimal interestRateDifferential, final EnumOptionData interestCalculationPeriodType,
|
||||||
final LocalDate expectedFirstRepaymentOnDate, final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment,
|
final LocalDate expectedFirstRepaymentOnDate, final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment,
|
||||||
final Integer graceOnInterestCharged, final LocalDate interestChargedFromDate, final LoanApplicationTimelineData timeline,
|
final Integer graceOnInterestCharged, final LocalDate interestChargedFromDate, final LoanApplicationTimelineData timeline,
|
||||||
final LoanSummaryData loanSummary, final BigDecimal feeChargesDueAtDisbursementCharged,
|
final LoanSummaryData loanSummary, final BigDecimal feeChargesDueAtDisbursementCharged,
|
||||||
@@ -848,13 +877,15 @@ public class LoanAccountData {
|
|||||||
final Collection<ChargeData> overdueCharges = null;
|
final Collection<ChargeData> overdueCharges = null;
|
||||||
final LoanScheduleData originalSchedule = null;
|
final LoanScheduleData originalSchedule = null;
|
||||||
final PaidInAdvanceData paidInAdvance = null;
|
final PaidInAdvanceData paidInAdvance = null;
|
||||||
|
final Collection<InterestRatePeriodData> interestRatesPeriods = null;
|
||||||
|
|
||||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
||||||
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
||||||
currencyData, proposedPrincipal, principal, approvedPrincipal, totalOverpaid, inArrearsTolerance, termFrequency,
|
currencyData, proposedPrincipal, principal, approvedPrincipal, totalOverpaid, inArrearsTolerance, termFrequency,
|
||||||
termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType,
|
termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType,
|
||||||
repaymentFrequencyDayOfWeekType, transactionStrategyId, transactionStrategyName, amortizationType, interestRatePerPeriod,
|
repaymentFrequencyDayOfWeekType, transactionStrategyId, transactionStrategyName, amortizationType, interestRatePerPeriod,
|
||||||
interestRateFrequencyType, annualInterestRate, interestType, interestCalculationPeriodType, expectedFirstRepaymentOnDate,
|
interestRateFrequencyType, annualInterestRate, interestType, isFloatingInterestRate, interestRateDifferential,
|
||||||
|
interestCalculationPeriodType, expectedFirstRepaymentOnDate,
|
||||||
graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, timeline, loanSummary,
|
graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, timeline, loanSummary,
|
||||||
feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, guarantors, calendarData,
|
feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, guarantors, calendarData,
|
||||||
productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions,
|
productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions,
|
||||||
@@ -865,7 +896,7 @@ public class LoanAccountData {
|
|||||||
disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmont, outstandingLoanBalance,
|
disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmont, outstandingLoanBalance,
|
||||||
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType,
|
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType,
|
||||||
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule,
|
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule,
|
||||||
createStandingInstructionAtDisbursement, paidInAdvance);
|
createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -888,20 +919,21 @@ public class LoanAccountData {
|
|||||||
final Collection<NoteData> notes, final Collection<PortfolioAccountData> accountLinkingOptions,
|
final Collection<NoteData> notes, final Collection<PortfolioAccountData> accountLinkingOptions,
|
||||||
final PortfolioAccountData linkedAccount, final Collection<DisbursementData> disbursementDetails,
|
final PortfolioAccountData linkedAccount, final Collection<DisbursementData> disbursementDetails,
|
||||||
final Collection<LoanTermVariationsData> emiAmountVariations, final Collection<ChargeData> overdueCharges,
|
final Collection<LoanTermVariationsData> emiAmountVariations, final Collection<ChargeData> overdueCharges,
|
||||||
final PaidInAdvanceData paidInAdvance) {
|
final PaidInAdvanceData paidInAdvance, Collection<InterestRatePeriodData> interestRatesPeriods) {
|
||||||
LoanProductConfigurableAttributes loanProductConfigurableAttributes = null;
|
LoanProductConfigurableAttributes loanProductConfigurableAttributes = null;
|
||||||
if (acc.product != null) {
|
if (acc.product != null) {
|
||||||
loanProductConfigurableAttributes = acc.product.getloanProductConfigurableAttributes();
|
loanProductConfigurableAttributes = acc.product.getloanProductConfigurableAttributes();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
|
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
|
||||||
acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.fundId, acc.fundName,
|
acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName,
|
||||||
acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal,
|
acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal,
|
||||||
acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency,
|
acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency,
|
||||||
acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType,
|
acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType,
|
||||||
acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId,
|
acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId,
|
||||||
acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType,
|
acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType,
|
||||||
acc.annualInterestRate, acc.interestType, acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate,
|
acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential,
|
||||||
|
acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate,
|
||||||
acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate,
|
acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate,
|
||||||
acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral,
|
acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral,
|
||||||
guarantors, calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions,
|
guarantors, calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions,
|
||||||
@@ -913,7 +945,7 @@ public class LoanAccountData {
|
|||||||
acc.maxOutstandingLoanBalance, emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
|
acc.maxOutstandingLoanBalance, emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
|
||||||
acc.graceOnArrearsAgeing, overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
acc.graceOnArrearsAgeing, overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
||||||
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
||||||
acc.createStandingInstructionAtDisbursement, paidInAdvance);
|
acc.createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData associationsAndTemplate(final LoanAccountData acc, final Collection<LoanProductData> productOptions,
|
public static LoanAccountData associationsAndTemplate(final LoanAccountData acc, final Collection<LoanProductData> productOptions,
|
||||||
@@ -925,18 +957,19 @@ public class LoanAccountData {
|
|||||||
acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions,
|
acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions,
|
||||||
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
|
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
|
||||||
allowedLoanOfficers, acc.loanPurposeOptions, acc.loanCollateralOptions, calendarOptions, acc.notes, accountLinkingOptions,
|
allowedLoanOfficers, acc.loanPurposeOptions, acc.loanCollateralOptions, calendarOptions, acc.notes, accountLinkingOptions,
|
||||||
acc.linkedAccount, acc.disbursementDetails, acc.emiAmountVariations, acc.overdueCharges, acc.paidInAdvance);
|
acc.linkedAccount, acc.disbursementDetails, acc.emiAmountVariations, acc.overdueCharges, acc.paidInAdvance, acc.interestRatesPeriods);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData associateGroup(final LoanAccountData acc, final GroupGeneralData group) {
|
public static LoanAccountData associateGroup(final LoanAccountData acc, final GroupGeneralData group) {
|
||||||
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
|
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
|
||||||
group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.fundId, acc.fundName,
|
group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName,
|
||||||
acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal,
|
acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal,
|
||||||
acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency,
|
acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency,
|
||||||
acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType,
|
acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType,
|
||||||
acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId,
|
acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId,
|
||||||
acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType,
|
acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType,
|
||||||
acc.annualInterestRate, acc.interestType, acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate,
|
acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential,
|
||||||
|
acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate,
|
||||||
acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate,
|
acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate,
|
||||||
acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges,
|
acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges,
|
||||||
acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions,
|
acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions,
|
||||||
@@ -949,7 +982,7 @@ public class LoanAccountData {
|
|||||||
acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
|
acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
|
||||||
acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
||||||
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
||||||
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance);
|
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData associateMemberVariations(final LoanAccountData acc, final Map<Long, Integer> memberLoanCycle) {
|
public static LoanAccountData associateMemberVariations(final LoanAccountData acc, final Map<Long, Integer> memberLoanCycle) {
|
||||||
@@ -991,13 +1024,14 @@ public class LoanAccountData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
|
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
|
||||||
acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.fundId, acc.fundName,
|
acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName,
|
||||||
acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal,
|
acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal,
|
||||||
acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency,
|
acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency,
|
||||||
acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType,
|
acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType,
|
||||||
acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId,
|
acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId,
|
||||||
acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType,
|
acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType,
|
||||||
acc.annualInterestRate, acc.interestType, acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate,
|
acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential,
|
||||||
|
acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate,
|
||||||
acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate,
|
acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate,
|
||||||
acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges,
|
acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges,
|
||||||
acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions,
|
acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions,
|
||||||
@@ -1010,7 +1044,7 @@ public class LoanAccountData {
|
|||||||
acc.maxOutstandingLoanBalance, acc.emiAmountVariations, memberVariations, acc.product, acc.inArrears,
|
acc.maxOutstandingLoanBalance, acc.emiAmountVariations, memberVariations, acc.product, acc.inArrears,
|
||||||
acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
||||||
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
||||||
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance);
|
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1020,13 +1054,14 @@ public class LoanAccountData {
|
|||||||
final LoanInterestRecalculationData interestRecalculationData = LoanInterestRecalculationData.withCalendarData(
|
final LoanInterestRecalculationData interestRecalculationData = LoanInterestRecalculationData.withCalendarData(
|
||||||
acc.interestRecalculationData, calendarData, compoundingCalendarData);
|
acc.interestRecalculationData, calendarData, compoundingCalendarData);
|
||||||
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
|
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
|
||||||
acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.fundId, acc.fundName,
|
acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName,
|
||||||
acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal,
|
acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal,
|
||||||
acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency,
|
acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency,
|
||||||
acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType,
|
acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType,
|
||||||
acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId,
|
acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId,
|
||||||
acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType,
|
acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType,
|
||||||
acc.annualInterestRate, acc.interestType, acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate,
|
acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential,
|
||||||
|
acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate,
|
||||||
acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate,
|
acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate,
|
||||||
acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges,
|
acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges,
|
||||||
acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions,
|
acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions,
|
||||||
@@ -1039,19 +1074,20 @@ public class LoanAccountData {
|
|||||||
acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
|
acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
|
||||||
acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
||||||
acc.isInterestRecalculationEnabled, interestRecalculationData, acc.originalSchedule,
|
acc.isInterestRecalculationEnabled, interestRecalculationData, acc.originalSchedule,
|
||||||
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance);
|
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData withOriginalSchedule(final LoanAccountData acc, final LoanScheduleData originalSchedule) {
|
public static LoanAccountData withOriginalSchedule(final LoanAccountData acc, final LoanScheduleData originalSchedule) {
|
||||||
|
|
||||||
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
|
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
|
||||||
acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.fundId, acc.fundName,
|
acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName,
|
||||||
acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal,
|
acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal,
|
||||||
acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency,
|
acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency,
|
||||||
acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType,
|
acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType,
|
||||||
acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId,
|
acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId,
|
||||||
acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType,
|
acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType,
|
||||||
acc.annualInterestRate, acc.interestType, acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate,
|
acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential,
|
||||||
|
acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate,
|
||||||
acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate,
|
acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate,
|
||||||
acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges,
|
acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges,
|
||||||
acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions,
|
acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions,
|
||||||
@@ -1064,7 +1100,7 @@ public class LoanAccountData {
|
|||||||
acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
|
acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
|
||||||
acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
||||||
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, originalSchedule,
|
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, originalSchedule,
|
||||||
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance);
|
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoanAccountData(
|
private LoanAccountData(
|
||||||
@@ -1080,6 +1116,7 @@ public class LoanAccountData {
|
|||||||
final Long loanProductId,
|
final Long loanProductId,
|
||||||
final String loanProductName,
|
final String loanProductName,
|
||||||
final String loanProductDescription, //
|
final String loanProductDescription, //
|
||||||
|
final boolean isLoanProductLinkedToFloatingRate,
|
||||||
final Long fundId,
|
final Long fundId,
|
||||||
final String fundName,
|
final String fundName,
|
||||||
final Long loanPurposeId,
|
final Long loanPurposeId,
|
||||||
@@ -1100,7 +1137,8 @@ public class LoanAccountData {
|
|||||||
final EnumOptionData repaymentFrequencyNthDayType, final EnumOptionData repaymentFrequencyDayOfWeekType,
|
final EnumOptionData repaymentFrequencyNthDayType, final EnumOptionData repaymentFrequencyDayOfWeekType,
|
||||||
final Long transactionProcessingStrategyId, final String transactionProcessingStrategyName,
|
final Long transactionProcessingStrategyId, final String transactionProcessingStrategyName,
|
||||||
final EnumOptionData amortizationType, final BigDecimal interestRatePerPeriod, final EnumOptionData interestRateFrequencyType,
|
final EnumOptionData amortizationType, final BigDecimal interestRatePerPeriod, final EnumOptionData interestRateFrequencyType,
|
||||||
final BigDecimal annualInterestRate, final EnumOptionData interestType, final EnumOptionData interestCalculationPeriodType,
|
final BigDecimal annualInterestRate, final EnumOptionData interestType, final boolean isFloatingInterestRate,
|
||||||
|
final BigDecimal interestRateDifferential, final EnumOptionData interestCalculationPeriodType,
|
||||||
final LocalDate expectedFirstRepaymentOnDate, final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment,
|
final LocalDate expectedFirstRepaymentOnDate, final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment,
|
||||||
final Integer graceOnInterestCharged, final LocalDate interestChargedFromDate, final LoanApplicationTimelineData timeline,
|
final Integer graceOnInterestCharged, final LocalDate interestChargedFromDate, final LoanApplicationTimelineData timeline,
|
||||||
final LoanSummaryData summary, final BigDecimal feeChargesDueAtDisbursementCharged, final LoanScheduleData repaymentSchedule,
|
final LoanSummaryData summary, final BigDecimal feeChargesDueAtDisbursementCharged, final LoanScheduleData repaymentSchedule,
|
||||||
@@ -1125,7 +1163,8 @@ public class LoanAccountData {
|
|||||||
final Integer graceOnArrearsAgeing, final Collection<ChargeData> overdueCharges, final Boolean isNPA,
|
final Integer graceOnArrearsAgeing, final Collection<ChargeData> overdueCharges, final Boolean isNPA,
|
||||||
final EnumOptionData daysInMonthType, final EnumOptionData daysInYearType, final boolean isInterestRecalculationEnabled,
|
final EnumOptionData daysInMonthType, final EnumOptionData daysInYearType, final boolean isInterestRecalculationEnabled,
|
||||||
final LoanInterestRecalculationData interestRecalculationData, final LoanScheduleData originalSchedule,
|
final LoanInterestRecalculationData interestRecalculationData, final LoanScheduleData originalSchedule,
|
||||||
final Boolean createStandingInstructionAtDisbursement, final PaidInAdvanceData paidInAdvance) {
|
final Boolean createStandingInstructionAtDisbursement, final PaidInAdvanceData paidInAdvance,
|
||||||
|
final Collection<InterestRatePeriodData> interestRatesPeriods) {
|
||||||
|
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.accountNo = accountNo;
|
this.accountNo = accountNo;
|
||||||
@@ -1139,6 +1178,7 @@ public class LoanAccountData {
|
|||||||
this.loanProductId = loanProductId;
|
this.loanProductId = loanProductId;
|
||||||
this.loanProductName = loanProductName;
|
this.loanProductName = loanProductName;
|
||||||
this.loanProductDescription = loanProductDescription;
|
this.loanProductDescription = loanProductDescription;
|
||||||
|
this.isLoanProductLinkedToFloatingRate = isLoanProductLinkedToFloatingRate;
|
||||||
this.fundId = fundId;
|
this.fundId = fundId;
|
||||||
this.fundName = fundName;
|
this.fundName = fundName;
|
||||||
this.loanPurposeId = loanPurposeId;
|
this.loanPurposeId = loanPurposeId;
|
||||||
@@ -1165,6 +1205,8 @@ public class LoanAccountData {
|
|||||||
this.interestRateFrequencyType = interestRateFrequencyType;
|
this.interestRateFrequencyType = interestRateFrequencyType;
|
||||||
this.annualInterestRate = annualInterestRate;
|
this.annualInterestRate = annualInterestRate;
|
||||||
this.interestType = interestType;
|
this.interestType = interestType;
|
||||||
|
this.isFloatingInterestRate = isFloatingInterestRate;
|
||||||
|
this.interestRateDifferential = interestRateDifferential;
|
||||||
this.interestCalculationPeriodType = interestCalculationPeriodType;
|
this.interestCalculationPeriodType = interestCalculationPeriodType;
|
||||||
this.expectedFirstRepaymentOnDate = expectedFirstRepaymentOnDate;
|
this.expectedFirstRepaymentOnDate = expectedFirstRepaymentOnDate;
|
||||||
this.graceOnPrincipalPayment = graceOnPrincipalPayment;
|
this.graceOnPrincipalPayment = graceOnPrincipalPayment;
|
||||||
@@ -1289,6 +1331,7 @@ public class LoanAccountData {
|
|||||||
if (this.product != null) {
|
if (this.product != null) {
|
||||||
this.product.setloanProductConfigurableAttributes(product.getloanProductConfigurableAttributes());
|
this.product.setloanProductConfigurableAttributes(product.getloanProductConfigurableAttributes());
|
||||||
}
|
}
|
||||||
|
this.interestRatesPeriods = interestRatesPeriods;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData() {
|
public RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData() {
|
||||||
@@ -1395,4 +1438,5 @@ public class LoanAccountData {
|
|||||||
if(this.summary != null) return this.summary.getTotalPaidFeeCharges() ;
|
if(this.summary != null) return this.summary.getTotalPaidFeeCharges() ;
|
||||||
return BigDecimal.ZERO ;
|
return BigDecimal.ZERO ;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+42
@@ -9,6 +9,7 @@ import java.math.BigDecimal;
|
|||||||
|
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanTermVariationType;
|
||||||
|
|
||||||
public class LoanTermVariationsData {
|
public class LoanTermVariationsData {
|
||||||
|
|
||||||
@@ -16,6 +17,7 @@ public class LoanTermVariationsData {
|
|||||||
private final Long id;
|
private final Long id;
|
||||||
private final EnumOptionData termType;
|
private final EnumOptionData termType;
|
||||||
private final LocalDate termVariationApplicableFrom;
|
private final LocalDate termVariationApplicableFrom;
|
||||||
|
private final Integer termVariationApplicableFromInstallment;
|
||||||
private final BigDecimal termValue;
|
private final BigDecimal termValue;
|
||||||
|
|
||||||
public LoanTermVariationsData(final Long id, final EnumOptionData termType, final LocalDate termVariationApplicableFrom,
|
public LoanTermVariationsData(final Long id, final EnumOptionData termType, final LocalDate termVariationApplicableFrom,
|
||||||
@@ -24,11 +26,25 @@ public class LoanTermVariationsData {
|
|||||||
this.termType = termType;
|
this.termType = termType;
|
||||||
this.termVariationApplicableFrom = termVariationApplicableFrom;
|
this.termVariationApplicableFrom = termVariationApplicableFrom;
|
||||||
this.termValue = termValue;
|
this.termValue = termValue;
|
||||||
|
this.termVariationApplicableFromInstallment = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoanTermVariationsData(final EnumOptionData termType, final LocalDate termVariationApplicableFrom,
|
||||||
|
final BigDecimal termValue) {
|
||||||
|
this.id = null;
|
||||||
|
this.termType = termType;
|
||||||
|
this.termVariationApplicableFrom = termVariationApplicableFrom;
|
||||||
|
this.termValue = termValue;
|
||||||
|
this.termVariationApplicableFromInstallment = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EnumOptionData getTermType() {
|
public EnumOptionData getTermType() {
|
||||||
return this.termType;
|
return this.termType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LoanTermVariationType getTermVariationType(){
|
||||||
|
return LoanTermVariationType.fromInt(this.termType.getId().intValue());
|
||||||
|
}
|
||||||
|
|
||||||
public LocalDate getTermApplicableFrom() {
|
public LocalDate getTermApplicableFrom() {
|
||||||
return this.termVariationApplicableFrom;
|
return this.termVariationApplicableFrom;
|
||||||
@@ -37,4 +53,30 @@ public class LoanTermVariationsData {
|
|||||||
public BigDecimal getTermValue() {
|
public BigDecimal getTermValue() {
|
||||||
return this.termValue;
|
return this.termValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isApplicable(final LocalDate fromDate, final LocalDate dueDate, int installmentNumber) {
|
||||||
|
return occursOnDayFromAndUpTo(fromDate, dueDate, this.termVariationApplicableFrom)
|
||||||
|
|| isIntegerEquals(installmentNumber, this.termVariationApplicableFromInstallment);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean occursOnDayFromAndUpTo(final LocalDate fromInclusive, final LocalDate upToNotInclusive, final LocalDate target) {
|
||||||
|
return target != null && !target.isBefore(fromInclusive) && target.isBefore(upToNotInclusive);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isIntegerEquals(final Integer installmentNumber, final Integer target) {
|
||||||
|
return target != null && target.equals(installmentNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isApplicable(final LocalDate fromDate, int installmentNumber) {
|
||||||
|
return occursBefore(fromDate, this.termVariationApplicableFrom)
|
||||||
|
|| isIntegerGreterThan(installmentNumber, this.termVariationApplicableFromInstallment);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean occursBefore(final LocalDate date, final LocalDate target) {
|
||||||
|
return target != null && target.isBefore(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isIntegerGreterThan(final Integer installmentNumber, final Integer target) {
|
||||||
|
return target != null && target < installmentNumber;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-3
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.loanaccount.data;
|
|||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
|
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRateDTO;
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
|
||||||
|
|
||||||
public class ScheduleGeneratorDTO {
|
public class ScheduleGeneratorDTO {
|
||||||
@@ -20,10 +21,12 @@ public class ScheduleGeneratorDTO {
|
|||||||
final CalendarInstance compoundingCalendarInstance;
|
final CalendarInstance compoundingCalendarInstance;
|
||||||
LocalDate recalculateFrom;
|
LocalDate recalculateFrom;
|
||||||
final Long overdurPenaltyWaitPeriod;
|
final Long overdurPenaltyWaitPeriod;
|
||||||
|
final FloatingRateDTO floatingRateDTO;
|
||||||
|
|
||||||
public ScheduleGeneratorDTO(final LoanScheduleGeneratorFactory loanScheduleFactory, final ApplicationCurrency applicationCurrency,
|
public ScheduleGeneratorDTO(final LoanScheduleGeneratorFactory loanScheduleFactory, final ApplicationCurrency applicationCurrency,
|
||||||
final LocalDate calculatedRepaymentsStartingFromDate, final HolidayDetailDTO holidayDetailDTO,
|
final LocalDate calculatedRepaymentsStartingFromDate, final HolidayDetailDTO holidayDetailDTO,
|
||||||
final CalendarInstance calendarInstanceForInterestRecalculation, final CalendarInstance compoundingCalendarInstance) {
|
final CalendarInstance calendarInstanceForInterestRecalculation, final CalendarInstance compoundingCalendarInstance,
|
||||||
|
final FloatingRateDTO floatingRateDTO) {
|
||||||
|
|
||||||
this.loanScheduleFactory = loanScheduleFactory;
|
this.loanScheduleFactory = loanScheduleFactory;
|
||||||
this.applicationCurrency = applicationCurrency;
|
this.applicationCurrency = applicationCurrency;
|
||||||
@@ -33,13 +36,14 @@ public class ScheduleGeneratorDTO {
|
|||||||
this.recalculateFrom = null;
|
this.recalculateFrom = null;
|
||||||
this.overdurPenaltyWaitPeriod = null;
|
this.overdurPenaltyWaitPeriod = null;
|
||||||
this.holidayDetailDTO = holidayDetailDTO;
|
this.holidayDetailDTO = holidayDetailDTO;
|
||||||
|
this.floatingRateDTO = floatingRateDTO;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScheduleGeneratorDTO(final LoanScheduleGeneratorFactory loanScheduleFactory, final ApplicationCurrency applicationCurrency,
|
public ScheduleGeneratorDTO(final LoanScheduleGeneratorFactory loanScheduleFactory, final ApplicationCurrency applicationCurrency,
|
||||||
final LocalDate calculatedRepaymentsStartingFromDate, final HolidayDetailDTO holidayDetailDTO,
|
final LocalDate calculatedRepaymentsStartingFromDate, final HolidayDetailDTO holidayDetailDTO,
|
||||||
final CalendarInstance calendarInstanceForInterestRecalculation, final CalendarInstance compoundingCalendarInstance,
|
final CalendarInstance calendarInstanceForInterestRecalculation, final CalendarInstance compoundingCalendarInstance,
|
||||||
final LocalDate recalculateFrom, final Long overdurPenaltyWaitPeriod) {
|
final LocalDate recalculateFrom, final Long overdurPenaltyWaitPeriod, final FloatingRateDTO floatingRateDTO) {
|
||||||
|
|
||||||
this.loanScheduleFactory = loanScheduleFactory;
|
this.loanScheduleFactory = loanScheduleFactory;
|
||||||
this.applicationCurrency = applicationCurrency;
|
this.applicationCurrency = applicationCurrency;
|
||||||
@@ -49,7 +53,7 @@ public class ScheduleGeneratorDTO {
|
|||||||
this.recalculateFrom = recalculateFrom;
|
this.recalculateFrom = recalculateFrom;
|
||||||
this.overdurPenaltyWaitPeriod = overdurPenaltyWaitPeriod;
|
this.overdurPenaltyWaitPeriod = overdurPenaltyWaitPeriod;
|
||||||
this.holidayDetailDTO = holidayDetailDTO;
|
this.holidayDetailDTO = holidayDetailDTO;
|
||||||
|
this.floatingRateDTO = floatingRateDTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoanScheduleGeneratorFactory getLoanScheduleFactory() {
|
public LoanScheduleGeneratorFactory getLoanScheduleFactory() {
|
||||||
@@ -96,4 +100,9 @@ public class ScheduleGeneratorDTO {
|
|||||||
return this.compoundingCalendarInstance;
|
return this.compoundingCalendarInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public FloatingRateDTO getFloatingRateDTO() {
|
||||||
|
return this.floatingRateDTO;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+140
-17
@@ -77,6 +77,8 @@ import org.mifosplatform.portfolio.collateral.domain.LoanCollateral;
|
|||||||
import org.mifosplatform.portfolio.common.domain.DayOfWeekType;
|
import org.mifosplatform.portfolio.common.domain.DayOfWeekType;
|
||||||
import org.mifosplatform.portfolio.common.domain.NthDayType;
|
import org.mifosplatform.portfolio.common.domain.NthDayType;
|
||||||
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRateDTO;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRatePeriodData;
|
||||||
import org.mifosplatform.portfolio.fund.domain.Fund;
|
import org.mifosplatform.portfolio.fund.domain.Fund;
|
||||||
import org.mifosplatform.portfolio.group.domain.Group;
|
import org.mifosplatform.portfolio.group.domain.Group;
|
||||||
import org.mifosplatform.portfolio.loanaccount.api.LoanApiConstants;
|
import org.mifosplatform.portfolio.loanaccount.api.LoanApiConstants;
|
||||||
@@ -369,18 +371,26 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
@Column(name = "interest_recalcualated_on")
|
@Column(name = "interest_recalcualated_on")
|
||||||
private Date interestRecalculatedOn;
|
private Date interestRecalculatedOn;
|
||||||
|
|
||||||
|
@Column(name = "is_floating_interest_rate", nullable = true)
|
||||||
|
private Boolean isFloatingInterestRate;
|
||||||
|
|
||||||
|
@Column(name = "interest_rate_differential", scale = 6, precision = 19, nullable = true)
|
||||||
|
private BigDecimal interestRateDifferential;
|
||||||
|
|
||||||
public static Loan newIndividualLoanApplication(final String accountNo, final Client client, final Integer loanType,
|
public static Loan newIndividualLoanApplication(final String accountNo, final Client client, final Integer loanType,
|
||||||
final LoanProduct loanProduct, final Fund fund, final Staff officer, final CodeValue loanPurpose,
|
final LoanProduct loanProduct, final Fund fund, final Staff officer, final CodeValue loanPurpose,
|
||||||
final LoanTransactionProcessingStrategy transactionProcessingStrategy,
|
final LoanTransactionProcessingStrategy transactionProcessingStrategy,
|
||||||
final LoanProductRelatedDetail loanRepaymentScheduleDetail, final Set<LoanCharge> loanCharges,
|
final LoanProductRelatedDetail loanRepaymentScheduleDetail, final Set<LoanCharge> loanCharges,
|
||||||
final Set<LoanCollateral> collateral, final BigDecimal fixedEmiAmount, final Set<LoanDisbursementDetails> disbursementDetails,
|
final Set<LoanCollateral> collateral, final BigDecimal fixedEmiAmount, final Set<LoanDisbursementDetails> disbursementDetails,
|
||||||
final BigDecimal maxOutstandingLoanBalance, final Boolean createStandingInstructionAtDisbursement) {
|
final BigDecimal maxOutstandingLoanBalance, final Boolean createStandingInstructionAtDisbursement,
|
||||||
|
final Boolean isFloatingInterestRate, final BigDecimal interestRateDifferential) {
|
||||||
final LoanStatus status = null;
|
final LoanStatus status = null;
|
||||||
final Group group = null;
|
final Group group = null;
|
||||||
final Boolean syncDisbursementWithMeeting = null;
|
final Boolean syncDisbursementWithMeeting = null;
|
||||||
return new Loan(accountNo, client, group, loanType, fund, officer, loanPurpose, transactionProcessingStrategy, loanProduct,
|
return new Loan(accountNo, client, group, loanType, fund, officer, loanPurpose, transactionProcessingStrategy, loanProduct,
|
||||||
loanRepaymentScheduleDetail, status, loanCharges, collateral, syncDisbursementWithMeeting, fixedEmiAmount,
|
loanRepaymentScheduleDetail, status, loanCharges, collateral, syncDisbursementWithMeeting, fixedEmiAmount,
|
||||||
disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement);
|
disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement, isFloatingInterestRate,
|
||||||
|
interestRateDifferential);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Loan newGroupLoanApplication(final String accountNo, final Group group, final Integer loanType,
|
public static Loan newGroupLoanApplication(final String accountNo, final Group group, final Integer loanType,
|
||||||
@@ -389,12 +399,14 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
final LoanProductRelatedDetail loanRepaymentScheduleDetail, final Set<LoanCharge> loanCharges,
|
final LoanProductRelatedDetail loanRepaymentScheduleDetail, final Set<LoanCharge> loanCharges,
|
||||||
final Set<LoanCollateral> collateral, final Boolean syncDisbursementWithMeeting, final BigDecimal fixedEmiAmount,
|
final Set<LoanCollateral> collateral, final Boolean syncDisbursementWithMeeting, final BigDecimal fixedEmiAmount,
|
||||||
final Set<LoanDisbursementDetails> disbursementDetails, final BigDecimal maxOutstandingLoanBalance,
|
final Set<LoanDisbursementDetails> disbursementDetails, final BigDecimal maxOutstandingLoanBalance,
|
||||||
final Boolean createStandingInstructionAtDisbursement) {
|
final Boolean createStandingInstructionAtDisbursement, final Boolean isFloatingInterestRate,
|
||||||
|
final BigDecimal interestRateDifferential) {
|
||||||
final LoanStatus status = null;
|
final LoanStatus status = null;
|
||||||
final Client client = null;
|
final Client client = null;
|
||||||
return new Loan(accountNo, client, group, loanType, fund, officer, loanPurpose, transactionProcessingStrategy, loanProduct,
|
return new Loan(accountNo, client, group, loanType, fund, officer, loanPurpose, transactionProcessingStrategy, loanProduct,
|
||||||
loanRepaymentScheduleDetail, status, loanCharges, collateral, syncDisbursementWithMeeting, fixedEmiAmount,
|
loanRepaymentScheduleDetail, status, loanCharges, collateral, syncDisbursementWithMeeting, fixedEmiAmount,
|
||||||
disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement);
|
disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement, isFloatingInterestRate,
|
||||||
|
interestRateDifferential);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Loan newIndividualLoanApplicationFromGroup(final String accountNo, final Client client, final Group group,
|
public static Loan newIndividualLoanApplicationFromGroup(final String accountNo, final Client client, final Group group,
|
||||||
@@ -403,11 +415,13 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
final LoanProductRelatedDetail loanRepaymentScheduleDetail, final Set<LoanCharge> loanCharges,
|
final LoanProductRelatedDetail loanRepaymentScheduleDetail, final Set<LoanCharge> loanCharges,
|
||||||
final Set<LoanCollateral> collateral, final Boolean syncDisbursementWithMeeting, final BigDecimal fixedEmiAmount,
|
final Set<LoanCollateral> collateral, final Boolean syncDisbursementWithMeeting, final BigDecimal fixedEmiAmount,
|
||||||
final Set<LoanDisbursementDetails> disbursementDetails, final BigDecimal maxOutstandingLoanBalance,
|
final Set<LoanDisbursementDetails> disbursementDetails, final BigDecimal maxOutstandingLoanBalance,
|
||||||
final Boolean createStandingInstructionAtDisbursement) {
|
final Boolean createStandingInstructionAtDisbursement, final Boolean isFloatingInterestRate,
|
||||||
|
final BigDecimal interestRateDifferential) {
|
||||||
final LoanStatus status = null;
|
final LoanStatus status = null;
|
||||||
return new Loan(accountNo, client, group, loanType, fund, officer, loanPurpose, transactionProcessingStrategy, loanProduct,
|
return new Loan(accountNo, client, group, loanType, fund, officer, loanPurpose, transactionProcessingStrategy, loanProduct,
|
||||||
loanRepaymentScheduleDetail, status, loanCharges, collateral, syncDisbursementWithMeeting, fixedEmiAmount,
|
loanRepaymentScheduleDetail, status, loanCharges, collateral, syncDisbursementWithMeeting, fixedEmiAmount,
|
||||||
disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement);
|
disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement, isFloatingInterestRate,
|
||||||
|
interestRateDifferential);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Loan() {
|
protected Loan() {
|
||||||
@@ -419,11 +433,15 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
final LoanProduct loanProduct, final LoanProductRelatedDetail loanRepaymentScheduleDetail, final LoanStatus loanStatus,
|
final LoanProduct loanProduct, final LoanProductRelatedDetail loanRepaymentScheduleDetail, final LoanStatus loanStatus,
|
||||||
final Set<LoanCharge> loanCharges, final Set<LoanCollateral> collateral, final Boolean syncDisbursementWithMeeting,
|
final Set<LoanCharge> loanCharges, final Set<LoanCollateral> collateral, final Boolean syncDisbursementWithMeeting,
|
||||||
final BigDecimal fixedEmiAmount, final Set<LoanDisbursementDetails> disbursementDetails,
|
final BigDecimal fixedEmiAmount, final Set<LoanDisbursementDetails> disbursementDetails,
|
||||||
final BigDecimal maxOutstandingLoanBalance, final Boolean createStandingInstructionAtDisbursement) {
|
final BigDecimal maxOutstandingLoanBalance, final Boolean createStandingInstructionAtDisbursement,
|
||||||
|
final Boolean isFloatingInterestRate, final BigDecimal interestRateDifferential) {
|
||||||
|
|
||||||
this.loanRepaymentScheduleDetail = loanRepaymentScheduleDetail;
|
this.loanRepaymentScheduleDetail = loanRepaymentScheduleDetail;
|
||||||
this.loanRepaymentScheduleDetail.validateRepaymentPeriodWithGraceSettings();
|
this.loanRepaymentScheduleDetail.validateRepaymentPeriodWithGraceSettings();
|
||||||
|
|
||||||
|
this.isFloatingInterestRate = isFloatingInterestRate;
|
||||||
|
this.interestRateDifferential = interestRateDifferential;
|
||||||
|
|
||||||
if (StringUtils.isBlank(accountNo)) {
|
if (StringUtils.isBlank(accountNo)) {
|
||||||
this.accountNumber = new RandomPasswordGenerator(19).generate();
|
this.accountNumber = new RandomPasswordGenerator(19).generate();
|
||||||
this.accountNumberRequiresAutoGeneration = true;
|
this.accountNumberRequiresAutoGeneration = true;
|
||||||
@@ -1288,6 +1306,20 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
actualChanges.put("recalculateLoanSchedule", true);
|
actualChanges.put("recalculateLoanSchedule", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final String isFloatingInterestRateParamName = "isFloatingInterestRate";
|
||||||
|
if (command.isChangeInBooleanParameterNamed(isFloatingInterestRateParamName, this.isFloatingInterestRate)) {
|
||||||
|
final Boolean newValue = command.booleanObjectValueOfParameterNamed(isFloatingInterestRateParamName);
|
||||||
|
actualChanges.put(isFloatingInterestRateParamName, newValue);
|
||||||
|
this.isFloatingInterestRate = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String interestRateDifferentialParamName = "interestRateDifferential";
|
||||||
|
if (command.isChangeInBigDecimalParameterNamed(interestRateDifferentialParamName, this.interestRateDifferential)) {
|
||||||
|
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(interestRateDifferentialParamName);
|
||||||
|
actualChanges.put(interestRateDifferentialParamName, newValue);
|
||||||
|
this.interestRateDifferential = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
Long existingFundId = null;
|
Long existingFundId = null;
|
||||||
if (this.fund != null) {
|
if (this.fund != null) {
|
||||||
existingFundId = this.fund.getId();
|
existingFundId = this.fund.getId();
|
||||||
@@ -1498,6 +1530,7 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
for (final LoanCharge loanCharge : charges) {
|
for (final LoanCharge loanCharge : charges) {
|
||||||
recalculateLoanCharge(loanCharge, penaltyWaitPeriod);
|
recalculateLoanCharge(loanCharge, penaltyWaitPeriod);
|
||||||
}
|
}
|
||||||
|
updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isInterestRecalculationEnabledForProduct() {
|
public boolean isInterestRecalculationEnabledForProduct() {
|
||||||
@@ -2578,6 +2611,23 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
rescheduleStrategyMethod = this.loanInterestRecalculationDetails.getRescheduleStrategyMethod();
|
rescheduleStrategyMethod = this.loanInterestRecalculationDetails.getRescheduleStrategyMethod();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BigDecimal annualNominalInterestRate = this.loanRepaymentScheduleDetail.getAnnualNominalInterestRate();
|
||||||
|
Collection<LoanTermVariationsData> loanTermVariations = new ArrayList<>();
|
||||||
|
if (loanProduct.isLinkedToFloatingInterestRate()) {
|
||||||
|
Collection<FloatingRatePeriodData> applicableRates = loanProduct.fetchInterestRates(scheduleGeneratorDTO.getFloatingRateDTO());
|
||||||
|
LocalDate interestRateStartDate = DateUtils.getLocalDateOfTenant();
|
||||||
|
for (FloatingRatePeriodData periodData : applicableRates) {
|
||||||
|
LoanTermVariationsData loanTermVariation = new LoanTermVariationsData(
|
||||||
|
LoanEnumerations.loanvariationType(LoanTermVariationType.INTEREST_RATE), periodData.getFromDateAsLocalDate(),
|
||||||
|
periodData.getInterestRate());
|
||||||
|
if (interestRateStartDate.isAfter(periodData.getFromDateAsLocalDate())) {
|
||||||
|
interestRateStartDate = periodData.getFromDateAsLocalDate();
|
||||||
|
annualNominalInterestRate = periodData.getInterestRate();
|
||||||
|
}
|
||||||
|
loanTermVariations.add(loanTermVariation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(scheduleGeneratorDTO.getApplicationCurrency(),
|
final LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(scheduleGeneratorDTO.getApplicationCurrency(),
|
||||||
loanTermFrequency, loanTermPeriodFrequencyType, nthDayType, dayOfWeekType, getDisbursementDate(),
|
loanTermFrequency, loanTermPeriodFrequencyType, nthDayType, dayOfWeekType, getDisbursementDate(),
|
||||||
getExpectedFirstRepaymentOnDate(), scheduleGeneratorDTO.getCalculatedRepaymentsStartingFromDate(), getInArrearsTolerance(),
|
getExpectedFirstRepaymentOnDate(), scheduleGeneratorDTO.getCalculatedRepaymentsStartingFromDate(), getInArrearsTolerance(),
|
||||||
@@ -2585,7 +2635,8 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
this.maxOutstandingLoanBalance, loanVariationTermsData, getInterestChargedFromDate(),
|
this.maxOutstandingLoanBalance, loanVariationTermsData, getInterestChargedFromDate(),
|
||||||
this.loanProduct.getPrincipalThresholdForLastInstallment(), this.loanProduct.getInstallmentAmountInMultiplesOf(),
|
this.loanProduct.getPrincipalThresholdForLastInstallment(), this.loanProduct.getInstallmentAmountInMultiplesOf(),
|
||||||
recalculationFrequencyType, restCalendarInstance, compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType,
|
recalculationFrequencyType, restCalendarInstance, compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType,
|
||||||
this.loanProduct.preCloseInterestCalculationStrategy(), rescheduleStrategyMethod, getApprovedPrincipal());
|
this.loanProduct.preCloseInterestCalculationStrategy(), rescheduleStrategyMethod, getApprovedPrincipal(),
|
||||||
|
annualNominalInterestRate, loanTermVariations);
|
||||||
|
|
||||||
final LoanScheduleModel loanSchedule = loanScheduleGenerator.generate(mc, loanApplicationTerms, charges(),
|
final LoanScheduleModel loanSchedule = loanScheduleGenerator.generate(mc, loanApplicationTerms, charges(),
|
||||||
scheduleGeneratorDTO.getHolidayDetailDTO());
|
scheduleGeneratorDTO.getHolidayDetailDTO());
|
||||||
@@ -4839,6 +4890,8 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
*/
|
*/
|
||||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
regenerateRepaymentScheduleWithInterestRecalculation(generatorDTO, currentUser);
|
regenerateRepaymentScheduleWithInterestRecalculation(generatorDTO, currentUser);
|
||||||
|
} else {
|
||||||
|
regenerateRepaymentSchedule(generatorDTO, currentUser);
|
||||||
}
|
}
|
||||||
return processTransactions();
|
return processTransactions();
|
||||||
|
|
||||||
@@ -4929,7 +4982,7 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
final LoanApplicationTerms loanApplicationTerms = constructLoanApplicationTerms(generatorDTO.getApplicationCurrency(),
|
final LoanApplicationTerms loanApplicationTerms = constructLoanApplicationTerms(generatorDTO.getApplicationCurrency(),
|
||||||
generatorDTO.getCalculatedRepaymentsStartingFromDate(), generatorDTO.getCalendarInstanceForInterestRecalculation(),
|
generatorDTO.getCalculatedRepaymentsStartingFromDate(), generatorDTO.getCalendarInstanceForInterestRecalculation(),
|
||||||
generatorDTO.getCompoundingCalendarInstance());
|
generatorDTO.getCompoundingCalendarInstance(), generatorDTO.getFloatingRateDTO());
|
||||||
|
|
||||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||||
.determineProcessor(this.transactionProcessingStrategy);
|
.determineProcessor(this.transactionProcessingStrategy);
|
||||||
@@ -4941,7 +4994,7 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
public LoanApplicationTerms constructLoanApplicationTerms(final ApplicationCurrency applicationCurrency,
|
public LoanApplicationTerms constructLoanApplicationTerms(final ApplicationCurrency applicationCurrency,
|
||||||
final LocalDate calculatedRepaymentsStartingFromDate, final CalendarInstance calendarInstanceForInterestRecalculation,
|
final LocalDate calculatedRepaymentsStartingFromDate, final CalendarInstance calendarInstanceForInterestRecalculation,
|
||||||
final CalendarInstance compoundingCalendarInstance) {
|
final CalendarInstance compoundingCalendarInstance, final FloatingRateDTO floatingRateDTO) {
|
||||||
final Integer loanTermFrequency = this.termFrequency;
|
final Integer loanTermFrequency = this.termFrequency;
|
||||||
final PeriodFrequencyType loanTermPeriodFrequencyType = PeriodFrequencyType.fromInt(this.termPeriodFrequencyType);
|
final PeriodFrequencyType loanTermPeriodFrequencyType = PeriodFrequencyType.fromInt(this.termPeriodFrequencyType);
|
||||||
final List<DisbursementData> disbursementData = new ArrayList<>();
|
final List<DisbursementData> disbursementData = new ArrayList<>();
|
||||||
@@ -4967,6 +5020,23 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
RecalculationFrequencyType recalculationFrequencyType = this.loanInterestRecalculationDetails().getRestFrequencyType();
|
RecalculationFrequencyType recalculationFrequencyType = this.loanInterestRecalculationDetails().getRestFrequencyType();
|
||||||
RecalculationFrequencyType compoundingFrequencyType = this.loanInterestRecalculationDetails().getCompoundingFrequencyType();
|
RecalculationFrequencyType compoundingFrequencyType = this.loanInterestRecalculationDetails().getCompoundingFrequencyType();
|
||||||
|
|
||||||
|
BigDecimal annualNominalInterestRate = this.loanRepaymentScheduleDetail.getAnnualNominalInterestRate();
|
||||||
|
Collection<LoanTermVariationsData> loanTermVariations = new ArrayList<>();
|
||||||
|
if (loanProduct.isLinkedToFloatingInterestRate()) {
|
||||||
|
Collection<FloatingRatePeriodData> applicableRates = loanProduct.fetchInterestRates(floatingRateDTO);
|
||||||
|
LocalDate interestRateStartDate = DateUtils.getLocalDateOfTenant();
|
||||||
|
for (FloatingRatePeriodData periodData : applicableRates) {
|
||||||
|
LoanTermVariationsData loanTermVariation = new LoanTermVariationsData(
|
||||||
|
LoanEnumerations.loanvariationType(LoanTermVariationType.INTEREST_RATE), periodData.getFromDateAsLocalDate(),
|
||||||
|
periodData.getInterestRate());
|
||||||
|
if (interestRateStartDate.isAfter(periodData.getFromDateAsLocalDate())) {
|
||||||
|
interestRateStartDate = periodData.getFromDateAsLocalDate();
|
||||||
|
annualNominalInterestRate = periodData.getInterestRate();
|
||||||
|
}
|
||||||
|
loanTermVariations.add(loanTermVariation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency,
|
final LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency,
|
||||||
loanTermPeriodFrequencyType, getDisbursementDate(), getExpectedFirstRepaymentOnDate(),
|
loanTermPeriodFrequencyType, getDisbursementDate(), getExpectedFirstRepaymentOnDate(),
|
||||||
calculatedRepaymentsStartingFromDate, getInArrearsTolerance(), this.loanRepaymentScheduleDetail,
|
calculatedRepaymentsStartingFromDate, getInArrearsTolerance(), this.loanRepaymentScheduleDetail,
|
||||||
@@ -4975,13 +5045,13 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
calendarInstanceForInterestRecalculation, recalculationFrequencyType, compoundingCalendarInstance,
|
calendarInstanceForInterestRecalculation, recalculationFrequencyType, compoundingCalendarInstance,
|
||||||
compoundingFrequencyType, this.loanProduct.getPrincipalThresholdForLastInstallment(),
|
compoundingFrequencyType, this.loanProduct.getPrincipalThresholdForLastInstallment(),
|
||||||
this.loanProduct.getInstallmentAmountInMultiplesOf(), this.loanProduct.preCloseInterestCalculationStrategy(),
|
this.loanProduct.getInstallmentAmountInMultiplesOf(), this.loanProduct.preCloseInterestCalculationStrategy(),
|
||||||
getApprovedPrincipal());
|
getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations);
|
||||||
return loanApplicationTerms;
|
return loanApplicationTerms;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoanRepaymentScheduleInstallment fetchPrepaymentDetail(final LoanScheduleGeneratorFactory loanScheduleFactory,
|
public LoanRepaymentScheduleInstallment fetchPrepaymentDetail(final LoanScheduleGeneratorFactory loanScheduleFactory,
|
||||||
final CalendarInstance restCalendarInstance, final CalendarInstance compoundingCalendarInstance,
|
final CalendarInstance restCalendarInstance, final CalendarInstance compoundingCalendarInstance,
|
||||||
final HolidayDetailDTO holidayDetailDTO, final LocalDate onDate) {
|
final HolidayDetailDTO holidayDetailDTO, final LocalDate onDate, FloatingRateDTO floatingRateDTO) {
|
||||||
LoanRepaymentScheduleInstallment installment = null;
|
LoanRepaymentScheduleInstallment installment = null;
|
||||||
|
|
||||||
if (this.loanRepaymentScheduleDetail.isInterestRecalculationEnabled()) {
|
if (this.loanRepaymentScheduleDetail.isInterestRecalculationEnabled()) {
|
||||||
@@ -5028,6 +5098,23 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
rescheduleStrategyMethod = this.loanInterestRecalculationDetails.getRescheduleStrategyMethod();
|
rescheduleStrategyMethod = this.loanInterestRecalculationDetails.getRescheduleStrategyMethod();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BigDecimal annualNominalInterestRate = this.loanRepaymentScheduleDetail.getAnnualNominalInterestRate();
|
||||||
|
Collection<LoanTermVariationsData> loanTermVariations = new ArrayList<>();
|
||||||
|
if (loanProduct.isLinkedToFloatingInterestRate()) {
|
||||||
|
Collection<FloatingRatePeriodData> applicableRates = loanProduct.fetchInterestRates(floatingRateDTO);
|
||||||
|
LocalDate interestRateStartDate = DateUtils.getLocalDateOfTenant();
|
||||||
|
for (FloatingRatePeriodData periodData : applicableRates) {
|
||||||
|
LoanTermVariationsData loanTermVariation = new LoanTermVariationsData(
|
||||||
|
LoanEnumerations.loanvariationType(LoanTermVariationType.INTEREST_RATE), periodData.getFromDateAsLocalDate(),
|
||||||
|
periodData.getInterestRate());
|
||||||
|
if (interestRateStartDate.isAfter(periodData.getFromDateAsLocalDate())) {
|
||||||
|
interestRateStartDate = periodData.getFromDateAsLocalDate();
|
||||||
|
annualNominalInterestRate = periodData.getInterestRate();
|
||||||
|
}
|
||||||
|
loanTermVariations.add(loanTermVariation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(null, loanTermFrequency,
|
final LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(null, loanTermFrequency,
|
||||||
loanTermPeriodFrequencyType, nthDayType, dayOfWeekType, getDisbursementDate(), getExpectedFirstRepaymentOnDate(), null,
|
loanTermPeriodFrequencyType, nthDayType, dayOfWeekType, getDisbursementDate(), getExpectedFirstRepaymentOnDate(), null,
|
||||||
getInArrearsTolerance(), this.loanRepaymentScheduleDetail, this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount,
|
getInArrearsTolerance(), this.loanRepaymentScheduleDetail, this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount,
|
||||||
@@ -5035,7 +5122,7 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
this.loanProduct.getPrincipalThresholdForLastInstallment(), this.loanProduct.getInstallmentAmountInMultiplesOf(),
|
this.loanProduct.getPrincipalThresholdForLastInstallment(), this.loanProduct.getInstallmentAmountInMultiplesOf(),
|
||||||
recalculationFrequencyType, restCalendarInstance, compoundingMethod, compoundingCalendarInstance,
|
recalculationFrequencyType, restCalendarInstance, compoundingMethod, compoundingCalendarInstance,
|
||||||
compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(), rescheduleStrategyMethod,
|
compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(), rescheduleStrategyMethod,
|
||||||
getApprovedPrincipal());
|
getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations);
|
||||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||||
.determineProcessor(this.transactionProcessingStrategy);
|
.determineProcessor(this.transactionProcessingStrategy);
|
||||||
installment = loanScheduleGenerator.calculatePrepaymentAmount(getCurrency(), onDate, loanApplicationTerms, mc, charges(),
|
installment = loanScheduleGenerator.calculatePrepaymentAmount(getCurrency(), onDate, loanApplicationTerms, mc, charges(),
|
||||||
@@ -5076,7 +5163,7 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
public LocalDate fetchInterestRecalculateFromDate() {
|
public LocalDate fetchInterestRecalculateFromDate() {
|
||||||
LocalDate interestRecalculatedOn = null;
|
LocalDate interestRecalculatedOn = null;
|
||||||
if (this.interestRecalculatedOn != null) {
|
if (this.interestRecalculatedOn == null) {
|
||||||
interestRecalculatedOn = getDisbursementDate();
|
interestRecalculatedOn = getDisbursementDate();
|
||||||
} else {
|
} else {
|
||||||
interestRecalculatedOn = new LocalDate(this.interestRecalculatedOn);
|
interestRecalculatedOn = new LocalDate(this.interestRecalculatedOn);
|
||||||
@@ -5189,13 +5276,16 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
* TODO
|
* TODO
|
||||||
* @param compoundingCalendarInstance
|
* @param compoundingCalendarInstance
|
||||||
* TODO
|
* TODO
|
||||||
|
* @param floatingRateDTO
|
||||||
|
* TODO
|
||||||
* @param loanCalendarInstance
|
* @param loanCalendarInstance
|
||||||
* Used for accessing the loan's calendar object
|
* Used for accessing the loan's calendar object
|
||||||
* @return application terms of the Loan object
|
* @return application terms of the Loan object
|
||||||
**/
|
**/
|
||||||
@SuppressWarnings({ "unused" })
|
@SuppressWarnings({ "unused" })
|
||||||
public LoanApplicationTerms getLoanApplicationTerms(final ApplicationCurrency applicationCurrency,
|
public LoanApplicationTerms getLoanApplicationTerms(final ApplicationCurrency applicationCurrency,
|
||||||
final CalendarInstance restCalendarInstance, CalendarInstance compoundingCalendarInstance, final Calendar loanCalendar) {
|
final CalendarInstance restCalendarInstance, CalendarInstance compoundingCalendarInstance, final Calendar loanCalendar,
|
||||||
|
final FloatingRateDTO floatingRateDTO) {
|
||||||
LoanProduct loanProduct = loanProduct();
|
LoanProduct loanProduct = loanProduct();
|
||||||
// LoanProductRelatedDetail loanProductRelatedDetail =
|
// LoanProductRelatedDetail loanProductRelatedDetail =
|
||||||
// getLoanRepaymentScheduleDetail();
|
// getLoanRepaymentScheduleDetail();
|
||||||
@@ -5219,7 +5309,7 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
final BigDecimal interestRatePerPeriod = this.loanRepaymentScheduleDetail.getNominalInterestRatePerPeriod();
|
final BigDecimal interestRatePerPeriod = this.loanRepaymentScheduleDetail.getNominalInterestRatePerPeriod();
|
||||||
final PeriodFrequencyType interestRatePeriodFrequencyType = this.loanRepaymentScheduleDetail.getInterestPeriodFrequencyType();
|
final PeriodFrequencyType interestRatePeriodFrequencyType = this.loanRepaymentScheduleDetail.getInterestPeriodFrequencyType();
|
||||||
|
|
||||||
final BigDecimal annualNominalInterestRate = this.loanRepaymentScheduleDetail.getAnnualNominalInterestRate();
|
BigDecimal annualNominalInterestRate = this.loanRepaymentScheduleDetail.getAnnualNominalInterestRate();
|
||||||
final Money principalMoney = this.loanRepaymentScheduleDetail.getPrincipal();
|
final Money principalMoney = this.loanRepaymentScheduleDetail.getPrincipal();
|
||||||
|
|
||||||
final LocalDate expectedDisbursementDate = getExpectedDisbursedOnLocalDate();
|
final LocalDate expectedDisbursementDate = getExpectedDisbursedOnLocalDate();
|
||||||
@@ -5264,13 +5354,30 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
rescheduleStrategyMethod = this.loanInterestRecalculationDetails.getRescheduleStrategyMethod();
|
rescheduleStrategyMethod = this.loanInterestRecalculationDetails.getRescheduleStrategyMethod();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Collection<LoanTermVariationsData> loanTermVariations = new ArrayList<>();
|
||||||
|
if (loanProduct.isLinkedToFloatingInterestRate()) {
|
||||||
|
Collection<FloatingRatePeriodData> applicableRates = loanProduct.fetchInterestRates(floatingRateDTO);
|
||||||
|
LocalDate interestRateStartDate = DateUtils.getLocalDateOfTenant();
|
||||||
|
for (FloatingRatePeriodData periodData : applicableRates) {
|
||||||
|
LoanTermVariationsData loanTermVariation = new LoanTermVariationsData(
|
||||||
|
LoanEnumerations.loanvariationType(LoanTermVariationType.INTEREST_RATE), periodData.getFromDateAsLocalDate(),
|
||||||
|
periodData.getInterestRate());
|
||||||
|
if (interestRateStartDate.isAfter(periodData.getFromDateAsLocalDate())) {
|
||||||
|
interestRateStartDate = periodData.getFromDateAsLocalDate();
|
||||||
|
annualNominalInterestRate = periodData.getInterestRate();
|
||||||
|
}
|
||||||
|
loanTermVariations.add(loanTermVariation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, nthDayType,
|
return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, nthDayType,
|
||||||
dayOfWeekType, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate,
|
dayOfWeekType, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate,
|
||||||
inArrearsToleranceMoney, this.loanRepaymentScheduleDetail, loanProduct.isMultiDisburseLoan(), emiAmount, disbursementData,
|
inArrearsToleranceMoney, this.loanRepaymentScheduleDetail, loanProduct.isMultiDisburseLoan(), emiAmount, disbursementData,
|
||||||
maxOutstandingBalance, loanVariationTermsData, interestChargedFromDate,
|
maxOutstandingBalance, loanVariationTermsData, interestChargedFromDate,
|
||||||
this.loanProduct.getPrincipalThresholdForLastInstallment(), this.loanProduct.getInstallmentAmountInMultiplesOf(),
|
this.loanProduct.getPrincipalThresholdForLastInstallment(), this.loanProduct.getInstallmentAmountInMultiplesOf(),
|
||||||
recalculationFrequencyType, restCalendarInstance, compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType,
|
recalculationFrequencyType, restCalendarInstance, compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType,
|
||||||
this.loanProduct.preCloseInterestCalculationStrategy(), rescheduleStrategyMethod, loanCalendar, getApprovedPrincipal());
|
this.loanProduct.preCloseInterestCalculationStrategy(), rescheduleStrategyMethod, loanCalendar, getApprovedPrincipal(),
|
||||||
|
annualNominalInterestRate, loanTermVariations);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -5509,4 +5616,20 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getIsFloatingInterestRate() {
|
||||||
|
return this.isFloatingInterestRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getInterestRateDifferential() {
|
||||||
|
return this.interestRateDifferential;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsFloatingInterestRate(Boolean isFloatingInterestRate) {
|
||||||
|
this.isFloatingInterestRate = isFloatingInterestRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInterestRateDifferential(BigDecimal interestRateDifferential) {
|
||||||
|
this.interestRateDifferential = interestRateDifferential;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-3
@@ -49,6 +49,9 @@ import org.mifosplatform.portfolio.common.BusinessEventNotificationConstants.BUS
|
|||||||
import org.mifosplatform.portfolio.common.BusinessEventNotificationConstants.BUSINESS_EVENTS;
|
import org.mifosplatform.portfolio.common.BusinessEventNotificationConstants.BUSINESS_EVENTS;
|
||||||
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
||||||
import org.mifosplatform.portfolio.common.service.BusinessEventNotifierService;
|
import org.mifosplatform.portfolio.common.service.BusinessEventNotifierService;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRateDTO;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRatePeriodData;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.group.domain.Group;
|
import org.mifosplatform.portfolio.group.domain.Group;
|
||||||
import org.mifosplatform.portfolio.group.exception.GroupNotActiveException;
|
import org.mifosplatform.portfolio.group.exception.GroupNotActiveException;
|
||||||
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
|
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||||
@@ -88,6 +91,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
|||||||
private final LoanAccrualPlatformService loanAccrualPlatformService;
|
private final LoanAccrualPlatformService loanAccrualPlatformService;
|
||||||
private final PlatformSecurityContext context;
|
private final PlatformSecurityContext context;
|
||||||
private final BusinessEventNotifierService businessEventNotifierService;
|
private final BusinessEventNotifierService businessEventNotifierService;
|
||||||
|
private final FloatingRatesReadPlatformService floatingRatesReadPlatformService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanAccountDomainServiceJpa(final LoanAssembler loanAccountAssembler, final LoanRepository loanRepository,
|
public LoanAccountDomainServiceJpa(final LoanAssembler loanAccountAssembler, final LoanRepository loanRepository,
|
||||||
@@ -101,7 +105,8 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
|||||||
final CalendarInstanceRepository calendarInstanceRepository,
|
final CalendarInstanceRepository calendarInstanceRepository,
|
||||||
final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository,
|
final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository,
|
||||||
final LoanAccrualPlatformService loanAccrualPlatformService, final PlatformSecurityContext context,
|
final LoanAccrualPlatformService loanAccrualPlatformService, final PlatformSecurityContext context,
|
||||||
final BusinessEventNotifierService businessEventNotifierService) {
|
final BusinessEventNotifierService businessEventNotifierService,
|
||||||
|
final FloatingRatesReadPlatformService floatingRatesReadPlatformService) {
|
||||||
this.loanAccountAssembler = loanAccountAssembler;
|
this.loanAccountAssembler = loanAccountAssembler;
|
||||||
this.loanRepository = loanRepository;
|
this.loanRepository = loanRepository;
|
||||||
this.loanTransactionRepository = loanTransactionRepository;
|
this.loanTransactionRepository = loanTransactionRepository;
|
||||||
@@ -119,6 +124,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
|||||||
this.loanAccrualPlatformService = loanAccrualPlatformService;
|
this.loanAccrualPlatformService = loanAccrualPlatformService;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.businessEventNotifierService = businessEventNotifierService;
|
this.businessEventNotifierService = businessEventNotifierService;
|
||||||
|
this.floatingRatesReadPlatformService = floatingRatesReadPlatformService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@@ -190,9 +196,11 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
|||||||
}
|
}
|
||||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays, allowTransactionsOnHoliday,
|
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays, allowTransactionsOnHoliday,
|
||||||
allowTransactionsOnNonWorkingDay);
|
allowTransactionsOnNonWorkingDay);
|
||||||
|
FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
|
||||||
|
|
||||||
final ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
final ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
||||||
overdurPenaltyWaitPeriod);
|
overdurPenaltyWaitPeriod, floatingRateDTO);
|
||||||
|
|
||||||
final ChangedTransactionDetail changedTransactionDetail = loan.makeRepayment(newRepaymentTransaction,
|
final ChangedTransactionDetail changedTransactionDetail = loan.makeRepayment(newRepaymentTransaction,
|
||||||
defaultLoanLifecycleStateMachine(), existingTransactionIds, existingReversedTransactionIds, isRecoveryRepayment,
|
defaultLoanLifecycleStateMachine(), existingTransactionIds, existingReversedTransactionIds, isRecoveryRepayment,
|
||||||
@@ -239,6 +247,19 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
|||||||
return newRepaymentTransaction;
|
return newRepaymentTransaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private FloatingRateDTO constructFloatingRateDTO(final Loan loan) {
|
||||||
|
FloatingRateDTO floatingRateDTO = null;
|
||||||
|
if (loan.loanProduct().isLinkedToFloatingInterestRate()) {
|
||||||
|
boolean isFloatingInterestRate = loan.getIsFloatingInterestRate();
|
||||||
|
BigDecimal interestRateDiff = loan.getInterestRateDifferential();
|
||||||
|
List<FloatingRatePeriodData> baseLendingRatePeriods = this.floatingRatesReadPlatformService.retrieveBaseLendingRate()
|
||||||
|
.getRatePeriods();
|
||||||
|
floatingRateDTO = new FloatingRateDTO(isFloatingInterestRate, loan.getDisbursementDate(), interestRateDiff,
|
||||||
|
baseLendingRatePeriods);
|
||||||
|
}
|
||||||
|
return floatingRateDTO;
|
||||||
|
}
|
||||||
|
|
||||||
private void saveLoanTransactionWithDataIntegrityViolationChecks(LoanTransaction newRepaymentTransaction) {
|
private void saveLoanTransactionWithDataIntegrityViolationChecks(LoanTransaction newRepaymentTransaction) {
|
||||||
try {
|
try {
|
||||||
this.loanTransactionRepository.save(newRepaymentTransaction);
|
this.loanTransactionRepository.save(newRepaymentTransaction);
|
||||||
@@ -557,8 +578,9 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
|||||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||||
}
|
}
|
||||||
|
FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
|
||||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance);
|
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, floatingRateDTO);
|
||||||
|
|
||||||
return scheduleGeneratorDTO;
|
return scheduleGeneratorDTO;
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -54,6 +54,8 @@ public interface LoanRepository extends JpaRepository<Loan, Long>, JpaSpecificat
|
|||||||
|
|
||||||
public static final String DOES_CLIENT_HAVE_NON_CLOSED_LOANS = "select case when (count (loan) > 0) then true else false end from Loan loan where loan.client.id = :clientId and loan.loanStatus in (100,200,300,303,304,700)";
|
public static final String DOES_CLIENT_HAVE_NON_CLOSED_LOANS = "select case when (count (loan) > 0) then true else false end from Loan loan where loan.client.id = :clientId and loan.loanStatus in (100,200,300,303,304,700)";
|
||||||
|
|
||||||
|
public static final String DOES_PRODUCT_HAVE_NON_CLOSED_LOANS = "select case when (count (loan) > 0) then true else false end from Loan loan where loan.loanProduct.id = :productId and loan.loanStatus in (100,200,300,303,304,700)";
|
||||||
|
|
||||||
@Query(FIND_GROUP_LOANS_DISBURSED_AFTER)
|
@Query(FIND_GROUP_LOANS_DISBURSED_AFTER)
|
||||||
List<Loan> getGroupLoansDisbursedAfter(@Param("disbursementDate") Date disbursementDate, @Param("groupId") Long groupId,
|
List<Loan> getGroupLoansDisbursedAfter(@Param("disbursementDate") Date disbursementDate, @Param("groupId") Long groupId,
|
||||||
@Param("loanType") Integer loanType);
|
@Param("loanType") Integer loanType);
|
||||||
@@ -126,5 +128,8 @@ public interface LoanRepository extends JpaRepository<Loan, Long>, JpaSpecificat
|
|||||||
|
|
||||||
@Query(DOES_CLIENT_HAVE_NON_CLOSED_LOANS)
|
@Query(DOES_CLIENT_HAVE_NON_CLOSED_LOANS)
|
||||||
boolean doNonClosedLoanAccountsExistForClient(@Param("clientId") Long clientId);
|
boolean doNonClosedLoanAccountsExistForClient(@Param("clientId") Long clientId);
|
||||||
|
|
||||||
|
@Query(DOES_PRODUCT_HAVE_NON_CLOSED_LOANS)
|
||||||
|
boolean doNonClosedLoanAccountsExistForProduct(@Param("productId") Long productId);
|
||||||
|
|
||||||
}
|
}
|
||||||
+9
-1
@@ -8,7 +8,8 @@ package org.mifosplatform.portfolio.loanaccount.domain;
|
|||||||
public enum LoanTermVariationType {
|
public enum LoanTermVariationType {
|
||||||
|
|
||||||
INVALID(0, "loanTermType.invalid"), //
|
INVALID(0, "loanTermType.invalid"), //
|
||||||
EMI_AMOUNT(1, "loanTermType.emiAmount"); //
|
EMI_AMOUNT(1, "loanTermType.emiAmount"), //
|
||||||
|
INTEREST_RATE(2, "loanTermType.interestRate");
|
||||||
|
|
||||||
private final Integer value;
|
private final Integer value;
|
||||||
private final String code;
|
private final String code;
|
||||||
@@ -33,6 +34,9 @@ public enum LoanTermVariationType {
|
|||||||
case 1:
|
case 1:
|
||||||
enumeration = LoanTermVariationType.EMI_AMOUNT;
|
enumeration = LoanTermVariationType.EMI_AMOUNT;
|
||||||
break;
|
break;
|
||||||
|
case 2:
|
||||||
|
enumeration = LoanTermVariationType.INTEREST_RATE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return enumeration;
|
return enumeration;
|
||||||
}
|
}
|
||||||
@@ -40,4 +44,8 @@ public enum LoanTermVariationType {
|
|||||||
public boolean isEMIAmountVariation() {
|
public boolean isEMIAmountVariation() {
|
||||||
return this.value.equals(LoanTermVariationType.EMI_AMOUNT.getValue());
|
return this.value.equals(LoanTermVariationType.EMI_AMOUNT.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isInterestRateVariation() {
|
||||||
|
return this.value.equals(LoanTermVariationType.INTEREST_RATE.getValue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-7
@@ -32,6 +32,7 @@ public class LoanScheduleRecalculationDTO {
|
|||||||
private final Map<LocalDate, Money> latePaymentMap;
|
private final Map<LocalDate, Money> latePaymentMap;
|
||||||
private final TreeMap<LocalDate, Money> compoundingMap;
|
private final TreeMap<LocalDate, Money> compoundingMap;
|
||||||
private final Map<LocalDate, Money> disburseDetailMap;
|
private final Map<LocalDate, Money> disburseDetailMap;
|
||||||
|
private final Money principalToBeScheduled;
|
||||||
private final Money outstandingBalance;
|
private final Money outstandingBalance;
|
||||||
private final Money outstandingBalanceAsPerRest;
|
private final Money outstandingBalanceAsPerRest;
|
||||||
private final List<LoanRepaymentScheduleInstallment> installments;
|
private final List<LoanRepaymentScheduleInstallment> installments;
|
||||||
@@ -44,9 +45,9 @@ public class LoanScheduleRecalculationDTO {
|
|||||||
final LocalDate actualRepaymentDate, final Money totalCumulativePrincipal, final Money totalCumulativeInterest,
|
final LocalDate actualRepaymentDate, final Money totalCumulativePrincipal, final Money totalCumulativeInterest,
|
||||||
final Money totalFeeChargesCharged, final Money totalPenaltyChargesCharged, final Money totalRepaymentExpected,
|
final Money totalFeeChargesCharged, final Money totalPenaltyChargesCharged, final Money totalRepaymentExpected,
|
||||||
final Money reducePrincipal, final Map<LocalDate, Money> principalPortionMap, final Map<LocalDate, Money> latePaymentMap,
|
final Money reducePrincipal, final Map<LocalDate, Money> principalPortionMap, final Map<LocalDate, Money> latePaymentMap,
|
||||||
final TreeMap<LocalDate, Money> compoundingMap, final Map<LocalDate, Money> disburseDetailMap, final Money outstandingBalance,
|
final TreeMap<LocalDate, Money> compoundingMap, final Map<LocalDate, Money> disburseDetailMap, Money principalToBeScheduled,
|
||||||
final Money outstandingBalanceAsPerRest, final List<LoanRepaymentScheduleInstallment> installments,
|
final Money outstandingBalance, final Money outstandingBalanceAsPerRest,
|
||||||
final Collection<RecalculationDetail> recalculationDetails,
|
final List<LoanRepaymentScheduleInstallment> installments, final Collection<RecalculationDetail> recalculationDetails,
|
||||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final LocalDate scheduleTillDate,
|
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final LocalDate scheduleTillDate,
|
||||||
final boolean partialUpdate) {
|
final boolean partialUpdate) {
|
||||||
this.periodNumber = periodNumber;
|
this.periodNumber = periodNumber;
|
||||||
@@ -63,6 +64,7 @@ public class LoanScheduleRecalculationDTO {
|
|||||||
this.latePaymentMap = latePaymentMap;
|
this.latePaymentMap = latePaymentMap;
|
||||||
this.compoundingMap = compoundingMap;
|
this.compoundingMap = compoundingMap;
|
||||||
this.disburseDetailMap = disburseDetailMap;
|
this.disburseDetailMap = disburseDetailMap;
|
||||||
|
this.principalToBeScheduled = principalToBeScheduled;
|
||||||
this.outstandingBalance = outstandingBalance;
|
this.outstandingBalance = outstandingBalance;
|
||||||
this.outstandingBalanceAsPerRest = outstandingBalanceAsPerRest;
|
this.outstandingBalanceAsPerRest = outstandingBalanceAsPerRest;
|
||||||
this.installments = installments;
|
this.installments = installments;
|
||||||
@@ -77,14 +79,15 @@ public class LoanScheduleRecalculationDTO {
|
|||||||
final Money totalCumulativeInterest, final Money totalFeeChargesCharged, final Money totalPenaltyChargesCharged,
|
final Money totalCumulativeInterest, final Money totalFeeChargesCharged, final Money totalPenaltyChargesCharged,
|
||||||
final Money totalRepaymentExpected, final Money reducePrincipal, final Map<LocalDate, Money> principalPortionMap,
|
final Money totalRepaymentExpected, final Money reducePrincipal, final Map<LocalDate, Money> principalPortionMap,
|
||||||
final Map<LocalDate, Money> latePaymentMap, final TreeMap<LocalDate, Money> compoundingMap,
|
final Map<LocalDate, Money> latePaymentMap, final TreeMap<LocalDate, Money> compoundingMap,
|
||||||
final Map<LocalDate, Money> disburseDetailMap, final Money outstandingBalance, final Money outstandingBalanceAsPerRest,
|
final Map<LocalDate, Money> disburseDetailMap, Money principalToBeScheduled, final Money outstandingBalance,
|
||||||
final List<LoanRepaymentScheduleInstallment> installments, final Collection<RecalculationDetail> recalculationDetails,
|
final Money outstandingBalanceAsPerRest, final List<LoanRepaymentScheduleInstallment> installments,
|
||||||
|
final Collection<RecalculationDetail> recalculationDetails,
|
||||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final LocalDate scheduleTillDate) {
|
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final LocalDate scheduleTillDate) {
|
||||||
final boolean partialUpdate = true;
|
final boolean partialUpdate = true;
|
||||||
return new LoanScheduleRecalculationDTO(periodNumber, instalmentNumber, periodStartDate, actualRepaymentDate,
|
return new LoanScheduleRecalculationDTO(periodNumber, instalmentNumber, periodStartDate, actualRepaymentDate,
|
||||||
totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
|
totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
|
||||||
totalRepaymentExpected, reducePrincipal, principalPortionMap, latePaymentMap, compoundingMap, disburseDetailMap,
|
totalRepaymentExpected, reducePrincipal, principalPortionMap, latePaymentMap, compoundingMap, disburseDetailMap,
|
||||||
outstandingBalance, outstandingBalanceAsPerRest, installments, recalculationDetails,
|
principalToBeScheduled, outstandingBalance, outstandingBalanceAsPerRest, installments, recalculationDetails,
|
||||||
loanRepaymentScheduleTransactionProcessor, scheduleTillDate, partialUpdate);
|
loanRepaymentScheduleTransactionProcessor, scheduleTillDate, partialUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,6 +108,7 @@ public class LoanScheduleRecalculationDTO {
|
|||||||
final Map<LocalDate, Money> latePaymentMap = null;
|
final Map<LocalDate, Money> latePaymentMap = null;
|
||||||
final TreeMap<LocalDate, Money> compoundingMap = null;
|
final TreeMap<LocalDate, Money> compoundingMap = null;
|
||||||
final Map<LocalDate, Money> disburseDetailMap = null;
|
final Map<LocalDate, Money> disburseDetailMap = null;
|
||||||
|
final Money principalToBeScheduled = null;
|
||||||
final Money outstandingBalance = null;
|
final Money outstandingBalance = null;
|
||||||
final Money outstandingBalanceAsPerRest = null;
|
final Money outstandingBalanceAsPerRest = null;
|
||||||
final List<LoanRepaymentScheduleInstallment> installments = null;
|
final List<LoanRepaymentScheduleInstallment> installments = null;
|
||||||
@@ -112,7 +116,7 @@ public class LoanScheduleRecalculationDTO {
|
|||||||
return new LoanScheduleRecalculationDTO(periodNumber, instalmentNumber, periodStartDate, actualRepaymentDate,
|
return new LoanScheduleRecalculationDTO(periodNumber, instalmentNumber, periodStartDate, actualRepaymentDate,
|
||||||
totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
|
totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
|
||||||
totalRepaymentExpected, reducePrincipal, principalPortionMap, latePaymentMap, compoundingMap, disburseDetailMap,
|
totalRepaymentExpected, reducePrincipal, principalPortionMap, latePaymentMap, compoundingMap, disburseDetailMap,
|
||||||
outstandingBalance, outstandingBalanceAsPerRest, installments, recalculationDetails,
|
principalToBeScheduled, outstandingBalance, outstandingBalanceAsPerRest, installments, recalculationDetails,
|
||||||
loanRepaymentScheduleTransactionProcessor, scheduleTillDate, partialUpdate);
|
loanRepaymentScheduleTransactionProcessor, scheduleTillDate, partialUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,4 +204,9 @@ public class LoanScheduleRecalculationDTO {
|
|||||||
return this.periodStartDate;
|
return this.periodStartDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Money getPrincipalToBeScheduled() {
|
||||||
|
return this.principalToBeScheduled;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+62
-19
@@ -28,8 +28,10 @@ import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
|||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
||||||
import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
|
import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
|
||||||
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRateDTO;
|
||||||
import org.mifosplatform.portfolio.loanaccount.data.DisbursementData;
|
import org.mifosplatform.portfolio.loanaccount.data.DisbursementData;
|
||||||
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
|
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.data.LoanTermVariationsData;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||||
@@ -181,6 +183,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
extendTermForDailyRepayments = true;
|
extendTermForDailyRepayments = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for applying variations
|
||||||
|
Collection<LoanTermVariationsData> loanTermVariations = new ArrayList<>(loanApplicationTerms.getLoanTermVariations());
|
||||||
|
|
||||||
// this block is to start the schedule generation from specified date
|
// this block is to start the schedule generation from specified date
|
||||||
if (loanScheduleRecalculationDTO != null && loanScheduleRecalculationDTO.isPartialUpdate()) {
|
if (loanScheduleRecalculationDTO != null && loanScheduleRecalculationDTO.isPartialUpdate()) {
|
||||||
periodNumber = loanScheduleRecalculationDTO.getPeriodNumber();
|
periodNumber = loanScheduleRecalculationDTO.getPeriodNumber();
|
||||||
@@ -206,6 +211,16 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
outstandingBalanceAsPerRest = loanScheduleRecalculationDTO.getOutstandingBalanceAsPerRest();
|
outstandingBalanceAsPerRest = loanScheduleRecalculationDTO.getOutstandingBalanceAsPerRest();
|
||||||
installments.clear();
|
installments.clear();
|
||||||
installments.addAll(loanScheduleRecalculationDTO.getInstallments());
|
installments.addAll(loanScheduleRecalculationDTO.getInstallments());
|
||||||
|
if (loanApplicationTerms.isMultiDisburseLoan()) {
|
||||||
|
principalToBeScheduled = loanScheduleRecalculationDTO.getPrincipalToBeScheduled();
|
||||||
|
loanApplicationTerms.setPrincipal(principalToBeScheduled);
|
||||||
|
}
|
||||||
|
for (LoanTermVariationsData variation : loanApplicationTerms.getLoanTermVariations()) {
|
||||||
|
if (variation.getTermVariationType().isInterestRateVariation() && variation.isApplicable(periodStartDate, periodNumber)
|
||||||
|
&& variation.getTermValue() != null) {
|
||||||
|
loanApplicationTerms.updateAnnualNominalInterestRate(variation.getTermValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!outstandingBalance.isZero() || !disburseDetailMap.isEmpty()) {
|
while (!outstandingBalance.isZero() || !disburseDetailMap.isEmpty()) {
|
||||||
@@ -241,6 +256,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
Collection<RecalculationDetail> applicableTransactions = getApplicableTransactionsForPeriod(loanApplicationTerms,
|
Collection<RecalculationDetail> applicableTransactions = getApplicableTransactionsForPeriod(loanApplicationTerms,
|
||||||
scheduledDueDate, transactions);
|
scheduledDueDate, transactions);
|
||||||
|
|
||||||
|
Collection<LoanTermVariationsData> applicableVariations = getApplicableTermVariationsForPeriod(periodStartDate,
|
||||||
|
scheduledDueDate, periodNumber, loanTermVariations);
|
||||||
|
|
||||||
double interestCalculationGraceOnRepaymentPeriodFraction = this.paymentPeriodsInOneYearCalculator
|
double interestCalculationGraceOnRepaymentPeriodFraction = this.paymentPeriodsInOneYearCalculator
|
||||||
.calculatePortionOfRepaymentPeriodInterestChargingGrace(periodStartDateApplicableForInterest, scheduledDueDate,
|
.calculatePortionOfRepaymentPeriodInterestChargingGrace(periodStartDateApplicableForInterest, scheduledDueDate,
|
||||||
loanApplicationTerms.getInterestChargedFromLocalDate(), loanApplicationTerms.getLoanTermPeriodFrequencyType(),
|
loanApplicationTerms.getInterestChargedFromLocalDate(), loanApplicationTerms.getLoanTermPeriodFrequencyType(),
|
||||||
@@ -320,7 +338,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
outstandingBalanceAsPerRest, loanApplicationTerms, periodNumber, mc,
|
outstandingBalanceAsPerRest, loanApplicationTerms, periodNumber, mc,
|
||||||
mergeVariationsToMap(principalPortionMap, latePaymentMap, disburseDetailMap, compoundingMap),
|
mergeVariationsToMap(principalPortionMap, latePaymentMap, disburseDetailMap, compoundingMap),
|
||||||
compoundingMap, periodStartDateApplicableForInterest, detail.getTransactionDate(),
|
compoundingMap, periodStartDateApplicableForInterest, detail.getTransactionDate(),
|
||||||
daysInPeriodApplicableForInterest);
|
daysInPeriodApplicableForInterest, applicableVariations);
|
||||||
interestForThisinstallment = principalInterestForThisPeriod.interest();
|
interestForThisinstallment = principalInterestForThisPeriod.interest();
|
||||||
|
|
||||||
totalOutstandingInterestPaymentDueToGrace = principalInterestForThisPeriod.interestPaymentDueToGrace();
|
totalOutstandingInterestPaymentDueToGrace = principalInterestForThisPeriod.interestPaymentDueToGrace();
|
||||||
@@ -461,7 +479,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
mc,
|
mc,
|
||||||
mergeVariationsToMap(principalPortionMap, latePaymentMap, disburseDetailMap, compoundingMap),
|
mergeVariationsToMap(principalPortionMap, latePaymentMap, disburseDetailMap, compoundingMap),
|
||||||
compoundingMap, periodStartDateApplicableForInterest, calculateTill,
|
compoundingMap, periodStartDateApplicableForInterest, calculateTill,
|
||||||
daysInPeriodApplicableForInterest);
|
daysInPeriodApplicableForInterest, applicableVariations);
|
||||||
if (!principalInterestForThisPeriod.interest()
|
if (!principalInterestForThisPeriod.interest()
|
||||||
.plus(principalInterestForThisPeriod.interestPaymentDueToGrace()).plus(outstandingBalance)
|
.plus(principalInterestForThisPeriod.interestPaymentDueToGrace()).plus(outstandingBalance)
|
||||||
.isGreaterThan(unprocessed)) {
|
.isGreaterThan(unprocessed)) {
|
||||||
@@ -528,7 +546,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
totalCumulativePrincipal.minus(reducePrincipal), totalCumulativeInterest, totalInterestChargedForFullLoanTerm,
|
totalCumulativePrincipal.minus(reducePrincipal), totalCumulativeInterest, totalInterestChargedForFullLoanTerm,
|
||||||
totalOutstandingInterestPaymentDueToGrace, outstandingBalanceAsPerRest, loanApplicationTerms, periodNumber, mc,
|
totalOutstandingInterestPaymentDueToGrace, outstandingBalanceAsPerRest, loanApplicationTerms, periodNumber, mc,
|
||||||
mergeVariationsToMap(principalPortionMap, latePaymentMap, disburseDetailMap, compoundingMap), compoundingMap,
|
mergeVariationsToMap(principalPortionMap, latePaymentMap, disburseDetailMap, compoundingMap), compoundingMap,
|
||||||
periodStartDateApplicableForInterest, scheduledDueDate, daysInPeriodApplicableForInterest);
|
periodStartDateApplicableForInterest, scheduledDueDate, daysInPeriodApplicableForInterest, applicableVariations);
|
||||||
|
|
||||||
if (loanApplicationTerms.getFixedEmiAmount() != null
|
if (loanApplicationTerms.getFixedEmiAmount() != null
|
||||||
&& loanApplicationTerms.getFixedEmiAmount().compareTo(principalInterestForThisPeriod.interest().getAmount()) != 1) {
|
&& loanApplicationTerms.getFixedEmiAmount().compareTo(principalInterestForThisPeriod.interest().getAmount()) != 1) {
|
||||||
@@ -648,7 +666,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
periodNumber, mc,
|
periodNumber, mc,
|
||||||
mergeVariationsToMap(principalPortionMap, latePaymentMap, disburseDetailMap, compoundingMap),
|
mergeVariationsToMap(principalPortionMap, latePaymentMap, disburseDetailMap, compoundingMap),
|
||||||
compoundingMap, periodStartDateApplicableForInterest, calculateTill,
|
compoundingMap, periodStartDateApplicableForInterest, calculateTill,
|
||||||
daysInPeriodApplicableForInterest);
|
daysInPeriodApplicableForInterest, applicableVariations);
|
||||||
Money diff = interestForThisinstallment.minus(interestTillDate.interest());
|
Money diff = interestForThisinstallment.minus(interestTillDate.interest());
|
||||||
if (!outstandingBalance.minus(diff).isGreaterThanZero()) {
|
if (!outstandingBalance.minus(diff).isGreaterThanZero()) {
|
||||||
outstandingBalance = outstandingBalance.minus(diff);
|
outstandingBalance = outstandingBalance.minus(diff);
|
||||||
@@ -860,6 +878,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
double interestCalculationGraceOnRepaymentPeriodFraction = Double.valueOf(0);
|
double interestCalculationGraceOnRepaymentPeriodFraction = Double.valueOf(0);
|
||||||
int periodNumberTemp = 1;
|
int periodNumberTemp = 1;
|
||||||
LocalDate lastRestDate = getNextRestScheduleDate(currentDate.minusDays(1), loanApplicationTerms, holidayDetailDTO);
|
LocalDate lastRestDate = getNextRestScheduleDate(currentDate.minusDays(1), loanApplicationTerms, holidayDetailDTO);
|
||||||
|
Collection<LoanTermVariationsData> applicableVariations = loanApplicationTerms.getLoanTermVariations();
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|
||||||
actualRepaymentDate = this.scheduledDateGenerator.generateNextRepaymentDate(actualRepaymentDate, loanApplicationTerms,
|
actualRepaymentDate = this.scheduledDateGenerator.generateNextRepaymentDate(actualRepaymentDate, loanApplicationTerms,
|
||||||
@@ -890,7 +910,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
totalInterest.zero(), totalInterest.zero(), totalInterest.zero(), totalInterest.zero(), outstanding,
|
totalInterest.zero(), totalInterest.zero(), totalInterest.zero(), totalInterest.zero(), outstanding,
|
||||||
loanApplicationTerms, periodNumberTemp, mc,
|
loanApplicationTerms, periodNumberTemp, mc,
|
||||||
mergeVariationsToMap(principalPortionMap, latePaymentMap, disburseDetailsMap, compoundingMap), compoundingMap,
|
mergeVariationsToMap(principalPortionMap, latePaymentMap, disburseDetailsMap, compoundingMap), compoundingMap,
|
||||||
periodStartDate, detail.getTransactionDate(), daysInPeriod);
|
periodStartDate, detail.getTransactionDate(), daysInPeriod, applicableVariations);
|
||||||
|
|
||||||
Money interest = principalInterestForThisPeriod.interest();
|
Money interest = principalInterestForThisPeriod.interest();
|
||||||
totalInterest = totalInterest.plus(interest);
|
totalInterest = totalInterest.plus(interest);
|
||||||
@@ -922,7 +942,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
totalInterest.zero(), totalInterest.zero(), totalInterest.zero(), outstanding, loanApplicationTerms,
|
totalInterest.zero(), totalInterest.zero(), totalInterest.zero(), outstanding, loanApplicationTerms,
|
||||||
periodNumberTemp, mc,
|
periodNumberTemp, mc,
|
||||||
mergeVariationsToMap(principalPortionMap, latePaymentMap, disburseDetailsMap, compoundingMap), compoundingMap,
|
mergeVariationsToMap(principalPortionMap, latePaymentMap, disburseDetailsMap, compoundingMap), compoundingMap,
|
||||||
periodStartDate, actualRepaymentDate, daysInPeriod);
|
periodStartDate, actualRepaymentDate, daysInPeriod, applicableVariations);
|
||||||
Money interest = principalInterestForThisPeriod.interest();
|
Money interest = principalInterestForThisPeriod.interest();
|
||||||
totalInterest = totalInterest.plus(interest);
|
totalInterest = totalInterest.plus(interest);
|
||||||
if (loanApplicationTerms.getInterestRecalculationCompoundingMethod().isInterestCompoundingEnabled()) {
|
if (loanApplicationTerms.getInterestRecalculationCompoundingMethod().isInterestCompoundingEnabled()) {
|
||||||
@@ -959,6 +979,18 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
return applicableTransactions;
|
return applicableTransactions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Collection<LoanTermVariationsData> getApplicableTermVariationsForPeriod(final LocalDate fromDate, final LocalDate dueDate,
|
||||||
|
final int installmentNumber, final Collection<LoanTermVariationsData> variations) {
|
||||||
|
Collection<LoanTermVariationsData> applicableVariations = new ArrayList<>();
|
||||||
|
for (LoanTermVariationsData detail : variations) {
|
||||||
|
if (detail.isApplicable(fromDate, dueDate, installmentNumber)) {
|
||||||
|
applicableVariations.add(detail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
variations.removeAll(applicableVariations);
|
||||||
|
return applicableVariations;
|
||||||
|
}
|
||||||
|
|
||||||
private List<LoanTransaction> createCurrentTransactionList(RecalculationDetail detail) {
|
private List<LoanTransaction> createCurrentTransactionList(RecalculationDetail detail) {
|
||||||
List<LoanTransaction> currentTransactions = new ArrayList<>(2);
|
List<LoanTransaction> currentTransactions = new ArrayList<>(2);
|
||||||
currentTransactions.add(detail.getTransaction());
|
currentTransactions.add(detail.getTransaction());
|
||||||
@@ -1340,7 +1372,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
@Override
|
@Override
|
||||||
public LoanRescheduleModel reschedule(final MathContext mathContext, final LoanRescheduleRequest loanRescheduleRequest,
|
public LoanRescheduleModel reschedule(final MathContext mathContext, final LoanRescheduleRequest loanRescheduleRequest,
|
||||||
final ApplicationCurrency applicationCurrency, final HolidayDetailDTO holidayDetailDTO,
|
final ApplicationCurrency applicationCurrency, final HolidayDetailDTO holidayDetailDTO,
|
||||||
final CalendarInstance restCalendarInstance, final CalendarInstance compoundingCalendarInstance, final Calendar loanCalendar) {
|
final CalendarInstance restCalendarInstance, final CalendarInstance compoundingCalendarInstance, final Calendar loanCalendar,
|
||||||
|
final FloatingRateDTO floatingRateDTO) {
|
||||||
|
|
||||||
final Loan loan = loanRescheduleRequest.getLoan();
|
final Loan loan = loanRescheduleRequest.getLoan();
|
||||||
final LoanSummary loanSummary = loan.getSummary();
|
final LoanSummary loanSummary = loan.getSummary();
|
||||||
@@ -1482,7 +1515,10 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
|
|
||||||
// get the loan application terms from the Loan object
|
// get the loan application terms from the Loan object
|
||||||
final LoanApplicationTerms loanApplicationTerms = loan.getLoanApplicationTerms(applicationCurrency, restCalendarInstance,
|
final LoanApplicationTerms loanApplicationTerms = loan.getLoanApplicationTerms(applicationCurrency, restCalendarInstance,
|
||||||
compoundingCalendarInstance, loanCalendar);
|
compoundingCalendarInstance, loanCalendar, floatingRateDTO);
|
||||||
|
|
||||||
|
// for applying variations
|
||||||
|
Collection<LoanTermVariationsData> loanTermVariations = new ArrayList<>(loanApplicationTerms.getLoanTermVariations());
|
||||||
|
|
||||||
// update the number of repayments
|
// update the number of repayments
|
||||||
loanApplicationTerms.updateNumberOfRepayments(numberOfRepayments);
|
loanApplicationTerms.updateNumberOfRepayments(numberOfRepayments);
|
||||||
@@ -1551,12 +1587,16 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
// principal outstanding
|
// principal outstanding
|
||||||
loanApplicationTerms.setPrincipal(totalPrincipalOutstanding);
|
loanApplicationTerms.setPrincipal(totalPrincipalOutstanding);
|
||||||
|
|
||||||
|
// for applying variations
|
||||||
|
Collection<LoanTermVariationsData> applicableVariations = getApplicableTermVariationsForPeriod(installmentFromDate,
|
||||||
|
adjustedInstallmentDueDate, periodNumber, loanTermVariations);
|
||||||
|
|
||||||
// determine the interest & principal for the period
|
// determine the interest & principal for the period
|
||||||
PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
|
PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
|
||||||
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction,
|
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction,
|
||||||
totalCumulativePrincipal, totalCumulativeInterest, totalInterestChargedForFullLoanTerm,
|
totalCumulativePrincipal, totalCumulativeInterest, totalInterestChargedForFullLoanTerm,
|
||||||
totalOutstandingInterestPaymentDueToGrace, outstandingBalance, loanApplicationTerms, periodNumber, mathContext,
|
totalOutstandingInterestPaymentDueToGrace, outstandingBalance, loanApplicationTerms, periodNumber, mathContext,
|
||||||
null, null, installmentFromDate, adjustedInstallmentDueDate, daysInInstallment);
|
null, null, installmentFromDate, adjustedInstallmentDueDate, daysInInstallment, applicableVariations);
|
||||||
|
|
||||||
// update the interest due for the period
|
// update the interest due for the period
|
||||||
period.updateInterestDue(principalInterestForThisPeriod.interest());
|
period.updateInterestDue(principalInterestForThisPeriod.interest());
|
||||||
@@ -1575,7 +1615,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
interestCalculationGraceOnRepaymentPeriodFraction, totalCumulativePrincipal, totalCumulativeInterest,
|
interestCalculationGraceOnRepaymentPeriodFraction, totalCumulativePrincipal, totalCumulativeInterest,
|
||||||
totalInterestChargedForFullLoanTerm, totalOutstandingInterestPaymentDueToGrace, outstandingBalance,
|
totalInterestChargedForFullLoanTerm, totalOutstandingInterestPaymentDueToGrace, outstandingBalance,
|
||||||
loanApplicationTerms, periodNumber, mathContext, null, null, installmentFromDate, adjustedInstallmentDueDate,
|
loanApplicationTerms, periodNumber, mathContext, null, null, installmentFromDate, adjustedInstallmentDueDate,
|
||||||
daysInInstallment);
|
daysInInstallment, applicableVariations);
|
||||||
|
|
||||||
period.updatePrincipalDue(principalInterestForThisPeriod.principal());
|
period.updatePrincipalDue(principalInterestForThisPeriod.principal());
|
||||||
|
|
||||||
@@ -1642,7 +1682,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
double interestCalculationGraceOnRepaymentPeriodFraction, Money totalCumulativePrincipal, Money totalCumulativeInterest,
|
double interestCalculationGraceOnRepaymentPeriodFraction, Money totalCumulativePrincipal, Money totalCumulativeInterest,
|
||||||
Money totalInterestDueForLoan, Money cumulatingInterestPaymentDueToGrace, Money outstandingBalance,
|
Money totalInterestDueForLoan, Money cumulatingInterestPaymentDueToGrace, Money outstandingBalance,
|
||||||
LoanApplicationTerms loanApplicationTerms, int periodNumber, MathContext mc, TreeMap<LocalDate, Money> principalVariation,
|
LoanApplicationTerms loanApplicationTerms, int periodNumber, MathContext mc, TreeMap<LocalDate, Money> principalVariation,
|
||||||
Map<LocalDate, Money> compoundingMap, LocalDate periodStartDate, LocalDate periodEndDate, int daysForInterestInFullPeriod);
|
Map<LocalDate, Money> compoundingMap, LocalDate periodStartDate, LocalDate periodEndDate, int daysForInterestInFullPeriod,
|
||||||
|
Collection<LoanTermVariationsData> termVariations);
|
||||||
|
|
||||||
protected final boolean isLastRepaymentPeriod(final int numberOfRepayments, final int periodNumber) {
|
protected final boolean isLastRepaymentPeriod(final int numberOfRepayments, final int periodNumber) {
|
||||||
return periodNumber == numberOfRepayments;
|
return periodNumber == numberOfRepayments;
|
||||||
@@ -1891,8 +1932,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
periods, chargesDueAtTimeOfDisbursement, disburseDetailMap, true);
|
periods, chargesDueAtTimeOfDisbursement, disburseDetailMap, true);
|
||||||
outstandingBalance = outstandingBalance.zero().plus(disburseAmt);
|
outstandingBalance = outstandingBalance.zero().plus(disburseAmt);
|
||||||
outstandingBalanceAsPerRest = outstandingBalance;
|
outstandingBalanceAsPerRest = outstandingBalance;
|
||||||
|
principalToBeScheduled = principalToBeScheduled.zero().plus(disburseAmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block process the installment and creates the period if it falls
|
// Block process the installment and creates the period if it falls
|
||||||
// before reschedule from date
|
// before reschedule from date
|
||||||
// This will create the recalculation details by applying the
|
// This will create the recalculation details by applying the
|
||||||
@@ -1914,7 +1956,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
}
|
}
|
||||||
periodNumber++;
|
periodNumber++;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<LocalDate, Money> disburseDetail : disburseDetailMap.entrySet()) {
|
for (Map.Entry<LocalDate, Money> disburseDetail : disburseDetailMap.entrySet()) {
|
||||||
if (disburseDetail.getKey().isAfter(installment.getFromDate())
|
if (disburseDetail.getKey().isAfter(installment.getFromDate())
|
||||||
&& !disburseDetail.getKey().isAfter(installment.getDueDate())) {
|
&& !disburseDetail.getKey().isAfter(installment.getDueDate())) {
|
||||||
@@ -1926,6 +1968,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
// updates actual outstanding balance with new
|
// updates actual outstanding balance with new
|
||||||
// disbursement detail
|
// disbursement detail
|
||||||
outstandingBalance = outstandingBalance.plus(disburseDetail.getValue());
|
outstandingBalance = outstandingBalance.plus(disburseDetail.getValue());
|
||||||
|
principalToBeScheduled = principalToBeScheduled.plus(disburseDetail.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2001,12 +2044,12 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
|
|
||||||
// for partial schedule generation
|
// for partial schedule generation
|
||||||
if (!newRepaymentScheduleInstallments.isEmpty()) {
|
if (!newRepaymentScheduleInstallments.isEmpty()) {
|
||||||
loanScheduleRecalculationDTO = LoanScheduleRecalculationDTO
|
loanScheduleRecalculationDTO = LoanScheduleRecalculationDTO.createLoanScheduleDTOForPartialUpdate(periodNumber,
|
||||||
.createLoanScheduleDTOForPartialUpdate(periodNumber, instalmentNumber, periodStartDate, actualRepaymentDate,
|
instalmentNumber, periodStartDate, actualRepaymentDate, totalCumulativePrincipal, totalCumulativeInterest,
|
||||||
totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
|
totalFeeChargesCharged, totalPenaltyChargesCharged, totalRepaymentExpected, reducePrincipal, principalPortionMap,
|
||||||
totalRepaymentExpected, reducePrincipal, principalPortionMap, latePaymentMap, compoundingMap,
|
latePaymentMap, compoundingMap, disburseDetailMap, principalToBeScheduled, outstandingBalance,
|
||||||
disburseDetailMap, outstandingBalance, outstandingBalanceAsPerRest, newRepaymentScheduleInstallments,
|
outstandingBalanceAsPerRest, newRepaymentScheduleInstallments, recalculationDetails,
|
||||||
recalculationDetails, loanRepaymentScheduleTransactionProcessor, scheduleTillDate);
|
loanRepaymentScheduleTransactionProcessor, scheduleTillDate);
|
||||||
retainedInstallments.addAll(newRepaymentScheduleInstallments);
|
retainedInstallments.addAll(newRepaymentScheduleInstallments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+25
-4
@@ -5,7 +5,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.mifosplatform.portfolio.loanaccount.loanschedule.domain;
|
package org.mifosplatform.portfolio.loanaccount.loanschedule.domain;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
@@ -13,6 +16,7 @@ import org.joda.time.Days;
|
|||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.data.LoanTermVariationsData;
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
|
import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -49,7 +53,8 @@ public class DecliningBalanceInterestLoanScheduleGenerator extends AbstractLoanS
|
|||||||
@SuppressWarnings("unused") final Money totalInterestDueForLoan, final Money cumulatingInterestPaymentDueToGrace,
|
@SuppressWarnings("unused") final Money totalInterestDueForLoan, final Money cumulatingInterestPaymentDueToGrace,
|
||||||
final Money outstandingBalance, final LoanApplicationTerms loanApplicationTerms, final int periodNumber, final MathContext mc,
|
final Money outstandingBalance, final LoanApplicationTerms loanApplicationTerms, final int periodNumber, final MathContext mc,
|
||||||
final TreeMap<LocalDate, Money> principalVariation, final Map<LocalDate, Money> compoundingMap,
|
final TreeMap<LocalDate, Money> principalVariation, final Map<LocalDate, Money> compoundingMap,
|
||||||
final LocalDate periodStartDate, final LocalDate periodEndDate, final int daysForInterestInFullPeriod) {
|
final LocalDate periodStartDate, final LocalDate periodEndDate, final int daysForInterestInFullPeriod,
|
||||||
|
final Collection<LoanTermVariationsData> termVariations) {
|
||||||
|
|
||||||
LocalDate interestStartDate = periodStartDate;
|
LocalDate interestStartDate = periodStartDate;
|
||||||
Money interestForThisInstallment = totalCumulativePrincipal.zero();
|
Money interestForThisInstallment = totalCumulativePrincipal.zero();
|
||||||
@@ -58,6 +63,20 @@ public class DecliningBalanceInterestLoanScheduleGenerator extends AbstractLoanS
|
|||||||
Money balanceForInterestCalculation = outstandingBalance;
|
Money balanceForInterestCalculation = outstandingBalance;
|
||||||
Money cumulatingInterestDueToGrace = cumulatingInterestPaymentDueToGrace;
|
Money cumulatingInterestDueToGrace = cumulatingInterestPaymentDueToGrace;
|
||||||
final int daysInPeriodApplicableForInterest = Days.daysBetween(periodStartDate, periodEndDate).getDays();
|
final int daysInPeriodApplicableForInterest = Days.daysBetween(periodStartDate, periodEndDate).getDays();
|
||||||
|
Map<LocalDate, BigDecimal> interestRates = new HashMap<>(termVariations.size());
|
||||||
|
for (LoanTermVariationsData loanTermVariation : termVariations) {
|
||||||
|
if (loanTermVariation.getTermVariationType().isInterestRateVariation()
|
||||||
|
&& loanTermVariation.isApplicable(periodStartDate, periodEndDate, periodNumber)) {
|
||||||
|
LocalDate fromDate = loanTermVariation.getTermApplicableFrom();
|
||||||
|
if (fromDate == null) {
|
||||||
|
fromDate = periodStartDate;
|
||||||
|
}
|
||||||
|
interestRates.put(fromDate, loanTermVariation.getTermValue());
|
||||||
|
if (!principalVariation.containsKey(fromDate)) {
|
||||||
|
principalVariation.put(fromDate, balanceForInterestCalculation.zero());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (principalVariation != null) {
|
if (principalVariation != null) {
|
||||||
// identifies rest date after current date for reducing all
|
// identifies rest date after current date for reducing all
|
||||||
// compounding
|
// compounding
|
||||||
@@ -102,6 +121,9 @@ public class DecliningBalanceInterestLoanScheduleGenerator extends AbstractLoanS
|
|||||||
compoundedMoney = compoundedMoney.plus(interestToBeCompounded).plus(compoundFee);
|
compoundedMoney = compoundedMoney.plus(interestToBeCompounded).plus(compoundFee);
|
||||||
}
|
}
|
||||||
balanceForInterestCalculation = balanceForInterestCalculation.plus(principal.getValue()).plus(compoundFee);
|
balanceForInterestCalculation = balanceForInterestCalculation.plus(principal.getValue()).plus(compoundFee);
|
||||||
|
if (interestRates.containsKey(principal.getKey())) {
|
||||||
|
loanApplicationTerms.updateAnnualNominalInterestRate(interestRates.get(principal.getKey()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -125,9 +147,8 @@ public class DecliningBalanceInterestLoanScheduleGenerator extends AbstractLoanS
|
|||||||
} else {
|
} else {
|
||||||
interestForThisInstallment = interestForThisInstallment.plus(calculateInterestForDays(daysForInterestInFullPeriod, result
|
interestForThisInstallment = interestForThisInstallment.plus(calculateInterestForDays(daysForInterestInFullPeriod, result
|
||||||
.interest().getAmount(), interestForDays));
|
.interest().getAmount(), interestForDays));
|
||||||
cumulatingInterestDueToGrace = cumulatingInterestDueToGrace.plus(calculateInterestForDays(
|
cumulatingInterestDueToGrace = cumulatingInterestDueToGrace.plus(calculateInterestForDays(daysForInterestInFullPeriod, result
|
||||||
daysForInterestInFullPeriod, result.interestPaymentDueToGrace().minus(cumulatingInterestDueToGrace)
|
.interestPaymentDueToGrace().minus(cumulatingInterestDueToGrace).getAmount(), interestForDays));
|
||||||
.getAmount(), interestForDays));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Money interestForPeriod = interestForThisInstallment;
|
Money interestForPeriod = interestForThisInstallment;
|
||||||
|
|||||||
+3
-1
@@ -6,12 +6,14 @@
|
|||||||
package org.mifosplatform.portfolio.loanaccount.loanschedule.domain;
|
package org.mifosplatform.portfolio.loanaccount.loanschedule.domain;
|
||||||
|
|
||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
import org.joda.time.Days;
|
import org.joda.time.Days;
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.data.LoanTermVariationsData;
|
||||||
|
|
||||||
public class FlatInterestLoanScheduleGenerator extends AbstractLoanScheduleGenerator {
|
public class FlatInterestLoanScheduleGenerator extends AbstractLoanScheduleGenerator {
|
||||||
|
|
||||||
@@ -22,7 +24,7 @@ public class FlatInterestLoanScheduleGenerator extends AbstractLoanScheduleGener
|
|||||||
final Money outstandingBalance, final LoanApplicationTerms loanApplicationTerms, final int periodNumber, final MathContext mc,
|
final Money outstandingBalance, final LoanApplicationTerms loanApplicationTerms, final int periodNumber, final MathContext mc,
|
||||||
@SuppressWarnings("unused") TreeMap<LocalDate, Money> principalVariation,
|
@SuppressWarnings("unused") TreeMap<LocalDate, Money> principalVariation,
|
||||||
@SuppressWarnings("unused") Map<LocalDate, Money> compoundingMap, LocalDate periodStartDate, LocalDate periodEndDate,
|
@SuppressWarnings("unused") Map<LocalDate, Money> compoundingMap, LocalDate periodStartDate, LocalDate periodEndDate,
|
||||||
@SuppressWarnings("unused") int daysForInterestInFullPeriod) {
|
@SuppressWarnings("unused") int daysForInterestInFullPeriod, @SuppressWarnings("unused") Collection<LoanTermVariationsData> termVariations) {
|
||||||
final int daysInPeriodApplicableForInterest = Days.daysBetween(periodStartDate, periodEndDate).getDays();
|
final int daysInPeriodApplicableForInterest = Days.daysBetween(periodStartDate, periodEndDate).getDays();
|
||||||
Money principalForThisInstallment = loanApplicationTerms.calculateTotalPrincipalForPeriod(calculator,
|
Money principalForThisInstallment = loanApplicationTerms.calculateTotalPrincipalForPeriod(calculator,
|
||||||
daysInPeriodApplicableForInterest, outstandingBalance, periodNumber, mc, null);
|
daysInPeriodApplicableForInterest, outstandingBalance, periodNumber, mc, null);
|
||||||
|
|||||||
+21
-37
@@ -7,6 +7,7 @@ package org.mifosplatform.portfolio.loanaccount.loanschedule.domain;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -151,6 +152,8 @@ public final class LoanApplicationTerms {
|
|||||||
|
|
||||||
private Money approvedPrincipal = null;
|
private Money approvedPrincipal = null;
|
||||||
|
|
||||||
|
private final Collection<LoanTermVariationsData> loanTermVariations;
|
||||||
|
|
||||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
||||||
final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery,
|
final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery,
|
||||||
final PeriodFrequencyType repaymentPeriodFrequencyType, Integer nthDay, DayOfWeekType weekDayType,
|
final PeriodFrequencyType repaymentPeriodFrequencyType, Integer nthDay, DayOfWeekType weekDayType,
|
||||||
@@ -168,7 +171,7 @@ public final class LoanApplicationTerms {
|
|||||||
final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
|
final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
|
||||||
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
|
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
|
||||||
final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy, final Calendar loanCalendar,
|
final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy, final Calendar loanCalendar,
|
||||||
BigDecimal approvedAmount) {
|
BigDecimal approvedAmount, Collection<LoanTermVariationsData> loanTermVariations) {
|
||||||
|
|
||||||
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
||||||
final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null;
|
final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null;
|
||||||
@@ -180,7 +183,7 @@ public final class LoanApplicationTerms {
|
|||||||
disbursementDatas, maxOutstandingBalance, emiAmountVariations, graceOnArrearsAgeing, daysInMonthType, daysInYearType,
|
disbursementDatas, maxOutstandingBalance, emiAmountVariations, graceOnArrearsAgeing, daysInMonthType, daysInYearType,
|
||||||
isInterestRecalculationEnabled, rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance,
|
isInterestRecalculationEnabled, rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance,
|
||||||
recalculationFrequencyType, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment,
|
recalculationFrequencyType, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment,
|
||||||
installmentAmountInMultiplesOf, preClosureInterestCalculationStrategy, loanCalendar, approvedAmount);
|
installmentAmountInMultiplesOf, preClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
||||||
@@ -195,7 +198,8 @@ public final class LoanApplicationTerms {
|
|||||||
final InterestRecalculationCompoundingMethod compoundingMethod, final CalendarInstance compoundingCalendarInstance,
|
final InterestRecalculationCompoundingMethod compoundingMethod, final CalendarInstance compoundingCalendarInstance,
|
||||||
final RecalculationFrequencyType compoundingFrequencyType,
|
final RecalculationFrequencyType compoundingFrequencyType,
|
||||||
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy,
|
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy,
|
||||||
final LoanRescheduleStrategyMethod rescheduleStrategyMethod, BigDecimal approvedAmount) {
|
final LoanRescheduleStrategyMethod rescheduleStrategyMethod, BigDecimal approvedAmount, BigDecimal annualNominalInterestRate,
|
||||||
|
Collection<LoanTermVariationsData> loanTermVariations) {
|
||||||
final Calendar loanCalendar = null;
|
final Calendar loanCalendar = null;
|
||||||
|
|
||||||
return assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, nthDay, dayOfWeek,
|
return assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, nthDay, dayOfWeek,
|
||||||
@@ -203,7 +207,8 @@ public final class LoanApplicationTerms {
|
|||||||
loanProductRelatedDetail, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, emiAmountVariations,
|
loanProductRelatedDetail, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, emiAmountVariations,
|
||||||
interestChargedFromDate, principalThresholdForLastInstalment, installmentAmountInMultiplesOf, recalculationFrequencyType,
|
interestChargedFromDate, principalThresholdForLastInstalment, installmentAmountInMultiplesOf, recalculationFrequencyType,
|
||||||
restCalendarInstance, compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType,
|
restCalendarInstance, compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType,
|
||||||
loanPreClosureInterestCalculationStrategy, rescheduleStrategyMethod, loanCalendar, approvedAmount);
|
loanPreClosureInterestCalculationStrategy, rescheduleStrategyMethod, loanCalendar, approvedAmount,
|
||||||
|
annualNominalInterestRate, loanTermVariations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
||||||
@@ -218,7 +223,8 @@ public final class LoanApplicationTerms {
|
|||||||
final InterestRecalculationCompoundingMethod compoundingMethod, final CalendarInstance compoundingCalendarInstance,
|
final InterestRecalculationCompoundingMethod compoundingMethod, final CalendarInstance compoundingCalendarInstance,
|
||||||
final RecalculationFrequencyType compoundingFrequencyType,
|
final RecalculationFrequencyType compoundingFrequencyType,
|
||||||
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy,
|
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy,
|
||||||
final LoanRescheduleStrategyMethod rescheduleStrategyMethod, final Calendar loanCalendar, BigDecimal approvedAmount) {
|
final LoanRescheduleStrategyMethod rescheduleStrategyMethod, final Calendar loanCalendar, BigDecimal approvedAmount,
|
||||||
|
BigDecimal annualNominalInterestRate, Collection<LoanTermVariationsData> loanTermVariations) {
|
||||||
|
|
||||||
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
||||||
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
||||||
@@ -227,7 +233,6 @@ public final class LoanApplicationTerms {
|
|||||||
final InterestMethod interestMethod = loanProductRelatedDetail.getInterestMethod();
|
final InterestMethod interestMethod = loanProductRelatedDetail.getInterestMethod();
|
||||||
final BigDecimal interestRatePerPeriod = loanProductRelatedDetail.getNominalInterestRatePerPeriod();
|
final BigDecimal interestRatePerPeriod = loanProductRelatedDetail.getNominalInterestRatePerPeriod();
|
||||||
final PeriodFrequencyType interestRatePeriodFrequencyType = loanProductRelatedDetail.getInterestPeriodFrequencyType();
|
final PeriodFrequencyType interestRatePeriodFrequencyType = loanProductRelatedDetail.getInterestPeriodFrequencyType();
|
||||||
final BigDecimal annualNominalInterestRate = loanProductRelatedDetail.getAnnualNominalInterestRate();
|
|
||||||
final InterestCalculationPeriodMethod interestCalculationPeriodMethod = loanProductRelatedDetail
|
final InterestCalculationPeriodMethod interestCalculationPeriodMethod = loanProductRelatedDetail
|
||||||
.getInterestCalculationPeriodMethod();
|
.getInterestCalculationPeriodMethod();
|
||||||
final Money principalMoney = loanProductRelatedDetail.getPrincipal();
|
final Money principalMoney = loanProductRelatedDetail.getPrincipal();
|
||||||
@@ -250,7 +255,7 @@ public final class LoanApplicationTerms {
|
|||||||
loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||||
rescheduleStrategyMethod, compoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
|
rescheduleStrategyMethod, compoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
|
||||||
compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
|
compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
|
||||||
loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount);
|
loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
||||||
@@ -263,7 +268,8 @@ public final class LoanApplicationTerms {
|
|||||||
final RecalculationFrequencyType recalculationFrequencyType, final CalendarInstance compoundingCalendarInstance,
|
final RecalculationFrequencyType recalculationFrequencyType, final CalendarInstance compoundingCalendarInstance,
|
||||||
final RecalculationFrequencyType compoundingFrequencyType, final BigDecimal principalThresholdForLastInstalment,
|
final RecalculationFrequencyType compoundingFrequencyType, final BigDecimal principalThresholdForLastInstalment,
|
||||||
final Integer installmentAmountInMultiplesOf,
|
final Integer installmentAmountInMultiplesOf,
|
||||||
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy, BigDecimal approvedAmount) {
|
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy, BigDecimal approvedAmount,
|
||||||
|
final BigDecimal annualNominalInterestRate, final Collection<LoanTermVariationsData> loanTermVariations) {
|
||||||
|
|
||||||
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
||||||
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
||||||
@@ -272,7 +278,6 @@ public final class LoanApplicationTerms {
|
|||||||
final InterestMethod interestMethod = loanProductRelatedDetail.getInterestMethod();
|
final InterestMethod interestMethod = loanProductRelatedDetail.getInterestMethod();
|
||||||
final BigDecimal interestRatePerPeriod = loanProductRelatedDetail.getNominalInterestRatePerPeriod();
|
final BigDecimal interestRatePerPeriod = loanProductRelatedDetail.getNominalInterestRatePerPeriod();
|
||||||
final PeriodFrequencyType interestRatePeriodFrequencyType = loanProductRelatedDetail.getInterestPeriodFrequencyType();
|
final PeriodFrequencyType interestRatePeriodFrequencyType = loanProductRelatedDetail.getInterestPeriodFrequencyType();
|
||||||
final BigDecimal annualNominalInterestRate = loanProductRelatedDetail.getAnnualNominalInterestRate();
|
|
||||||
final InterestCalculationPeriodMethod interestCalculationPeriodMethod = loanProductRelatedDetail
|
final InterestCalculationPeriodMethod interestCalculationPeriodMethod = loanProductRelatedDetail
|
||||||
.getInterestCalculationPeriodMethod();
|
.getInterestCalculationPeriodMethod();
|
||||||
final Money principalMoney = loanProductRelatedDetail.getPrincipal();
|
final Money principalMoney = loanProductRelatedDetail.getPrincipal();
|
||||||
@@ -302,28 +307,7 @@ public final class LoanApplicationTerms {
|
|||||||
daysInMonthType, daysInYearType, isInterestRecalculationEnabled, rescheduleStrategyMethod,
|
daysInMonthType, daysInYearType, isInterestRecalculationEnabled, rescheduleStrategyMethod,
|
||||||
interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
|
interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
|
||||||
compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
|
compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
|
||||||
loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount);
|
loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations);
|
||||||
}
|
|
||||||
|
|
||||||
public static LoanApplicationTerms assembleFrom(final Integer repaymentEvery, final PeriodFrequencyType repaymentPeriodFrequencyType,
|
|
||||||
final LoanApplicationTerms applicationTerms, BigDecimal approvedAmount) {
|
|
||||||
return new LoanApplicationTerms(applicationTerms.currency, applicationTerms.loanTermFrequency,
|
|
||||||
applicationTerms.loanTermPeriodFrequencyType, applicationTerms.numberOfRepayments, repaymentEvery,
|
|
||||||
repaymentPeriodFrequencyType, null, null, applicationTerms.amortizationMethod, applicationTerms.interestMethod,
|
|
||||||
applicationTerms.interestRatePerPeriod, applicationTerms.interestRatePeriodFrequencyType,
|
|
||||||
applicationTerms.annualNominalInterestRate, applicationTerms.interestCalculationPeriodMethod, applicationTerms.principal,
|
|
||||||
applicationTerms.expectedDisbursementDate, applicationTerms.repaymentsStartingFromDate,
|
|
||||||
applicationTerms.calculatedRepaymentsStartingFromDate, applicationTerms.principalGrace,
|
|
||||||
applicationTerms.interestPaymentGrace, applicationTerms.interestChargingGrace, applicationTerms.interestChargedFromDate,
|
|
||||||
applicationTerms.inArrearsTolerance, applicationTerms.multiDisburseLoan, applicationTerms.fixedEmiAmount,
|
|
||||||
applicationTerms.disbursementDatas, applicationTerms.maxOutstandingBalance, applicationTerms.emiAmountVariations,
|
|
||||||
applicationTerms.graceOnArrearsAgeing, applicationTerms.daysInMonthType, applicationTerms.daysInYearType,
|
|
||||||
applicationTerms.interestRecalculationEnabled, applicationTerms.rescheduleStrategyMethod,
|
|
||||||
applicationTerms.interestRecalculationCompoundingMethod, applicationTerms.restCalendarInstance,
|
|
||||||
applicationTerms.recalculationFrequencyType, applicationTerms.compoundingCalendarInstance,
|
|
||||||
applicationTerms.compoundingFrequencyType, applicationTerms.principalThresholdForLastInstalment,
|
|
||||||
applicationTerms.installmentAmountInMultiplesOf, applicationTerms.preClosureInterestCalculationStrategy,
|
|
||||||
applicationTerms.loanCalendar, approvedAmount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
||||||
@@ -344,7 +328,7 @@ public final class LoanApplicationTerms {
|
|||||||
final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
|
final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
|
||||||
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
|
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
|
||||||
final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy, final Calendar loanCalendar,
|
final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy, final Calendar loanCalendar,
|
||||||
BigDecimal approvedAmount) {
|
BigDecimal approvedAmount, Collection<LoanTermVariationsData> loanTermVariations) {
|
||||||
this.currency = currency;
|
this.currency = currency;
|
||||||
this.loanTermFrequency = loanTermFrequency;
|
this.loanTermFrequency = loanTermFrequency;
|
||||||
this.loanTermPeriodFrequencyType = loanTermPeriodFrequencyType;
|
this.loanTermPeriodFrequencyType = loanTermPeriodFrequencyType;
|
||||||
@@ -394,6 +378,7 @@ public final class LoanApplicationTerms {
|
|||||||
|
|
||||||
this.loanCalendar = loanCalendar;
|
this.loanCalendar = loanCalendar;
|
||||||
this.approvedPrincipal = Money.of(principal.getCurrency(), approvedAmount);
|
this.approvedPrincipal = Money.of(principal.getCurrency(), approvedAmount);
|
||||||
|
this.loanTermVariations = loanTermVariations;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate,
|
public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate,
|
||||||
@@ -1215,10 +1200,6 @@ public final class LoanApplicationTerms {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public BigDecimal getInterestRatePerPeriod() {
|
|
||||||
return this.interestRatePerPeriod;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigDecimal getAnnualNominalInterestRate() {
|
public BigDecimal getAnnualNominalInterestRate() {
|
||||||
return this.annualNominalInterestRate;
|
return this.annualNominalInterestRate;
|
||||||
}
|
}
|
||||||
@@ -1270,9 +1251,12 @@ public final class LoanApplicationTerms {
|
|||||||
return loanCalendar;
|
return loanCalendar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public BigDecimal getFixedPrincipalAmount() {
|
public BigDecimal getFixedPrincipalAmount() {
|
||||||
return this.fixedPrincipalAmount;
|
return this.fixedPrincipalAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<LoanTermVariationsData> getLoanTermVariations() {
|
||||||
|
return this.loanTermVariations;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+2
-1
@@ -14,6 +14,7 @@ import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
|
|||||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRateDTO;
|
||||||
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
|
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||||
@@ -38,5 +39,5 @@ public interface LoanScheduleGenerator {
|
|||||||
|
|
||||||
LoanRescheduleModel reschedule(final MathContext mathContext, final LoanRescheduleRequest loanRescheduleRequest,
|
LoanRescheduleModel reschedule(final MathContext mathContext, final LoanRescheduleRequest loanRescheduleRequest,
|
||||||
final ApplicationCurrency applicationCurrency, final HolidayDetailDTO holidayDetailDTO, CalendarInstance restCalendarInstance,
|
final ApplicationCurrency applicationCurrency, final HolidayDetailDTO holidayDetailDTO, CalendarInstance restCalendarInstance,
|
||||||
CalendarInstance compoundingCalendarInstance, final Calendar loanCalendar);
|
CalendarInstance compoundingCalendarInstance, final Calendar loanCalendar, FloatingRateDTO floatingRateDTO);
|
||||||
}
|
}
|
||||||
+40
-4
@@ -9,6 +9,7 @@ import java.math.BigDecimal;
|
|||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -17,6 +18,7 @@ import org.apache.commons.lang.StringUtils;
|
|||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
|
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||||
|
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||||
import org.mifosplatform.organisation.holiday.domain.Holiday;
|
import org.mifosplatform.organisation.holiday.domain.Holiday;
|
||||||
import org.mifosplatform.organisation.holiday.domain.HolidayRepository;
|
import org.mifosplatform.organisation.holiday.domain.HolidayRepository;
|
||||||
import org.mifosplatform.organisation.holiday.domain.HolidayStatusType;
|
import org.mifosplatform.organisation.holiday.domain.HolidayStatusType;
|
||||||
@@ -45,6 +47,9 @@ import org.mifosplatform.portfolio.common.domain.DayOfWeekType;
|
|||||||
import org.mifosplatform.portfolio.common.domain.DaysInMonthType;
|
import org.mifosplatform.portfolio.common.domain.DaysInMonthType;
|
||||||
import org.mifosplatform.portfolio.common.domain.DaysInYearType;
|
import org.mifosplatform.portfolio.common.domain.DaysInYearType;
|
||||||
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRateDTO;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRatePeriodData;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.group.domain.Group;
|
import org.mifosplatform.portfolio.group.domain.Group;
|
||||||
import org.mifosplatform.portfolio.group.domain.GroupRepositoryWrapper;
|
import org.mifosplatform.portfolio.group.domain.GroupRepositoryWrapper;
|
||||||
import org.mifosplatform.portfolio.loanaccount.api.LoanApiConstants;
|
import org.mifosplatform.portfolio.loanaccount.api.LoanApiConstants;
|
||||||
@@ -99,6 +104,7 @@ public class LoanScheduleAssembler {
|
|||||||
private final ClientRepositoryWrapper clientRepository;
|
private final ClientRepositoryWrapper clientRepository;
|
||||||
private final GroupRepositoryWrapper groupRepository;
|
private final GroupRepositoryWrapper groupRepository;
|
||||||
private final WorkingDaysRepositoryWrapper workingDaysRepository;
|
private final WorkingDaysRepositoryWrapper workingDaysRepository;
|
||||||
|
private final FloatingRatesReadPlatformService floatingRatesReadPlatformService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanScheduleAssembler(final FromJsonHelper fromApiJsonHelper, final LoanProductRepository loanProductRepository,
|
public LoanScheduleAssembler(final FromJsonHelper fromApiJsonHelper, final LoanProductRepository loanProductRepository,
|
||||||
@@ -107,7 +113,8 @@ public class LoanScheduleAssembler {
|
|||||||
final LoanChargeAssembler loanChargeAssembler, final CalendarRepository calendarRepository,
|
final LoanChargeAssembler loanChargeAssembler, final CalendarRepository calendarRepository,
|
||||||
final HolidayRepository holidayRepository, final ConfigurationDomainService configurationDomainService,
|
final HolidayRepository holidayRepository, final ConfigurationDomainService configurationDomainService,
|
||||||
final ClientRepositoryWrapper clientRepository, final GroupRepositoryWrapper groupRepository,
|
final ClientRepositoryWrapper clientRepository, final GroupRepositoryWrapper groupRepository,
|
||||||
final WorkingDaysRepositoryWrapper workingDaysRepository) {
|
final WorkingDaysRepositoryWrapper workingDaysRepository,
|
||||||
|
final FloatingRatesReadPlatformService floatingRatesReadPlatformService) {
|
||||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||||
this.loanProductRepository = loanProductRepository;
|
this.loanProductRepository = loanProductRepository;
|
||||||
this.applicationCurrencyRepository = applicationCurrencyRepository;
|
this.applicationCurrencyRepository = applicationCurrencyRepository;
|
||||||
@@ -120,6 +127,7 @@ public class LoanScheduleAssembler {
|
|||||||
this.clientRepository = clientRepository;
|
this.clientRepository = clientRepository;
|
||||||
this.groupRepository = groupRepository;
|
this.groupRepository = groupRepository;
|
||||||
this.workingDaysRepository = workingDaysRepository;
|
this.workingDaysRepository = workingDaysRepository;
|
||||||
|
this.floatingRatesReadPlatformService = floatingRatesReadPlatformService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoanApplicationTerms assembleLoanTerms(final JsonElement element) {
|
public LoanApplicationTerms assembleLoanTerms(final JsonElement element) {
|
||||||
@@ -164,8 +172,10 @@ public class LoanScheduleAssembler {
|
|||||||
final BigDecimal interestRatePerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element);
|
final BigDecimal interestRatePerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element);
|
||||||
final PeriodFrequencyType interestRatePeriodFrequencyType = loanProduct.getInterestPeriodFrequencyType();
|
final PeriodFrequencyType interestRatePeriodFrequencyType = loanProduct.getInterestPeriodFrequencyType();
|
||||||
|
|
||||||
final BigDecimal annualNominalInterestRate = this.aprCalculator.calculateFrom(interestRatePeriodFrequencyType,
|
BigDecimal annualNominalInterestRate = BigDecimal.ZERO;
|
||||||
interestRatePerPeriod);
|
if (interestRatePerPeriod != null) {
|
||||||
|
annualNominalInterestRate = this.aprCalculator.calculateFrom(interestRatePeriodFrequencyType, interestRatePerPeriod);
|
||||||
|
}
|
||||||
|
|
||||||
// disbursement details
|
// disbursement details
|
||||||
final BigDecimal principal = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("principal", element);
|
final BigDecimal principal = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("principal", element);
|
||||||
@@ -296,6 +306,31 @@ public class LoanScheduleAssembler {
|
|||||||
|
|
||||||
final Integer installmentAmountInMultiplesOf = loanProduct.getInstallmentAmountInMultiplesOf();
|
final Integer installmentAmountInMultiplesOf = loanProduct.getInstallmentAmountInMultiplesOf();
|
||||||
|
|
||||||
|
Collection<LoanTermVariationsData> loanTermVariations = new ArrayList<>();
|
||||||
|
if (loanProduct.isLinkedToFloatingInterestRate()) {
|
||||||
|
final BigDecimal interestRateDiff = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(
|
||||||
|
LoanApiConstants.interestRateDifferentialParameterName, element);
|
||||||
|
final Boolean isFloatingInterestRate = this.fromApiJsonHelper.extractBooleanNamed(
|
||||||
|
LoanApiConstants.isFloatingInterestRateParameterName, element);
|
||||||
|
List<FloatingRatePeriodData> baseLendingRatePeriods = this.floatingRatesReadPlatformService.retrieveBaseLendingRate()
|
||||||
|
.getRatePeriods();
|
||||||
|
FloatingRateDTO floatingRateDTO = new FloatingRateDTO(isFloatingInterestRate, expectedDisbursementDate, interestRateDiff,
|
||||||
|
baseLendingRatePeriods);
|
||||||
|
Collection<FloatingRatePeriodData> applicableRates = loanProduct.fetchInterestRates(floatingRateDTO);
|
||||||
|
|
||||||
|
LocalDate interestRateStartDate = DateUtils.getLocalDateOfTenant();
|
||||||
|
for (FloatingRatePeriodData periodData : applicableRates) {
|
||||||
|
LoanTermVariationsData loanTermVariation = new LoanTermVariationsData(
|
||||||
|
LoanEnumerations.loanvariationType(LoanTermVariationType.INTEREST_RATE), periodData.getFromDateAsLocalDate(),
|
||||||
|
periodData.getInterestRate());
|
||||||
|
if (interestRateStartDate.isAfter(periodData.getFromDateAsLocalDate())) {
|
||||||
|
interestRateStartDate = periodData.getFromDateAsLocalDate();
|
||||||
|
annualNominalInterestRate = periodData.getInterestRate();
|
||||||
|
}
|
||||||
|
loanTermVariations.add(loanTermVariation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
|
return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
|
||||||
repaymentEvery, repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod,
|
repaymentEvery, repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod,
|
||||||
interestRatePerPeriod, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod,
|
interestRatePerPeriod, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod,
|
||||||
@@ -304,7 +339,8 @@ public class LoanScheduleAssembler {
|
|||||||
loanProduct.isMultiDisburseLoan(), emiAmount, disbursementDatas, maxOutstandingBalance, loanVariationTermsData,
|
loanProduct.isMultiDisburseLoan(), emiAmount, disbursementDatas, maxOutstandingBalance, loanVariationTermsData,
|
||||||
graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, recalculationFrequencyType,
|
graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, recalculationFrequencyType,
|
||||||
restCalendarInstance, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment,
|
restCalendarInstance, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment,
|
||||||
installmentAmountInMultiplesOf, loanProduct.preCloseInterestCalculationStrategy(), calendar, BigDecimal.ZERO);
|
installmentAmountInMultiplesOf, loanProduct.preCloseInterestCalculationStrategy(), calendar, BigDecimal.ZERO,
|
||||||
|
loanTermVariations);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CalendarInstance createInterestRecalculationCalendarInstance(final LocalDate calendarStartDate,
|
private CalendarInstance createInterestRecalculationCalendarInstance(final LocalDate calendarStartDate,
|
||||||
|
|||||||
+25
-5
@@ -26,6 +26,9 @@ import org.mifosplatform.portfolio.accountdetails.domain.AccountType;
|
|||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstanceRepository;
|
import org.mifosplatform.portfolio.calendar.domain.CalendarInstanceRepository;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRateDTO;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRatePeriodData;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanAccountDomainService;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanAccountDomainService;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||||
@@ -63,6 +66,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
|||||||
private final CalendarInstanceRepository calendarInstanceRepository;
|
private final CalendarInstanceRepository calendarInstanceRepository;
|
||||||
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
|
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
|
||||||
private final ConfigurationDomainService configurationDomainService;
|
private final ConfigurationDomainService configurationDomainService;
|
||||||
|
private final FloatingRatesReadPlatformService floatingRatesReadPlatformService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanScheduleCalculationPlatformServiceImpl(final CalculateLoanScheduleQueryFromApiJsonHelper fromApiJsonDeserializer,
|
public LoanScheduleCalculationPlatformServiceImpl(final CalculateLoanScheduleQueryFromApiJsonHelper fromApiJsonDeserializer,
|
||||||
@@ -72,7 +76,8 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
|||||||
final LoanAssembler loanAssembler, final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository,
|
final LoanAssembler loanAssembler, final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository,
|
||||||
final LoanAccountDomainService accountDomainService, final CalendarInstanceRepository calendarInstanceRepository,
|
final LoanAccountDomainService accountDomainService, final CalendarInstanceRepository calendarInstanceRepository,
|
||||||
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
|
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
|
||||||
final ConfigurationDomainService configurationDomainService) {
|
final ConfigurationDomainService configurationDomainService,
|
||||||
|
final FloatingRatesReadPlatformService floatingRatesReadPlatformService) {
|
||||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||||
this.loanScheduleAssembler = loanScheduleAssembler;
|
this.loanScheduleAssembler = loanScheduleAssembler;
|
||||||
this.fromJsonHelper = fromJsonHelper;
|
this.fromJsonHelper = fromJsonHelper;
|
||||||
@@ -86,6 +91,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
|||||||
this.calendarInstanceRepository = calendarInstanceRepository;
|
this.calendarInstanceRepository = calendarInstanceRepository;
|
||||||
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
|
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
|
||||||
this.configurationDomainService = configurationDomainService;
|
this.configurationDomainService = configurationDomainService;
|
||||||
|
this.floatingRatesReadPlatformService = floatingRatesReadPlatformService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -164,11 +170,12 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
|||||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||||
LocalDate calculatedRepaymentsStartingFromDate = accountDomainService.getCalculatedRepaymentsStartingFromDate(
|
LocalDate calculatedRepaymentsStartingFromDate = accountDomainService.getCalculatedRepaymentsStartingFromDate(
|
||||||
loan.getDisbursementDate(), loan, calendarInstance);
|
loan.getDisbursementDate(), loan, calendarInstance);
|
||||||
|
FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
|
||||||
LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(applicationCurrency,
|
LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(applicationCurrency,
|
||||||
calculatedRepaymentsStartingFromDate, restCalendarInstance, compoundingCalendarInstance);
|
calculatedRepaymentsStartingFromDate, restCalendarInstance, compoundingCalendarInstance, floatingRateDTO);
|
||||||
LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = this.loanScheduleAssembler.calculatePrepaymentAmount(
|
LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = this.loanScheduleAssembler.calculatePrepaymentAmount(currency,
|
||||||
currency, today, loanApplicationTerms, loan.charges(), loan.getOfficeId(), loan.retreiveListOfTransactionsPostDisbursementExcludeAccruals(),
|
today, loanApplicationTerms, loan.charges(), loan.getOfficeId(),
|
||||||
loanRepaymentScheduleTransactionProcessor);
|
loan.retreiveListOfTransactionsPostDisbursementExcludeAccruals(), loanRepaymentScheduleTransactionProcessor);
|
||||||
Money totalAmount = totalPrincipal.plus(loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency)).plus(
|
Money totalAmount = totalPrincipal.plus(loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency)).plus(
|
||||||
loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency));
|
loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency));
|
||||||
Money interestDue = Money.zero(currency);
|
Money interestDue = Money.zero(currency);
|
||||||
@@ -209,4 +216,17 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
|||||||
}
|
}
|
||||||
loanScheduleData.updateFuturePeriods(futureInstallments);
|
loanScheduleData.updateFuturePeriods(futureInstallments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private FloatingRateDTO constructFloatingRateDTO(final Loan loan) {
|
||||||
|
FloatingRateDTO floatingRateDTO = null;
|
||||||
|
if (loan.loanProduct().isLinkedToFloatingInterestRate()) {
|
||||||
|
boolean isFloatingInterestRate = loan.getIsFloatingInterestRate();
|
||||||
|
BigDecimal interestRateDiff = loan.getInterestRateDifferential();
|
||||||
|
List<FloatingRatePeriodData> baseLendingRatePeriods = this.floatingRatesReadPlatformService.retrieveBaseLendingRate()
|
||||||
|
.getRatePeriods();
|
||||||
|
floatingRateDTO = new FloatingRateDTO(isFloatingInterestRate, loan.getDisbursementDate(), interestRateDiff,
|
||||||
|
baseLendingRatePeriods);
|
||||||
|
}
|
||||||
|
return floatingRateDTO;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+6
-3
@@ -10,6 +10,7 @@ import java.math.MathContext;
|
|||||||
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
|
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRateDTO;
|
||||||
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
|
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.DecliningBalanceInterestLoanScheduleGenerator;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.DecliningBalanceInterestLoanScheduleGenerator;
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.FlatInterestLoanScheduleGenerator;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.FlatInterestLoanScheduleGenerator;
|
||||||
@@ -21,19 +22,21 @@ public class DefaultLoanReschedulerFactory implements LoanReschedulerFactory {
|
|||||||
public LoanRescheduleModel reschedule(final MathContext mathContext, final InterestMethod interestMethod,
|
public LoanRescheduleModel reschedule(final MathContext mathContext, final InterestMethod interestMethod,
|
||||||
final LoanRescheduleRequest loanRescheduleRequest, final ApplicationCurrency applicationCurrency,
|
final LoanRescheduleRequest loanRescheduleRequest, final ApplicationCurrency applicationCurrency,
|
||||||
final HolidayDetailDTO holidayDetailDTO, final CalendarInstance restCalendarInstance,
|
final HolidayDetailDTO holidayDetailDTO, final CalendarInstance restCalendarInstance,
|
||||||
final CalendarInstance compoundingCalendarInstance, final Calendar loanCalendar) {
|
final CalendarInstance compoundingCalendarInstance, final Calendar loanCalendar, final FloatingRateDTO floatingRateDTO) {
|
||||||
|
|
||||||
LoanRescheduleModel loanRescheduleModel = null;
|
LoanRescheduleModel loanRescheduleModel = null;
|
||||||
|
|
||||||
switch (interestMethod) {
|
switch (interestMethod) {
|
||||||
case DECLINING_BALANCE:
|
case DECLINING_BALANCE:
|
||||||
loanRescheduleModel = new DecliningBalanceInterestLoanScheduleGenerator().reschedule(mathContext, loanRescheduleRequest,
|
loanRescheduleModel = new DecliningBalanceInterestLoanScheduleGenerator().reschedule(mathContext, loanRescheduleRequest,
|
||||||
applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, loanCalendar);
|
applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, loanCalendar,
|
||||||
|
floatingRateDTO);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FLAT:
|
case FLAT:
|
||||||
loanRescheduleModel = new FlatInterestLoanScheduleGenerator().reschedule(mathContext, loanRescheduleRequest,
|
loanRescheduleModel = new FlatInterestLoanScheduleGenerator().reschedule(mathContext, loanRescheduleRequest,
|
||||||
applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, loanCalendar);
|
applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, loanCalendar,
|
||||||
|
floatingRateDTO);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INVALID:
|
case INVALID:
|
||||||
|
|||||||
+2
-1
@@ -10,6 +10,7 @@ import java.math.MathContext;
|
|||||||
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
|
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRateDTO;
|
||||||
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
|
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
|
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
|
||||||
|
|
||||||
@@ -18,5 +19,5 @@ public interface LoanReschedulerFactory {
|
|||||||
public LoanRescheduleModel reschedule(final MathContext mathContext, final InterestMethod interestMethod,
|
public LoanRescheduleModel reschedule(final MathContext mathContext, final InterestMethod interestMethod,
|
||||||
final LoanRescheduleRequest loanRescheduleRequest, final ApplicationCurrency applicationCurrency,
|
final LoanRescheduleRequest loanRescheduleRequest, final ApplicationCurrency applicationCurrency,
|
||||||
final HolidayDetailDTO holidayDetailDTO, CalendarInstance restCalendarInstance, CalendarInstance compoundingCalendarInstance,
|
final HolidayDetailDTO holidayDetailDTO, CalendarInstance restCalendarInstance, CalendarInstance compoundingCalendarInstance,
|
||||||
final Calendar loanCalendar);
|
final Calendar loanCalendar, FloatingRateDTO floatingRateDTO);
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-8
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.mifosplatform.portfolio.loanaccount.rescheduleloan.service;
|
package org.mifosplatform.portfolio.loanaccount.rescheduleloan.service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -23,6 +24,9 @@ import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
|||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstanceRepository;
|
import org.mifosplatform.portfolio.calendar.domain.CalendarInstanceRepository;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRateDTO;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRatePeriodData;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
|
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleHistory;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleHistory;
|
||||||
@@ -47,6 +51,7 @@ public class LoanReschedulePreviewPlatformServiceImpl implements LoanRescheduleP
|
|||||||
private final WorkingDaysRepositoryWrapper workingDaysRepository;
|
private final WorkingDaysRepositoryWrapper workingDaysRepository;
|
||||||
private final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService;
|
private final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService;
|
||||||
private final CalendarInstanceRepository calendarInstanceRepository;
|
private final CalendarInstanceRepository calendarInstanceRepository;
|
||||||
|
private final FloatingRatesReadPlatformService floatingRatesReadPlatformService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanReschedulePreviewPlatformServiceImpl(final LoanRescheduleRequestRepository loanRescheduleRequestRepository,
|
public LoanReschedulePreviewPlatformServiceImpl(final LoanRescheduleRequestRepository loanRescheduleRequestRepository,
|
||||||
@@ -54,7 +59,8 @@ public class LoanReschedulePreviewPlatformServiceImpl implements LoanRescheduleP
|
|||||||
final ConfigurationDomainService configurationDomainService, final HolidayRepository holidayRepository,
|
final ConfigurationDomainService configurationDomainService, final HolidayRepository holidayRepository,
|
||||||
final WorkingDaysRepositoryWrapper workingDaysRepository,
|
final WorkingDaysRepositoryWrapper workingDaysRepository,
|
||||||
final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService,
|
final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService,
|
||||||
final CalendarInstanceRepository calendarInstanceRepository) {
|
final CalendarInstanceRepository calendarInstanceRepository,
|
||||||
|
final FloatingRatesReadPlatformService floatingRatesReadPlatformService) {
|
||||||
this.loanRescheduleRequestRepository = loanRescheduleRequestRepository;
|
this.loanRescheduleRequestRepository = loanRescheduleRequestRepository;
|
||||||
this.applicationCurrencyRepository = applicationCurrencyRepository;
|
this.applicationCurrencyRepository = applicationCurrencyRepository;
|
||||||
this.configurationDomainService = configurationDomainService;
|
this.configurationDomainService = configurationDomainService;
|
||||||
@@ -62,6 +68,7 @@ public class LoanReschedulePreviewPlatformServiceImpl implements LoanRescheduleP
|
|||||||
this.workingDaysRepository = workingDaysRepository;
|
this.workingDaysRepository = workingDaysRepository;
|
||||||
this.loanScheduleHistoryWritePlatformService = loanScheduleHistoryWritePlatformService;
|
this.loanScheduleHistoryWritePlatformService = loanScheduleHistoryWritePlatformService;
|
||||||
this.calendarInstanceRepository = calendarInstanceRepository;
|
this.calendarInstanceRepository = calendarInstanceRepository;
|
||||||
|
this.floatingRatesReadPlatformService = floatingRatesReadPlatformService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -73,8 +80,8 @@ public class LoanReschedulePreviewPlatformServiceImpl implements LoanRescheduleP
|
|||||||
Loan loan = loanRescheduleRequest.getLoan();
|
Loan loan = loanRescheduleRequest.getLoan();
|
||||||
|
|
||||||
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
||||||
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(),
|
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan
|
||||||
loan.getDisbursementDate().toDate(), HolidayStatusType.ACTIVE.getValue());
|
.getDisbursementDate().toDate(), HolidayStatusType.ACTIVE.getValue());
|
||||||
final WorkingDays workingDays = this.workingDaysRepository.findOne();
|
final WorkingDays workingDays = this.workingDaysRepository.findOne();
|
||||||
final LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail = loan.getLoanRepaymentScheduleDetail();
|
final LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail = loan.getLoanRepaymentScheduleDetail();
|
||||||
final MonetaryCurrency currency = loanProductRelatedDetail.getCurrency();
|
final MonetaryCurrency currency = loanProductRelatedDetail.getCurrency();
|
||||||
@@ -83,16 +90,16 @@ public class LoanReschedulePreviewPlatformServiceImpl implements LoanRescheduleP
|
|||||||
final InterestMethod interestMethod = loan.getLoanRepaymentScheduleDetail().getInterestMethod();
|
final InterestMethod interestMethod = loan.getLoanRepaymentScheduleDetail().getInterestMethod();
|
||||||
final RoundingMode roundingMode = MoneyHelper.getRoundingMode();
|
final RoundingMode roundingMode = MoneyHelper.getRoundingMode();
|
||||||
final MathContext mathContext = new MathContext(8, roundingMode);
|
final MathContext mathContext = new MathContext(8, roundingMode);
|
||||||
List<LoanRepaymentScheduleHistory> oldPeriods = this.loanScheduleHistoryWritePlatformService
|
List<LoanRepaymentScheduleHistory> oldPeriods = this.loanScheduleHistoryWritePlatformService.createLoanScheduleArchive(
|
||||||
.createLoanScheduleArchive(loan.getRepaymentScheduleInstallments(), loan, loanRescheduleRequest);
|
loan.getRepaymentScheduleInstallments(), loan, loanRescheduleRequest);
|
||||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||||
CalendarInstance restCalendarInstance = null;
|
CalendarInstance restCalendarInstance = null;
|
||||||
CalendarInstance compoundingCalendarInstance = null;
|
CalendarInstance compoundingCalendarInstance = null;
|
||||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
||||||
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||||
CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||||
}
|
}
|
||||||
final CalendarInstance loanCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
|
final CalendarInstance loanCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
|
||||||
CalendarEntityType.LOANS.getValue());
|
CalendarEntityType.LOANS.getValue());
|
||||||
@@ -100,12 +107,26 @@ public class LoanReschedulePreviewPlatformServiceImpl implements LoanRescheduleP
|
|||||||
if (loanCalendarInstance != null) {
|
if (loanCalendarInstance != null) {
|
||||||
loanCalendar = loanCalendarInstance.getCalendar();
|
loanCalendar = loanCalendarInstance.getCalendar();
|
||||||
}
|
}
|
||||||
|
final FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
|
||||||
LoanRescheduleModel loanRescheduleModel = new DefaultLoanReschedulerFactory().reschedule(mathContext, interestMethod,
|
LoanRescheduleModel loanRescheduleModel = new DefaultLoanReschedulerFactory().reschedule(mathContext, interestMethod,
|
||||||
loanRescheduleRequest, applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance,
|
loanRescheduleRequest, applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance,
|
||||||
loanCalendar);
|
loanCalendar, floatingRateDTO);
|
||||||
LoanRescheduleModel loanRescheduleModelWithOldPeriods = LoanRescheduleModel.createWithSchedulehistory(loanRescheduleModel,
|
LoanRescheduleModel loanRescheduleModelWithOldPeriods = LoanRescheduleModel.createWithSchedulehistory(loanRescheduleModel,
|
||||||
oldPeriods);
|
oldPeriods);
|
||||||
return loanRescheduleModelWithOldPeriods;
|
return loanRescheduleModelWithOldPeriods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private FloatingRateDTO constructFloatingRateDTO(final Loan loan) {
|
||||||
|
FloatingRateDTO floatingRateDTO = null;
|
||||||
|
if (loan.loanProduct().isLinkedToFloatingInterestRate()) {
|
||||||
|
boolean isFloatingInterestRate = loan.getIsFloatingInterestRate();
|
||||||
|
BigDecimal interestRateDiff = loan.getInterestRateDifferential();
|
||||||
|
List<FloatingRatePeriodData> baseLendingRatePeriods = this.floatingRatesReadPlatformService.retrieveBaseLendingRate()
|
||||||
|
.getRatePeriods();
|
||||||
|
floatingRateDTO = new FloatingRateDTO(isFloatingInterestRate, loan.getDisbursementDate(), interestRateDiff,
|
||||||
|
baseLendingRatePeriods);
|
||||||
|
}
|
||||||
|
return floatingRateDTO;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+38
-17
@@ -36,6 +36,9 @@ import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
|||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstanceRepository;
|
import org.mifosplatform.portfolio.calendar.domain.CalendarInstanceRepository;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRateDTO;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRatePeriodData;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
|
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||||
import org.mifosplatform.portfolio.loanaccount.data.LoanChargePaidByData;
|
import org.mifosplatform.portfolio.loanaccount.data.LoanChargePaidByData;
|
||||||
import org.mifosplatform.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
import org.mifosplatform.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
||||||
@@ -84,6 +87,7 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
|||||||
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
|
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
|
||||||
private final LoanRepository loanRepository;
|
private final LoanRepository loanRepository;
|
||||||
private final LoanAssembler loanAssembler;
|
private final LoanAssembler loanAssembler;
|
||||||
|
private final FloatingRatesReadPlatformService floatingRatesReadPlatformService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LoanRescheduleRequestWritePlatformServiceImpl constructor
|
* LoanRescheduleRequestWritePlatformServiceImpl constructor
|
||||||
@@ -103,7 +107,7 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
|||||||
final LoanChargeReadPlatformService loanChargeReadPlatformService, final LoanScheduleGeneratorFactory loanScheduleFactory,
|
final LoanChargeReadPlatformService loanChargeReadPlatformService, final LoanScheduleGeneratorFactory loanScheduleFactory,
|
||||||
final LoanTransactionRepository loanTransactionRepository,
|
final LoanTransactionRepository loanTransactionRepository,
|
||||||
final JournalEntryWritePlatformService journalEntryWritePlatformService, final LoanRepository loanRepository,
|
final JournalEntryWritePlatformService journalEntryWritePlatformService, final LoanRepository loanRepository,
|
||||||
final LoanAssembler loanAssembler) {
|
final LoanAssembler loanAssembler, final FloatingRatesReadPlatformService floatingRatesReadPlatformService) {
|
||||||
this.loanRepositoryWrapper = loanRepositoryWrapper;
|
this.loanRepositoryWrapper = loanRepositoryWrapper;
|
||||||
this.codeValueRepositoryWrapper = codeValueRepositoryWrapper;
|
this.codeValueRepositoryWrapper = codeValueRepositoryWrapper;
|
||||||
this.platformSecurityContext = platformSecurityContext;
|
this.platformSecurityContext = platformSecurityContext;
|
||||||
@@ -123,6 +127,7 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
|||||||
this.journalEntryWritePlatformService = journalEntryWritePlatformService;
|
this.journalEntryWritePlatformService = journalEntryWritePlatformService;
|
||||||
this.loanRepository = loanRepository;
|
this.loanRepository = loanRepository;
|
||||||
this.loanAssembler = loanAssembler;
|
this.loanAssembler = loanAssembler;
|
||||||
|
this.floatingRatesReadPlatformService = floatingRatesReadPlatformService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -272,8 +277,8 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
|||||||
final Map<String, Object> changes = new LinkedHashMap<>();
|
final Map<String, Object> changes = new LinkedHashMap<>();
|
||||||
|
|
||||||
LocalDate approvedOnDate = jsonCommand.localDateValueOfParameterNamed("approvedOnDate");
|
LocalDate approvedOnDate = jsonCommand.localDateValueOfParameterNamed("approvedOnDate");
|
||||||
final DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(jsonCommand.dateFormat())
|
final DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(jsonCommand.dateFormat()).withLocale(
|
||||||
.withLocale(jsonCommand.extractLocale());
|
jsonCommand.extractLocale());
|
||||||
|
|
||||||
changes.put("locale", jsonCommand.locale());
|
changes.put("locale", jsonCommand.locale());
|
||||||
changes.put("dateFormat", jsonCommand.dateFormat());
|
changes.put("dateFormat", jsonCommand.dateFormat());
|
||||||
@@ -285,8 +290,8 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
|||||||
final LoanSummary loanSummary = loan.getSummary();
|
final LoanSummary loanSummary = loan.getSummary();
|
||||||
|
|
||||||
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
||||||
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(),
|
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan
|
||||||
loan.getDisbursementDate().toDate());
|
.getDisbursementDate().toDate());
|
||||||
final WorkingDays workingDays = this.workingDaysRepository.findOne();
|
final WorkingDays workingDays = this.workingDaysRepository.findOne();
|
||||||
final LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail = loan.getLoanRepaymentScheduleDetail();
|
final LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail = loan.getLoanRepaymentScheduleDetail();
|
||||||
final MonetaryCurrency currency = loanProductRelatedDetail.getCurrency();
|
final MonetaryCurrency currency = loanProductRelatedDetail.getCurrency();
|
||||||
@@ -314,9 +319,10 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
|||||||
if (loanCalendarInstance != null) {
|
if (loanCalendarInstance != null) {
|
||||||
loanCalendar = loanCalendarInstance.getCalendar();
|
loanCalendar = loanCalendarInstance.getCalendar();
|
||||||
}
|
}
|
||||||
|
FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
|
||||||
LoanRescheduleModel loanRescheduleModel = new DefaultLoanReschedulerFactory().reschedule(mathContext, interestMethod,
|
LoanRescheduleModel loanRescheduleModel = new DefaultLoanReschedulerFactory().reschedule(mathContext, interestMethod,
|
||||||
loanRescheduleRequest, applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance,
|
loanRescheduleRequest, applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance,
|
||||||
loanCalendar);
|
loanCalendar, floatingRateDTO);
|
||||||
|
|
||||||
final Collection<LoanRescheduleModelRepaymentPeriod> periods = loanRescheduleModel.getPeriods();
|
final Collection<LoanRescheduleModelRepaymentPeriod> periods = loanRescheduleModel.getPeriods();
|
||||||
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
|
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
|
||||||
@@ -373,7 +379,8 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
|||||||
waiveLoanCharges(loan, waiveLoanCharges);
|
waiveLoanCharges(loan, waiveLoanCharges);
|
||||||
|
|
||||||
// update the Loan summary
|
// update the Loan summary
|
||||||
loanSummary.updateSummary(currency, loan.getPrincpal(), repaymentScheduleInstallments, new LoanSummaryWrapper(), true, null);
|
loanSummary
|
||||||
|
.updateSummary(currency, loan.getPrincpal(), repaymentScheduleInstallments, new LoanSummaryWrapper(), true, null);
|
||||||
|
|
||||||
// update the total number of schedule repayments
|
// update the total number of schedule repayments
|
||||||
loan.updateNumberOfRepayments(periods.size());
|
loan.updateNumberOfRepayments(periods.size());
|
||||||
@@ -458,26 +465,27 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
|||||||
applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
||||||
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
|
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
|
||||||
CalendarEntityType.LOANS.getValue());
|
CalendarEntityType.LOANS.getValue());
|
||||||
calculatedRepaymentsStartingFromDate = this.loanAccountDomainService
|
calculatedRepaymentsStartingFromDate = this.loanAccountDomainService.getCalculatedRepaymentsStartingFromDate(
|
||||||
.getCalculatedRepaymentsStartingFromDate(loan.getDisbursementDate(), loan, calendarInstance);
|
loan.getDisbursementDate(), loan, calendarInstance);
|
||||||
|
|
||||||
isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
||||||
holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(),
|
holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan.getDisbursementDate()
|
||||||
loan.getDisbursementDate().toDate());
|
.toDate());
|
||||||
workingDays = this.workingDaysRepository.findOne();
|
workingDays = this.workingDaysRepository.findOne();
|
||||||
overdurPenaltyWaitPeriod = this.configurationDomainService.retrievePenaltyWaitPeriod();
|
overdurPenaltyWaitPeriod = this.configurationDomainService.retrievePenaltyWaitPeriod();
|
||||||
recalculateFrom = DateUtils.getLocalDateOfTenant();
|
recalculateFrom = DateUtils.getLocalDateOfTenant();
|
||||||
}
|
}
|
||||||
|
|
||||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||||
|
FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
|
||||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance,
|
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance,
|
||||||
recalculateFrom, overdurPenaltyWaitPeriod);
|
recalculateFrom, overdurPenaltyWaitPeriod, floatingRateDTO);
|
||||||
|
|
||||||
Money accruedCharge = Money.zero(loan.getCurrency());
|
Money accruedCharge = Money.zero(loan.getCurrency());
|
||||||
if (loan.isPeriodicAccrualAccountingEnabledOnLoanProduct()) {
|
if (loan.isPeriodicAccrualAccountingEnabledOnLoanProduct()) {
|
||||||
Collection<LoanChargePaidByData> chargePaidByDatas = this.loanChargeReadPlatformService
|
Collection<LoanChargePaidByData> chargePaidByDatas = this.loanChargeReadPlatformService.retriveLoanChargesPaidBy(
|
||||||
.retriveLoanChargesPaidBy(loanCharge.getId(), LoanTransactionType.ACCRUAL, loanInstallmentNumber);
|
loanCharge.getId(), LoanTransactionType.ACCRUAL, loanInstallmentNumber);
|
||||||
for (LoanChargePaidByData chargePaidByData : chargePaidByDatas) {
|
for (LoanChargePaidByData chargePaidByData : chargePaidByDatas) {
|
||||||
accruedCharge = accruedCharge.plus(chargePaidByData.getAmount());
|
accruedCharge = accruedCharge.plus(chargePaidByData.getAmount());
|
||||||
}
|
}
|
||||||
@@ -527,8 +535,8 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
|||||||
final Map<String, Object> changes = new LinkedHashMap<>();
|
final Map<String, Object> changes = new LinkedHashMap<>();
|
||||||
|
|
||||||
LocalDate rejectedOnDate = jsonCommand.localDateValueOfParameterNamed("rejectedOnDate");
|
LocalDate rejectedOnDate = jsonCommand.localDateValueOfParameterNamed("rejectedOnDate");
|
||||||
final DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(jsonCommand.dateFormat())
|
final DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(jsonCommand.dateFormat()).withLocale(
|
||||||
.withLocale(jsonCommand.extractLocale());
|
jsonCommand.extractLocale());
|
||||||
|
|
||||||
changes.put("locale", jsonCommand.locale());
|
changes.put("locale", jsonCommand.locale());
|
||||||
changes.put("dateFormat", jsonCommand.dateFormat());
|
changes.put("dateFormat", jsonCommand.dateFormat());
|
||||||
@@ -567,4 +575,17 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
|||||||
throw new PlatformDataIntegrityException("error.msg.loan.reschedule.unknown.data.integrity.issue",
|
throw new PlatformDataIntegrityException("error.msg.loan.reschedule.unknown.data.integrity.issue",
|
||||||
"Unknown data integrity issue with resource.");
|
"Unknown data integrity issue with resource.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private FloatingRateDTO constructFloatingRateDTO(final Loan loan) {
|
||||||
|
FloatingRateDTO floatingRateDTO = null;
|
||||||
|
if (loan.loanProduct().isLinkedToFloatingInterestRate()) {
|
||||||
|
boolean isFloatingInterestRate = loan.getIsFloatingInterestRate();
|
||||||
|
BigDecimal interestRateDiff = loan.getInterestRateDifferential();
|
||||||
|
List<FloatingRatePeriodData> baseLendingRatePeriods = this.floatingRatesReadPlatformService.retrieveBaseLendingRate()
|
||||||
|
.getRatePeriods();
|
||||||
|
floatingRateDTO = new FloatingRateDTO(isFloatingInterestRate, loan.getDisbursementDate(), interestRateDiff,
|
||||||
|
baseLendingRatePeriods);
|
||||||
|
}
|
||||||
|
return floatingRateDTO;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-6
@@ -36,12 +36,14 @@ public final class CalculateLoanScheduleQueryFromApiJsonHelper {
|
|||||||
final Set<String> supportedParameters = new HashSet<>(Arrays.asList("id", "clientId", "groupId", "loanType", "calendarId", "productId",
|
final Set<String> supportedParameters = new HashSet<>(Arrays.asList("id", "clientId", "groupId", "loanType", "calendarId", "productId",
|
||||||
"accountNo", "externalId", "fundId", "loanOfficerId", "loanPurposeId", "transactionProcessingStrategyId", "principal",
|
"accountNo", "externalId", "fundId", "loanOfficerId", "loanPurposeId", "transactionProcessingStrategyId", "principal",
|
||||||
"inArrearsTolerance", "interestRatePerPeriod", "repaymentEvery", "numberOfRepayments", "loanTermFrequency",
|
"inArrearsTolerance", "interestRatePerPeriod", "repaymentEvery", "numberOfRepayments", "loanTermFrequency",
|
||||||
"loanTermFrequencyType", "repaymentFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", "interestRateFrequencyType",
|
"loanTermFrequencyType", "repaymentFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType",
|
||||||
"expectedDisbursementDate", "repaymentsStartingFromDate", "graceOnPrincipalPayment", "graceOnInterestPayment",
|
"interestRateFrequencyType", "expectedDisbursementDate", "repaymentsStartingFromDate", "graceOnPrincipalPayment",
|
||||||
"graceOnInterestCharged", "interestChargedFromDate", "submittedOnDate", "submittedOnNote", "locale", "dateFormat", "charges",
|
"graceOnInterestPayment", "graceOnInterestCharged", "interestChargedFromDate", "submittedOnDate", "submittedOnNote", "locale",
|
||||||
"collateral", "syncDisbursementWithMeeting", "linkAccountId", LoanApiConstants.disbursementDataParameterName,
|
"dateFormat", "charges", "collateral", "syncDisbursementWithMeeting", "linkAccountId",
|
||||||
LoanApiConstants.emiAmountParameterName, LoanApiConstants.maxOutstandingBalanceParameterName,
|
LoanApiConstants.disbursementDataParameterName, LoanApiConstants.emiAmountParameterName,
|
||||||
LoanProductConstants.graceOnArrearsAgeingParameterName, LoanProductConstants.recalculationRestFrequencyDateParamName,"createStandingInstructionAtDisbursement"));
|
LoanApiConstants.maxOutstandingBalanceParameterName, LoanProductConstants.graceOnArrearsAgeingParameterName,
|
||||||
|
LoanProductConstants.recalculationRestFrequencyDateParamName, "createStandingInstructionAtDisbursement",
|
||||||
|
LoanApiConstants.isFloatingInterestRateParameterName, LoanApiConstants.interestRateDifferentialParameterName));
|
||||||
|
|
||||||
private final FromJsonHelper fromApiJsonHelper;
|
private final FromJsonHelper fromApiJsonHelper;
|
||||||
|
|
||||||
|
|||||||
+160
-29
@@ -48,10 +48,10 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
|||||||
*/
|
*/
|
||||||
final Set<String> supportedParameters = new HashSet<>(Arrays.asList("dateFormat", "locale", "id", "clientId", "groupId", "loanType",
|
final Set<String> supportedParameters = new HashSet<>(Arrays.asList("dateFormat", "locale", "id", "clientId", "groupId", "loanType",
|
||||||
"productId", "principal", "loanTermFrequency", "loanTermFrequencyType", "numberOfRepayments", "repaymentEvery",
|
"productId", "principal", "loanTermFrequency", "loanTermFrequencyType", "numberOfRepayments", "repaymentEvery",
|
||||||
"repaymentFrequencyType", "repaymentFrequencyNthDayType", "repaymentFrequencyDayOfWeekType",
|
"repaymentFrequencyType", "repaymentFrequencyNthDayType", "repaymentFrequencyDayOfWeekType", "interestRatePerPeriod",
|
||||||
"interestRatePerPeriod",
|
"amortizationType", "interestType",
|
||||||
"amortizationType",
|
LoanApiConstants.isFloatingInterestRate,
|
||||||
"interestType",
|
LoanApiConstants.interestRateDifferential,
|
||||||
"interestCalculationPeriodType",
|
"interestCalculationPeriodType",
|
||||||
"interestRateFrequencyType",
|
"interestRateFrequencyType",
|
||||||
"expectedDisbursementDate",
|
"expectedDisbursementDate",
|
||||||
@@ -203,12 +203,6 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
|||||||
baseDataValidator.reset().parameter(repaymentEveryFrequencyTypeParameterName).value(repaymentEveryType).notNull()
|
baseDataValidator.reset().parameter(repaymentEveryFrequencyTypeParameterName).value(repaymentEveryType).notNull()
|
||||||
.inMinMaxRange(0, 3);
|
.inMinMaxRange(0, 3);
|
||||||
|
|
||||||
final String interestRatePerPeriodParameterName = "interestRatePerPeriod";
|
|
||||||
final BigDecimal interestRatePerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(
|
|
||||||
interestRatePerPeriodParameterName, element);
|
|
||||||
baseDataValidator.reset().parameter(interestRatePerPeriodParameterName).value(interestRatePerPeriod).notNull()
|
|
||||||
.zeroOrPositiveAmount();
|
|
||||||
|
|
||||||
final String interestTypeParameterName = "interestType";
|
final String interestTypeParameterName = "interestType";
|
||||||
final Integer interestType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(interestTypeParameterName, element);
|
final Integer interestType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(interestTypeParameterName, element);
|
||||||
baseDataValidator.reset().parameter(interestTypeParameterName).value(interestType).notNull().inMinMaxRange(0, 1);
|
baseDataValidator.reset().parameter(interestTypeParameterName).value(interestType).notNull().inMinMaxRange(0, 1);
|
||||||
@@ -219,6 +213,71 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
|||||||
baseDataValidator.reset().parameter(interestCalculationPeriodTypeParameterName).value(interestCalculationPeriodType).notNull()
|
baseDataValidator.reset().parameter(interestCalculationPeriodTypeParameterName).value(interestCalculationPeriodType).notNull()
|
||||||
.inMinMaxRange(0, 1);
|
.inMinMaxRange(0, 1);
|
||||||
|
|
||||||
|
if (loanProduct.isLinkedToFloatingInterestRate()) {
|
||||||
|
if (this.fromApiJsonHelper.parameterExists("interestRatePerPeriod", element)) {
|
||||||
|
baseDataValidator
|
||||||
|
.reset()
|
||||||
|
.parameter("interestRatePerPeriod")
|
||||||
|
.failWithCode("not.supported.loanproduct.linked.to.floating.rate",
|
||||||
|
"interestRatePerPeriod param is not supported, selected Loan Product is linked with floating interest rate.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.fromApiJsonHelper.parameterExists(LoanApiConstants.isFloatingInterestRate, element)){
|
||||||
|
final Boolean isFloatingInterestRate = this.fromApiJsonHelper.extractBooleanNamed(
|
||||||
|
LoanApiConstants.isFloatingInterestRate, element);
|
||||||
|
if(isFloatingInterestRate != null && isFloatingInterestRate && !loanProduct.getFloatingRates().isFloatingInterestRateCalculationAllowed()){
|
||||||
|
baseDataValidator.reset().parameter(LoanApiConstants.isFloatingInterestRate).failWithCode("true.not.supported.for.selected.loanproduct",
|
||||||
|
"isFloatingInterestRate value of true not supported for selected Loan Product.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
baseDataValidator.reset().parameter(LoanApiConstants.isFloatingInterestRate).trueOrFalseRequired(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interestType != null && interestType == InterestMethod.FLAT.getValue()) {
|
||||||
|
baseDataValidator
|
||||||
|
.reset()
|
||||||
|
.parameter(interestTypeParameterName)
|
||||||
|
.failWithCode("should.be.0.for.selected.loan.product",
|
||||||
|
"interestType should be DECLINING_BALANCE for selected Loan Product as it is linked to floating rates.");
|
||||||
|
}
|
||||||
|
|
||||||
|
final String interestRateDifferentialParameterName = LoanApiConstants.interestRateDifferential;
|
||||||
|
final BigDecimal interestRateDifferential = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(
|
||||||
|
interestRateDifferentialParameterName, element);
|
||||||
|
baseDataValidator
|
||||||
|
.reset()
|
||||||
|
.parameter(interestRateDifferentialParameterName)
|
||||||
|
.value(interestRateDifferential)
|
||||||
|
.notNull()
|
||||||
|
.zeroOrPositiveAmount()
|
||||||
|
.inMinAndMaxAmountRange(loanProduct.getFloatingRates().getMinDifferentialLendingRate(),
|
||||||
|
loanProduct.getFloatingRates().getMaxDifferentialLendingRate());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(LoanApiConstants.isFloatingInterestRate, element)) {
|
||||||
|
baseDataValidator
|
||||||
|
.reset()
|
||||||
|
.parameter(LoanApiConstants.isFloatingInterestRate)
|
||||||
|
.failWithCode("not.supported.loanproduct.not.linked.to.floating.rate",
|
||||||
|
"isFloatingInterestRate param is not supported, selected Loan Product is not linked with floating interest rate.");
|
||||||
|
}
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(LoanApiConstants.interestRateDifferential, element)) {
|
||||||
|
baseDataValidator
|
||||||
|
.reset()
|
||||||
|
.parameter(LoanApiConstants.interestRateDifferential)
|
||||||
|
.failWithCode("not.supported.loanproduct.not.linked.to.floating.rate",
|
||||||
|
"interestRateDifferential param is not supported, selected Loan Product is not linked with floating interest rate.");
|
||||||
|
}
|
||||||
|
|
||||||
|
final String interestRatePerPeriodParameterName = "interestRatePerPeriod";
|
||||||
|
final BigDecimal interestRatePerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(
|
||||||
|
interestRatePerPeriodParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(interestRatePerPeriodParameterName).value(interestRatePerPeriod).notNull()
|
||||||
|
.zeroOrPositiveAmount();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
final String amortizationTypeParameterName = "amortizationType";
|
final String amortizationTypeParameterName = "amortizationType";
|
||||||
final Integer amortizationType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(amortizationTypeParameterName, element);
|
final Integer amortizationType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(amortizationTypeParameterName, element);
|
||||||
baseDataValidator.reset().parameter(amortizationTypeParameterName).value(amortizationType).notNull().inMinMaxRange(0, 1);
|
baseDataValidator.reset().parameter(amortizationTypeParameterName).value(amortizationType).notNull().inMinMaxRange(0, 1);
|
||||||
@@ -392,7 +451,7 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
|||||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validateForModify(final String json, final LoanProduct loanProduct) {
|
public void validateForModify(final String json, final LoanProduct loanProduct, final Loan existingLoanApplication) {
|
||||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||||
|
|
||||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||||
@@ -518,22 +577,93 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
|||||||
baseDataValidator.reset().parameter(repaymentEveryTypeParameterName).value(repaymentEveryType).notNull().inMinMaxRange(0, 3);
|
baseDataValidator.reset().parameter(repaymentEveryTypeParameterName).value(repaymentEveryType).notNull().inMinMaxRange(0, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
final String interestRatePerPeriodParameterName = "interestRatePerPeriod";
|
|
||||||
if (this.fromApiJsonHelper.parameterExists(interestRatePerPeriodParameterName, element)) {
|
|
||||||
atLeastOneParameterPassedForUpdate = true;
|
|
||||||
final BigDecimal interestRatePerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(
|
|
||||||
interestRatePerPeriodParameterName, element);
|
|
||||||
baseDataValidator.reset().parameter(interestRatePerPeriodParameterName).value(interestRatePerPeriod).notNull()
|
|
||||||
.zeroOrPositiveAmount();
|
|
||||||
}
|
|
||||||
|
|
||||||
final String interestTypeParameterName = "interestType";
|
final String interestTypeParameterName = "interestType";
|
||||||
|
Integer interestType = null;
|
||||||
if (this.fromApiJsonHelper.parameterExists(interestTypeParameterName, element)) {
|
if (this.fromApiJsonHelper.parameterExists(interestTypeParameterName, element)) {
|
||||||
atLeastOneParameterPassedForUpdate = true;
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
final Integer interestType = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(interestTypeParameterName, element);
|
interestType = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(interestTypeParameterName, element);
|
||||||
baseDataValidator.reset().parameter(interestTypeParameterName).value(interestType).notNull().inMinMaxRange(0, 1);
|
baseDataValidator.reset().parameter(interestTypeParameterName).value(interestType).notNull().inMinMaxRange(0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (loanProduct.isLinkedToFloatingInterestRate()) {
|
||||||
|
if (this.fromApiJsonHelper.parameterExists("interestRatePerPeriod", element)) {
|
||||||
|
baseDataValidator
|
||||||
|
.reset()
|
||||||
|
.parameter("interestRatePerPeriod")
|
||||||
|
.failWithCode("not.supported.loanproduct.linked.to.floating.rate",
|
||||||
|
"interestRatePerPeriod param is not supported, selected Loan Product is linked with floating interest rate.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Boolean isFloatingInterestRate = existingLoanApplication.getIsFloatingInterestRate();
|
||||||
|
if(this.fromApiJsonHelper.parameterExists(LoanApiConstants.isFloatingInterestRate, element)){
|
||||||
|
isFloatingInterestRate = this.fromApiJsonHelper.extractBooleanNamed(LoanApiConstants.isFloatingInterestRate, element);
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
}
|
||||||
|
if(isFloatingInterestRate != null){
|
||||||
|
if(isFloatingInterestRate
|
||||||
|
&& !loanProduct.getFloatingRates().isFloatingInterestRateCalculationAllowed()){
|
||||||
|
baseDataValidator.reset().parameter(LoanApiConstants.isFloatingInterestRate).failWithCode("true.not.supported.for.selected.loanproduct",
|
||||||
|
"isFloatingInterestRate value of true not supported for selected Loan Product.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
baseDataValidator.reset().parameter(LoanApiConstants.isFloatingInterestRate).trueOrFalseRequired(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interestType == null) {
|
||||||
|
interestType = existingLoanApplication.getLoanProductRelatedDetail().getInterestMethod().getValue();
|
||||||
|
}
|
||||||
|
if (interestType != null && interestType == InterestMethod.FLAT.getValue()) {
|
||||||
|
baseDataValidator
|
||||||
|
.reset()
|
||||||
|
.parameter(interestTypeParameterName)
|
||||||
|
.failWithCode("should.be.0.for.selected.loan.product",
|
||||||
|
"interestType should be DECLINING_BALANCE for selected Loan Product as it is linked to floating rates.");
|
||||||
|
}
|
||||||
|
|
||||||
|
final String interestRateDifferentialParameterName = LoanApiConstants.interestRateDifferential;
|
||||||
|
BigDecimal interestRateDifferential = existingLoanApplication.getInterestRateDifferential();
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(interestRateDifferentialParameterName, element)) {
|
||||||
|
interestRateDifferential = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(interestRateDifferentialParameterName,
|
||||||
|
element);
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
}
|
||||||
|
baseDataValidator
|
||||||
|
.reset()
|
||||||
|
.parameter(interestRateDifferentialParameterName)
|
||||||
|
.value(interestRateDifferential)
|
||||||
|
.notNull()
|
||||||
|
.zeroOrPositiveAmount()
|
||||||
|
.inMinAndMaxAmountRange(loanProduct.getFloatingRates().getMinDifferentialLendingRate(),
|
||||||
|
loanProduct.getFloatingRates().getMaxDifferentialLendingRate());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(LoanApiConstants.isFloatingInterestRate, element)) {
|
||||||
|
baseDataValidator
|
||||||
|
.reset()
|
||||||
|
.parameter(LoanApiConstants.isFloatingInterestRate)
|
||||||
|
.failWithCode("not.supported.loanproduct.not.linked.to.floating.rate",
|
||||||
|
"isFloatingInterestRate param is not supported, selected Loan Product is not linked with floating interest rate.");
|
||||||
|
}
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(LoanApiConstants.interestRateDifferential, element)) {
|
||||||
|
baseDataValidator
|
||||||
|
.reset()
|
||||||
|
.parameter(LoanApiConstants.interestRateDifferential)
|
||||||
|
.failWithCode("not.supported.loanproduct.not.linked.to.floating.rate",
|
||||||
|
"interestRateDifferential param is not supported, selected Loan Product is not linked with floating interest rate.");
|
||||||
|
}
|
||||||
|
|
||||||
|
final String interestRatePerPeriodParameterName = "interestRatePerPeriod";
|
||||||
|
BigDecimal interestRatePerPeriod = existingLoanApplication.getLoanProductRelatedDetail().getNominalInterestRatePerPeriod();
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(interestRatePerPeriodParameterName, element)) {
|
||||||
|
this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(interestRatePerPeriodParameterName, element);
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
}
|
||||||
|
baseDataValidator.reset().parameter(interestRatePerPeriodParameterName).value(interestRatePerPeriod).notNull()
|
||||||
|
.zeroOrPositiveAmount();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
final String interestCalculationPeriodTypeParameterName = "interestCalculationPeriodType";
|
final String interestCalculationPeriodTypeParameterName = "interestCalculationPeriodType";
|
||||||
if (this.fromApiJsonHelper.parameterExists(interestCalculationPeriodTypeParameterName, element)) {
|
if (this.fromApiJsonHelper.parameterExists(interestCalculationPeriodTypeParameterName, element)) {
|
||||||
atLeastOneParameterPassedForUpdate = true;
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
@@ -849,23 +979,23 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
|||||||
if (variationArray != null) {
|
if (variationArray != null) {
|
||||||
for (int i = 0; i < variationArray.size(); i++) {
|
for (int i = 0; i < variationArray.size(); i++) {
|
||||||
final JsonObject jsonObject1 = variationArray.get(i).getAsJsonObject();
|
final JsonObject jsonObject1 = variationArray.get(i).getAsJsonObject();
|
||||||
if(jsonObject1.has(LoanApiConstants.disbursementDateParameterName)){
|
if (jsonObject1.has(LoanApiConstants.disbursementDateParameterName)) {
|
||||||
LocalDate date1 = this.fromApiJsonHelper.extractLocalDateNamed(LoanApiConstants.disbursementDateParameterName, jsonObject1,
|
LocalDate date1 = this.fromApiJsonHelper.extractLocalDateNamed(LoanApiConstants.disbursementDateParameterName,
|
||||||
dateFormat, locale);
|
jsonObject1, dateFormat, locale);
|
||||||
|
|
||||||
for (int j = i + 1; j < variationArray.size(); j++) {
|
for (int j = i + 1; j < variationArray.size(); j++) {
|
||||||
final JsonObject jsonObject2 = variationArray.get(j).getAsJsonObject();
|
final JsonObject jsonObject2 = variationArray.get(j).getAsJsonObject();
|
||||||
if(jsonObject2.has(LoanApiConstants.disbursementDateParameterName)){
|
if (jsonObject2.has(LoanApiConstants.disbursementDateParameterName)) {
|
||||||
LocalDate date2 = this.fromApiJsonHelper.extractLocalDateNamed(LoanApiConstants.disbursementDateParameterName,
|
LocalDate date2 = this.fromApiJsonHelper.extractLocalDateNamed(LoanApiConstants.disbursementDateParameterName,
|
||||||
jsonObject2, dateFormat, locale);
|
jsonObject2, dateFormat, locale);
|
||||||
if (date1.isAfter(date2)) {
|
if (date1.isAfter(date2)) {
|
||||||
baseDataValidator.reset().parameter(LoanApiConstants.disbursementDataParameterName)
|
baseDataValidator.reset().parameter(LoanApiConstants.disbursementDataParameterName)
|
||||||
.failWithCode(LoanApiConstants.DISBURSEMENT_DATES_NOT_IN_ORDER);
|
.failWithCode(LoanApiConstants.DISBURSEMENT_DATES_NOT_IN_ORDER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -918,8 +1048,9 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
|||||||
if (expectedDisbursement.equals(expectedDisbursementDate)) {
|
if (expectedDisbursement.equals(expectedDisbursementDate)) {
|
||||||
isFirstinstallmentOnExpectedDisbursementDate = true;
|
isFirstinstallmentOnExpectedDisbursementDate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}i++;
|
}
|
||||||
|
i++;
|
||||||
} while (i < variationArray.size());
|
} while (i < variationArray.size());
|
||||||
if (!isFirstinstallmentOnExpectedDisbursementDate) {
|
if (!isFirstinstallmentOnExpectedDisbursementDate) {
|
||||||
baseDataValidator.reset().parameter(LoanApiConstants.disbursementDateParameterName)
|
baseDataValidator.reset().parameter(LoanApiConstants.disbursementDateParameterName)
|
||||||
|
|||||||
+27
-16
@@ -472,13 +472,23 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
try {
|
try {
|
||||||
AppUser currentUser = getAppUserIfPresent();
|
AppUser currentUser = getAppUserIfPresent();
|
||||||
final Loan existingLoanApplication = retrieveLoanBy(loanId);
|
final Loan existingLoanApplication = retrieveLoanBy(loanId);
|
||||||
this.fromApiJsonDeserializer.validateForModify(command.json(), existingLoanApplication.loanProduct());
|
|
||||||
|
|
||||||
checkClientOrGroupActive(existingLoanApplication);
|
|
||||||
|
|
||||||
if (!existingLoanApplication.isSubmittedAndPendingApproval()) { throw new LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeModified(
|
if (!existingLoanApplication.isSubmittedAndPendingApproval()) { throw new LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeModified(
|
||||||
loanId); }
|
loanId); }
|
||||||
|
|
||||||
|
final String productIdParamName = "productId";
|
||||||
|
LoanProduct newLoanProduct = null;
|
||||||
|
if (command.isChangeInLongParameterNamed(productIdParamName, existingLoanApplication.loanProduct().getId())) {
|
||||||
|
final Long productId = command.longValueOfParameterNamed(productIdParamName);
|
||||||
|
newLoanProduct = this.loanProductRepository.findOne(productId);
|
||||||
|
if (newLoanProduct == null) { throw new LoanProductNotFoundException(productId); }
|
||||||
|
}
|
||||||
|
|
||||||
|
LoanProduct loanProductForValidations = newLoanProduct == null? existingLoanApplication.loanProduct(): newLoanProduct;
|
||||||
|
|
||||||
|
this.fromApiJsonDeserializer.validateForModify(command.json(), loanProductForValidations, existingLoanApplication);
|
||||||
|
|
||||||
|
checkClientOrGroupActive(existingLoanApplication);
|
||||||
|
|
||||||
final Set<LoanCharge> existingCharges = existingLoanApplication.charges();
|
final Set<LoanCharge> existingCharges = existingLoanApplication.charges();
|
||||||
Map<Long, LoanChargeData> chargesMap = new HashMap<>();
|
Map<Long, LoanChargeData> chargesMap = new HashMap<>();
|
||||||
for (LoanCharge charge : existingCharges) {
|
for (LoanCharge charge : existingCharges) {
|
||||||
@@ -554,33 +564,34 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
existingLoanApplication.updateGroup(group);
|
existingLoanApplication.updateGroup(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
final String productIdParamName = "productId";
|
if (newLoanProduct != null) {
|
||||||
if (changes.containsKey(productIdParamName)) {
|
existingLoanApplication.updateLoanProduct(newLoanProduct);
|
||||||
final Long productId = command.longValueOfParameterNamed(productIdParamName);
|
|
||||||
final LoanProduct loanProduct = this.loanProductRepository.findOne(productId);
|
|
||||||
if (loanProduct == null) { throw new LoanProductNotFoundException(productId); }
|
|
||||||
|
|
||||||
existingLoanApplication.updateLoanProduct(loanProduct);
|
|
||||||
if (!changes.containsKey("interestRateFrequencyType")) {
|
if (!changes.containsKey("interestRateFrequencyType")) {
|
||||||
existingLoanApplication.updateInterestRateFrequencyType();
|
existingLoanApplication.updateInterestRateFrequencyType();
|
||||||
}
|
}
|
||||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
|
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
|
||||||
if (loanProduct.useBorrowerCycle()) {
|
if (newLoanProduct.useBorrowerCycle()) {
|
||||||
final Long clientId = this.fromJsonHelper.extractLongNamed("clientId", command.parsedJson());
|
final Long clientId = this.fromJsonHelper.extractLongNamed("clientId", command.parsedJson());
|
||||||
final Long groupId = this.fromJsonHelper.extractLongNamed("groupId", command.parsedJson());
|
final Long groupId = this.fromJsonHelper.extractLongNamed("groupId", command.parsedJson());
|
||||||
Integer cycleNumber = 0;
|
Integer cycleNumber = 0;
|
||||||
if (clientId != null) {
|
if (clientId != null) {
|
||||||
cycleNumber = this.loanReadPlatformService.retriveLoanCounter(clientId, loanProduct.getId());
|
cycleNumber = this.loanReadPlatformService.retriveLoanCounter(clientId, newLoanProduct.getId());
|
||||||
} else if (groupId != null) {
|
} else if (groupId != null) {
|
||||||
cycleNumber = this.loanReadPlatformService.retriveLoanCounter(groupId, AccountType.GROUP.getValue(),
|
cycleNumber = this.loanReadPlatformService.retriveLoanCounter(groupId, AccountType.GROUP.getValue(),
|
||||||
loanProduct.getId());
|
newLoanProduct.getId());
|
||||||
}
|
}
|
||||||
this.loanProductCommandFromApiJsonDeserializer.validateMinMaxConstraints(command.parsedJson(), baseDataValidator,
|
this.loanProductCommandFromApiJsonDeserializer.validateMinMaxConstraints(command.parsedJson(), baseDataValidator,
|
||||||
loanProduct, cycleNumber);
|
newLoanProduct, cycleNumber);
|
||||||
} else {
|
} else {
|
||||||
this.loanProductCommandFromApiJsonDeserializer.validateMinMaxConstraints(command.parsedJson(), baseDataValidator,
|
this.loanProductCommandFromApiJsonDeserializer.validateMinMaxConstraints(command.parsedJson(), baseDataValidator,
|
||||||
loanProduct);
|
newLoanProduct);
|
||||||
|
}
|
||||||
|
if(newLoanProduct.isLinkedToFloatingInterestRate()){
|
||||||
|
existingLoanApplication.getLoanProductRelatedDetail().updateForFloatingInterestRates();
|
||||||
|
}else{
|
||||||
|
existingLoanApplication.setInterestRateDifferential(null);
|
||||||
|
existingLoanApplication.setIsFloatingInterestRate(null);
|
||||||
}
|
}
|
||||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-3
@@ -215,6 +215,9 @@ public class LoanAssembler {
|
|||||||
Group group = null;
|
Group group = null;
|
||||||
|
|
||||||
final LoanProductRelatedDetail loanProductRelatedDetail = this.loanScheduleAssembler.assembleLoanProductRelatedDetail(element);
|
final LoanProductRelatedDetail loanProductRelatedDetail = this.loanScheduleAssembler.assembleLoanProductRelatedDetail(element);
|
||||||
|
|
||||||
|
final BigDecimal interestRateDifferential = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(LoanApiConstants.interestRateDifferentialParameterName, element);
|
||||||
|
final Boolean isFloatingInterestRate = this.fromApiJsonHelper.extractBooleanNamed(LoanApiConstants.isFloatingInterestRateParameterName, element);
|
||||||
|
|
||||||
final String loanTypeParameterName = "loanType";
|
final String loanTypeParameterName = "loanType";
|
||||||
final String loanTypeStr = this.fromApiJsonHelper.extractStringNamed(loanTypeParameterName, element);
|
final String loanTypeStr = this.fromApiJsonHelper.extractStringNamed(loanTypeParameterName, element);
|
||||||
@@ -239,20 +242,21 @@ public class LoanAssembler {
|
|||||||
loanApplication = Loan.newIndividualLoanApplicationFromGroup(accountNo, client, group, loanType.getId().intValue(),
|
loanApplication = Loan.newIndividualLoanApplicationFromGroup(accountNo, client, group, loanType.getId().intValue(),
|
||||||
loanProduct, fund, loanOfficer, loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges,
|
loanProduct, fund, loanOfficer, loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges,
|
||||||
collateral, syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance,
|
collateral, syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance,
|
||||||
createStandingInstructionAtDisbursement);
|
createStandingInstructionAtDisbursement, isFloatingInterestRate, interestRateDifferential);
|
||||||
|
|
||||||
} else if (group != null) {
|
} else if (group != null) {
|
||||||
|
|
||||||
loanApplication = Loan.newGroupLoanApplication(accountNo, group, loanType.getId().intValue(), loanProduct, fund, loanOfficer,
|
loanApplication = Loan.newGroupLoanApplication(accountNo, group, loanType.getId().intValue(), loanProduct, fund, loanOfficer,
|
||||||
loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges, collateral,
|
loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges, collateral,
|
||||||
syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance,
|
syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance,
|
||||||
createStandingInstructionAtDisbursement);
|
createStandingInstructionAtDisbursement,isFloatingInterestRate, interestRateDifferential);
|
||||||
|
|
||||||
} else if (client != null) {
|
} else if (client != null) {
|
||||||
|
|
||||||
loanApplication = Loan.newIndividualLoanApplication(accountNo, client, loanType.getId().intValue(), loanProduct, fund,
|
loanApplication = Loan.newIndividualLoanApplication(accountNo, client, loanType.getId().intValue(), loanProduct, fund,
|
||||||
loanOfficer, loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges, collateral,
|
loanOfficer, loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges, collateral,
|
||||||
fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement);
|
fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement,
|
||||||
|
isFloatingInterestRate, interestRateDifferential);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -14,6 +14,7 @@ import org.mifosplatform.infrastructure.core.service.Page;
|
|||||||
import org.mifosplatform.infrastructure.core.service.SearchParameters;
|
import org.mifosplatform.infrastructure.core.service.SearchParameters;
|
||||||
import org.mifosplatform.organisation.staff.data.StaffData;
|
import org.mifosplatform.organisation.staff.data.StaffData;
|
||||||
import org.mifosplatform.portfolio.calendar.data.CalendarData;
|
import org.mifosplatform.portfolio.calendar.data.CalendarData;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.InterestRatePeriodData;
|
||||||
import org.mifosplatform.portfolio.loanaccount.data.DisbursementData;
|
import org.mifosplatform.portfolio.loanaccount.data.DisbursementData;
|
||||||
import org.mifosplatform.portfolio.loanaccount.data.LoanAccountData;
|
import org.mifosplatform.portfolio.loanaccount.data.LoanAccountData;
|
||||||
import org.mifosplatform.portfolio.loanaccount.data.LoanApprovalData;
|
import org.mifosplatform.portfolio.loanaccount.data.LoanApprovalData;
|
||||||
@@ -95,7 +96,7 @@ public interface LoanReadPlatformService {
|
|||||||
|
|
||||||
Collection<LoanScheduleAccrualData> retrivePeriodicAccrualData(LocalDate tillDate);
|
Collection<LoanScheduleAccrualData> retrivePeriodicAccrualData(LocalDate tillDate);
|
||||||
|
|
||||||
Collection<Long> fetchArrearLoans();
|
Collection<Long> fetchLoansForInterestRecalculation();
|
||||||
|
|
||||||
LoanTransactionData retrieveLoanPrePaymentTemplate(Long loanId, LocalDate onDate);
|
LoanTransactionData retrieveLoanPrePaymentTemplate(Long loanId, LocalDate onDate);
|
||||||
|
|
||||||
@@ -110,4 +111,6 @@ public interface LoanReadPlatformService {
|
|||||||
PaidInAdvanceData retrieveTotalPaidInAdvance(Long loanId);
|
PaidInAdvanceData retrieveTotalPaidInAdvance(Long loanId);
|
||||||
|
|
||||||
LoanTransactionData retrieveRefundByCashTemplate(Long loanId);
|
LoanTransactionData retrieveRefundByCashTemplate(Long loanId);
|
||||||
|
|
||||||
|
Collection<InterestRatePeriodData> retrieveLoanInterestRatePeriodData(Long loanId);
|
||||||
}
|
}
|
||||||
+202
-78
@@ -5,6 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.mifosplatform.portfolio.loanaccount.service;
|
package org.mifosplatform.portfolio.loanaccount.service;
|
||||||
|
|
||||||
|
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.interestType;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
@@ -61,6 +63,10 @@ import org.mifosplatform.portfolio.client.domain.ClientEnumerations;
|
|||||||
import org.mifosplatform.portfolio.client.service.ClientReadPlatformService;
|
import org.mifosplatform.portfolio.client.service.ClientReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
||||||
import org.mifosplatform.portfolio.common.service.CommonEnumerations;
|
import org.mifosplatform.portfolio.common.service.CommonEnumerations;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.InterestRatePeriodData;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRateDTO;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRatePeriodData;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.fund.data.FundData;
|
import org.mifosplatform.portfolio.fund.data.FundData;
|
||||||
import org.mifosplatform.portfolio.fund.service.FundReadPlatformService;
|
import org.mifosplatform.portfolio.fund.service.FundReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.group.data.GroupGeneralData;
|
import org.mifosplatform.portfolio.group.data.GroupGeneralData;
|
||||||
@@ -97,6 +103,7 @@ import org.mifosplatform.portfolio.loanaccount.loanschedule.data.OverdueLoanSche
|
|||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
|
||||||
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
|
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
|
||||||
import org.mifosplatform.portfolio.loanproduct.data.TransactionProcessingStrategyData;
|
import org.mifosplatform.portfolio.loanproduct.data.TransactionProcessingStrategyData;
|
||||||
|
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
|
||||||
import org.mifosplatform.portfolio.loanproduct.service.LoanDropdownReadPlatformService;
|
import org.mifosplatform.portfolio.loanproduct.service.LoanDropdownReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations;
|
import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations;
|
||||||
import org.mifosplatform.portfolio.loanproduct.service.LoanProductReadPlatformService;
|
import org.mifosplatform.portfolio.loanproduct.service.LoanProductReadPlatformService;
|
||||||
@@ -142,6 +149,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
private final WorkingDaysRepositoryWrapper workingDaysRepository;
|
private final WorkingDaysRepositoryWrapper workingDaysRepository;
|
||||||
private final PaymentTypeReadPlatformService paymentTypeReadPlatformService;
|
private final PaymentTypeReadPlatformService paymentTypeReadPlatformService;
|
||||||
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
|
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
|
||||||
|
private final FloatingRatesReadPlatformService floatingRatesReadPlatformService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanReadPlatformServiceImpl(final PlatformSecurityContext context, final LoanRepository loanRepository,
|
public LoanReadPlatformServiceImpl(final PlatformSecurityContext context, final LoanRepository loanRepository,
|
||||||
@@ -155,7 +163,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
final LoanScheduleGeneratorFactory loanScheduleFactory, final CalendarInstanceRepository calendarInstanceRepository,
|
final LoanScheduleGeneratorFactory loanScheduleFactory, final CalendarInstanceRepository calendarInstanceRepository,
|
||||||
final HolidayRepository holidayRepository, final ConfigurationDomainService configurationDomainService,
|
final HolidayRepository holidayRepository, final ConfigurationDomainService configurationDomainService,
|
||||||
final WorkingDaysRepositoryWrapper workingDaysRepository, PaymentTypeReadPlatformService paymentTypeReadPlatformService,
|
final WorkingDaysRepositoryWrapper workingDaysRepository, PaymentTypeReadPlatformService paymentTypeReadPlatformService,
|
||||||
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory) {
|
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
|
||||||
|
final FloatingRatesReadPlatformService floatingRatesReadPlatformService) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.loanRepository = loanRepository;
|
this.loanRepository = loanRepository;
|
||||||
this.loanTransactionRepository = loanTransactionRepository;
|
this.loanTransactionRepository = loanTransactionRepository;
|
||||||
@@ -178,6 +187,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
this.workingDaysRepository = workingDaysRepository;
|
this.workingDaysRepository = workingDaysRepository;
|
||||||
this.paymentTypeReadPlatformService = paymentTypeReadPlatformService;
|
this.paymentTypeReadPlatformService = paymentTypeReadPlatformService;
|
||||||
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
|
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
|
||||||
|
this.floatingRatesReadPlatformService = floatingRatesReadPlatformService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -197,8 +207,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
sqlBuilder.append(" left join m_office transferToOffice on transferToOffice.id = c.transfer_to_office_id ");
|
sqlBuilder.append(" left join m_office transferToOffice on transferToOffice.id = c.transfer_to_office_id ");
|
||||||
sqlBuilder.append(" where l.id=? and ( o.hierarchy like ? or transferToOffice.hierarchy like ?)");
|
sqlBuilder.append(" where l.id=? and ( o.hierarchy like ? or transferToOffice.hierarchy like ?)");
|
||||||
|
|
||||||
return this.jdbcTemplate.queryForObject(sqlBuilder.toString(), rm,
|
return this.jdbcTemplate.queryForObject(sqlBuilder.toString(), rm, new Object[] { loanId, hierarchySearchString,
|
||||||
new Object[] { loanId, hierarchySearchString, hierarchySearchString });
|
hierarchySearchString });
|
||||||
} catch (final EmptyResultDataAccessException e) {
|
} catch (final EmptyResultDataAccessException e) {
|
||||||
throw new LoanNotFoundException(loanId);
|
throw new LoanNotFoundException(loanId);
|
||||||
}
|
}
|
||||||
@@ -236,7 +246,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
/***
|
/***
|
||||||
* TODO Vishwas: Remove references to "Contra" from the codebase
|
* TODO Vishwas: Remove references to "Contra" from the codebase
|
||||||
***/
|
***/
|
||||||
final String sql = "select " + rm.LoanPaymentsSchema()
|
final String sql = "select "
|
||||||
|
+ rm.LoanPaymentsSchema()
|
||||||
+ " where tr.loan_id = ? and tr.transaction_type_enum not in (0, 3) and (tr.is_reversed=0 or tr.manually_adjusted_or_reversed = 1) order by tr.transaction_date ASC,id ";
|
+ " where tr.loan_id = ? and tr.transaction_type_enum not in (0, 3) and (tr.is_reversed=0 or tr.manually_adjusted_or_reversed = 1) order by tr.transaction_date ASC,id ";
|
||||||
return this.jdbcTemplate.query(sql, rm, new Object[] { loanId });
|
return this.jdbcTemplate.query(sql, rm, new Object[] { loanId });
|
||||||
} catch (final EmptyResultDataAccessException e) {
|
} catch (final EmptyResultDataAccessException e) {
|
||||||
@@ -395,10 +406,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
final BigDecimal outstandingLoanBalance = null;
|
final BigDecimal outstandingLoanBalance = null;
|
||||||
final BigDecimal unrecognizedIncomePortion = null;
|
final BigDecimal unrecognizedIncomePortion = null;
|
||||||
return new LoanTransactionData(null, null, null, transactionType, null, currencyData, earliestUnpaidInstallmentDate,
|
return new LoanTransactionData(null, null, null, transactionType, null, currencyData, earliestUnpaidInstallmentDate,
|
||||||
loanRepaymentScheduleInstallment.getTotalOutstanding(currency).getAmount(),
|
loanRepaymentScheduleInstallment.getTotalOutstanding(currency).getAmount(), loanRepaymentScheduleInstallment
|
||||||
loanRepaymentScheduleInstallment.getPrincipalOutstanding(currency).getAmount(),
|
.getPrincipalOutstanding(currency).getAmount(), loanRepaymentScheduleInstallment.getInterestOutstanding(currency)
|
||||||
loanRepaymentScheduleInstallment.getInterestOutstanding(currency).getAmount(),
|
.getAmount(), loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency).getAmount(),
|
||||||
loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency).getAmount(),
|
|
||||||
loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency).getAmount(), null, unrecognizedIncomePortion,
|
loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency).getAmount(), null, unrecognizedIncomePortion,
|
||||||
paymentOptions, null, null, null, outstandingLoanBalance, false);
|
paymentOptions, null, null, null, outstandingLoanBalance, false);
|
||||||
}
|
}
|
||||||
@@ -425,26 +435,26 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
||||||
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||||
CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||||
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
||||||
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(),
|
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan
|
||||||
loan.getDisbursementDate().toDate(), HolidayStatusType.ACTIVE.getValue());
|
.getDisbursementDate().toDate(), HolidayStatusType.ACTIVE.getValue());
|
||||||
final WorkingDays workingDays = this.workingDaysRepository.findOne();
|
final WorkingDays workingDays = this.workingDaysRepository.findOne();
|
||||||
holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
|
||||||
final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = loan.fetchPrepaymentDetail(this.loanScheduleFactory,
|
final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = loan.fetchPrepaymentDetail(this.loanScheduleFactory,
|
||||||
restCalendarInstance, compoundingCalendarInstance, holidayDetailDTO, onDate);
|
restCalendarInstance, compoundingCalendarInstance, holidayDetailDTO, onDate, floatingRateDTO);
|
||||||
final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.REPAYMENT);
|
final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.REPAYMENT);
|
||||||
final Collection<PaymentTypeData> paymentOptions = this.paymentTypeReadPlatformService.retrieveAllPaymentTypes();
|
final Collection<PaymentTypeData> paymentOptions = this.paymentTypeReadPlatformService.retrieveAllPaymentTypes();
|
||||||
final BigDecimal outstandingLoanBalance = loanRepaymentScheduleInstallment.getPrincipalOutstanding(currency).getAmount();
|
final BigDecimal outstandingLoanBalance = loanRepaymentScheduleInstallment.getPrincipalOutstanding(currency).getAmount();
|
||||||
final BigDecimal unrecognizedIncomePortion = null;
|
final BigDecimal unrecognizedIncomePortion = null;
|
||||||
return new LoanTransactionData(null, null, null, transactionType, null, currencyData, earliestUnpaidInstallmentDate,
|
return new LoanTransactionData(null, null, null, transactionType, null, currencyData, earliestUnpaidInstallmentDate,
|
||||||
loanRepaymentScheduleInstallment.getTotalOutstanding(currency).getAmount(),
|
loanRepaymentScheduleInstallment.getTotalOutstanding(currency).getAmount(), loanRepaymentScheduleInstallment
|
||||||
loanRepaymentScheduleInstallment.getPrincipalOutstanding(currency).getAmount(),
|
.getPrincipalOutstanding(currency).getAmount(), loanRepaymentScheduleInstallment.getInterestOutstanding(currency)
|
||||||
loanRepaymentScheduleInstallment.getInterestOutstanding(currency).getAmount(),
|
.getAmount(), loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency).getAmount(),
|
||||||
loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency).getAmount(),
|
|
||||||
loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency).getAmount(), null, unrecognizedIncomePortion,
|
loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency).getAmount(), null, unrecognizedIncomePortion,
|
||||||
paymentOptions, null, null, null, outstandingLoanBalance, false);
|
paymentOptions, null, null, null, outstandingLoanBalance, false);
|
||||||
}
|
}
|
||||||
@@ -544,6 +554,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
return "l.id as id, l.account_no as accountNo, l.external_id as externalId, l.fund_id as fundId, f.name as fundName,"
|
return "l.id as id, l.account_no as accountNo, l.external_id as externalId, l.fund_id as fundId, f.name as fundName,"
|
||||||
+ " l.loan_type_enum as loanType, l.loanpurpose_cv_id as loanPurposeId, cv.code_value as loanPurposeName,"
|
+ " l.loan_type_enum as loanType, l.loanpurpose_cv_id as loanPurposeId, cv.code_value as loanPurposeName,"
|
||||||
+ " lp.id as loanProductId, lp.name as loanProductName, lp.description as loanProductDescription,"
|
+ " lp.id as loanProductId, lp.name as loanProductName, lp.description as loanProductDescription,"
|
||||||
|
+ " lp.is_linked_to_floating_interest_rates as isLoanProductLinkedToFloatingRate, "
|
||||||
+ " lp.allow_multiple_disbursals as multiDisburseLoan,"
|
+ " lp.allow_multiple_disbursals as multiDisburseLoan,"
|
||||||
+ " lp.can_define_fixed_emi_amount as canDefineInstallmentAmount,"
|
+ " lp.can_define_fixed_emi_amount as canDefineInstallmentAmount,"
|
||||||
+ " c.id as clientId, c.display_name as clientName, c.office_id as clientOfficeId,"
|
+ " c.id as clientId, c.display_name as clientName, c.office_id as clientOfficeId,"
|
||||||
@@ -568,14 +579,19 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
+ " lps.name as transactionStrategyName, "
|
+ " lps.name as transactionStrategyName, "
|
||||||
+ " l.currency_code as currencyCode, l.currency_digits as currencyDigits, l.currency_multiplesof as inMultiplesOf, rc.`name` as currencyName, rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, "
|
+ " l.currency_code as currencyCode, l.currency_digits as currencyDigits, l.currency_multiplesof as inMultiplesOf, rc.`name` as currencyName, rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, "
|
||||||
+ " l.loan_officer_id as loanOfficerId, s.display_name as loanOfficerName, "
|
+ " l.loan_officer_id as loanOfficerId, s.display_name as loanOfficerName, "
|
||||||
+ " l.principal_disbursed_derived as principalDisbursed," + " l.principal_repaid_derived as principalPaid,"
|
+ " l.principal_disbursed_derived as principalDisbursed,"
|
||||||
|
+ " l.principal_repaid_derived as principalPaid,"
|
||||||
+ " l.principal_writtenoff_derived as principalWrittenOff,"
|
+ " l.principal_writtenoff_derived as principalWrittenOff,"
|
||||||
+ " l.principal_outstanding_derived as principalOutstanding," + " l.interest_charged_derived as interestCharged,"
|
+ " l.principal_outstanding_derived as principalOutstanding,"
|
||||||
+ " l.interest_repaid_derived as interestPaid," + " l.interest_waived_derived as interestWaived,"
|
+ " l.interest_charged_derived as interestCharged,"
|
||||||
+ " l.interest_writtenoff_derived as interestWrittenOff," + " l.interest_outstanding_derived as interestOutstanding,"
|
+ " l.interest_repaid_derived as interestPaid,"
|
||||||
|
+ " l.interest_waived_derived as interestWaived,"
|
||||||
|
+ " l.interest_writtenoff_derived as interestWrittenOff,"
|
||||||
|
+ " l.interest_outstanding_derived as interestOutstanding,"
|
||||||
+ " l.fee_charges_charged_derived as feeChargesCharged,"
|
+ " l.fee_charges_charged_derived as feeChargesCharged,"
|
||||||
+ " l.total_charges_due_at_disbursement_derived as feeChargesDueAtDisbursementCharged,"
|
+ " l.total_charges_due_at_disbursement_derived as feeChargesDueAtDisbursementCharged,"
|
||||||
+ " l.fee_charges_repaid_derived as feeChargesPaid," + " l.fee_charges_waived_derived as feeChargesWaived,"
|
+ " l.fee_charges_repaid_derived as feeChargesPaid,"
|
||||||
|
+ " l.fee_charges_waived_derived as feeChargesWaived,"
|
||||||
+ " l.fee_charges_writtenoff_derived as feeChargesWrittenOff,"
|
+ " l.fee_charges_writtenoff_derived as feeChargesWrittenOff,"
|
||||||
+ " l.fee_charges_outstanding_derived as feeChargesOutstanding,"
|
+ " l.fee_charges_outstanding_derived as feeChargesOutstanding,"
|
||||||
+ " l.penalty_charges_charged_derived as penaltyChargesCharged,"
|
+ " l.penalty_charges_charged_derived as penaltyChargesCharged,"
|
||||||
@@ -583,14 +599,21 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
+ " l.penalty_charges_waived_derived as penaltyChargesWaived,"
|
+ " l.penalty_charges_waived_derived as penaltyChargesWaived,"
|
||||||
+ " l.penalty_charges_writtenoff_derived as penaltyChargesWrittenOff,"
|
+ " l.penalty_charges_writtenoff_derived as penaltyChargesWrittenOff,"
|
||||||
+ " l.penalty_charges_outstanding_derived as penaltyChargesOutstanding,"
|
+ " l.penalty_charges_outstanding_derived as penaltyChargesOutstanding,"
|
||||||
+ " l.total_expected_repayment_derived as totalExpectedRepayment," + " l.total_repayment_derived as totalRepayment,"
|
+ " l.total_expected_repayment_derived as totalExpectedRepayment,"
|
||||||
+ " l.total_expected_costofloan_derived as totalExpectedCostOfLoan," + " l.total_costofloan_derived as totalCostOfLoan,"
|
+ " l.total_repayment_derived as totalRepayment,"
|
||||||
+ " l.total_waived_derived as totalWaived," + " l.total_writtenoff_derived as totalWrittenOff,"
|
+ " l.total_expected_costofloan_derived as totalExpectedCostOfLoan,"
|
||||||
+ " l.total_outstanding_derived as totalOutstanding," + " l.total_overpaid_derived as totalOverpaid,"
|
+ " l.total_costofloan_derived as totalCostOfLoan,"
|
||||||
+ " l.fixed_emi_amount as fixedEmiAmount," + " l.max_outstanding_loan_balance as outstandingLoanBalance,"
|
+ " l.total_waived_derived as totalWaived,"
|
||||||
+ " la.principal_overdue_derived as principalOverdue," + " la.interest_overdue_derived as interestOverdue,"
|
+ " l.total_writtenoff_derived as totalWrittenOff,"
|
||||||
|
+ " l.total_outstanding_derived as totalOutstanding,"
|
||||||
|
+ " l.total_overpaid_derived as totalOverpaid,"
|
||||||
|
+ " l.fixed_emi_amount as fixedEmiAmount,"
|
||||||
|
+ " l.max_outstanding_loan_balance as outstandingLoanBalance,"
|
||||||
|
+ " la.principal_overdue_derived as principalOverdue,"
|
||||||
|
+ " la.interest_overdue_derived as interestOverdue,"
|
||||||
+ " la.fee_charges_overdue_derived as feeChargesOverdue,"
|
+ " la.fee_charges_overdue_derived as feeChargesOverdue,"
|
||||||
+ " la.penalty_charges_overdue_derived as penaltyChargesOverdue," + " la.total_overdue_derived as totalOverdue,"
|
+ " la.penalty_charges_overdue_derived as penaltyChargesOverdue,"
|
||||||
|
+ " la.total_overdue_derived as totalOverdue,"
|
||||||
+ " la.overdue_since_date_derived as overdueSinceDate,"
|
+ " la.overdue_since_date_derived as overdueSinceDate,"
|
||||||
+ " l.sync_disbursement_with_meeting as syncDisbursementWithMeeting,"
|
+ " l.sync_disbursement_with_meeting as syncDisbursementWithMeeting,"
|
||||||
+ " l.loan_counter as loanCounter, l.loan_product_counter as loanProductCounter,"
|
+ " l.loan_counter as loanCounter, l.loan_product_counter as loanProductCounter,"
|
||||||
@@ -601,7 +624,10 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
+ " lir.rest_freqency_date as restFrequencyDate, "
|
+ " lir.rest_freqency_date as restFrequencyDate, "
|
||||||
+ " lir.compounding_frequency_type_enum as compoundingFrequencyEnum, lir.compounding_frequency_interval as compoundingInterval, "
|
+ " lir.compounding_frequency_type_enum as compoundingFrequencyEnum, lir.compounding_frequency_interval as compoundingInterval, "
|
||||||
+ " lir.compounding_freqency_date as compoundingFrequencyDate, "
|
+ " lir.compounding_freqency_date as compoundingFrequencyDate, "
|
||||||
+ " l.create_standing_instruction_at_disbursement as createStandingInstructionAtDisbursement " + " from m_loan l" //
|
+ " l.is_floating_interest_rate as isFloatingInterestRate, "
|
||||||
|
+ " l.interest_rate_differential as interestRateDifferential, "
|
||||||
|
+ " l.create_standing_instruction_at_disbursement as createStandingInstructionAtDisbursement "
|
||||||
|
+ " from m_loan l" //
|
||||||
+ " join m_product_loan lp on lp.id = l.product_id" //
|
+ " join m_product_loan lp on lp.id = l.product_id" //
|
||||||
+ " left join m_loan_recalculation_details lir on lir.loan_id = l.id "
|
+ " left join m_loan_recalculation_details lir on lir.loan_id = l.id "
|
||||||
+ " join m_currency rc on rc.`code` = l.currency_code" //
|
+ " join m_currency rc on rc.`code` = l.currency_code" //
|
||||||
@@ -614,7 +640,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
+ " left join m_appuser rbu on rbu.id = l.rejectedon_userid"
|
+ " left join m_appuser rbu on rbu.id = l.rejectedon_userid"
|
||||||
+ " left join m_appuser wbu on wbu.id = l.withdrawnon_userid"
|
+ " left join m_appuser wbu on wbu.id = l.withdrawnon_userid"
|
||||||
+ " left join m_appuser abu on abu.id = l.approvedon_userid"
|
+ " left join m_appuser abu on abu.id = l.approvedon_userid"
|
||||||
+ " left join m_appuser dbu on dbu.id = l.disbursedon_userid" + " left join m_appuser cbu on cbu.id = l.closedon_userid"
|
+ " left join m_appuser dbu on dbu.id = l.disbursedon_userid"
|
||||||
|
+ " left join m_appuser cbu on cbu.id = l.closedon_userid"
|
||||||
+ " left join m_code_value cv on cv.id = l.loanpurpose_cv_id"
|
+ " left join m_code_value cv on cv.id = l.loanpurpose_cv_id"
|
||||||
+ " left join ref_loan_transaction_processing_strategy lps on lps.id = l.loan_transaction_strategy_id";
|
+ " left join ref_loan_transaction_processing_strategy lps on lps.id = l.loan_transaction_strategy_id";
|
||||||
}
|
}
|
||||||
@@ -664,6 +691,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
final Long loanProductId = JdbcSupport.getLong(rs, "loanProductId");
|
final Long loanProductId = JdbcSupport.getLong(rs, "loanProductId");
|
||||||
final String loanProductName = rs.getString("loanProductName");
|
final String loanProductName = rs.getString("loanProductName");
|
||||||
final String loanProductDescription = rs.getString("loanProductDescription");
|
final String loanProductDescription = rs.getString("loanProductDescription");
|
||||||
|
final boolean isLoanProductLinkedToFloatingRate = rs.getBoolean("isLoanProductLinkedToFloatingRate");
|
||||||
final Boolean multiDisburseLoan = rs.getBoolean("multiDisburseLoan");
|
final Boolean multiDisburseLoan = rs.getBoolean("multiDisburseLoan");
|
||||||
final Boolean canDefineInstallmentAmount = rs.getBoolean("canDefineInstallmentAmount");
|
final Boolean canDefineInstallmentAmount = rs.getBoolean("canDefineInstallmentAmount");
|
||||||
final BigDecimal outstandingLoanBalance = rs.getBigDecimal("outstandingLoanBalance");
|
final BigDecimal outstandingLoanBalance = rs.getBigDecimal("outstandingLoanBalance");
|
||||||
@@ -720,6 +748,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
final Integer repaymentEvery = JdbcSupport.getInteger(rs, "repaymentEvery");
|
final Integer repaymentEvery = JdbcSupport.getInteger(rs, "repaymentEvery");
|
||||||
final BigDecimal interestRatePerPeriod = rs.getBigDecimal("interestRatePerPeriod");
|
final BigDecimal interestRatePerPeriod = rs.getBigDecimal("interestRatePerPeriod");
|
||||||
final BigDecimal annualInterestRate = rs.getBigDecimal("annualInterestRate");
|
final BigDecimal annualInterestRate = rs.getBigDecimal("annualInterestRate");
|
||||||
|
final BigDecimal interestRateDifferential = rs.getBigDecimal("interestRateDifferential");
|
||||||
|
final boolean isFloatingInterestRate = rs.getBoolean("isFloatingInterestRate");
|
||||||
|
|
||||||
final Integer graceOnPrincipalPayment = JdbcSupport.getIntegerDefaultToNullIfZero(rs, "graceOnPrincipalPayment");
|
final Integer graceOnPrincipalPayment = JdbcSupport.getIntegerDefaultToNullIfZero(rs, "graceOnPrincipalPayment");
|
||||||
final Integer graceOnInterestPayment = JdbcSupport.getIntegerDefaultToNullIfZero(rs, "graceOnInterestPayment");
|
final Integer graceOnInterestPayment = JdbcSupport.getIntegerDefaultToNullIfZero(rs, "graceOnInterestPayment");
|
||||||
@@ -873,16 +903,17 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, groupData,
|
return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, groupData,
|
||||||
loanType, loanProductId, loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName,
|
loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName,
|
||||||
loanOfficerId, loanOfficerName, currencyData, proposedPrincipal, principal, approvedPrincipal, totalOverpaid,
|
loanOfficerId, loanOfficerName, currencyData, proposedPrincipal, principal, approvedPrincipal, totalOverpaid,
|
||||||
inArrearsTolerance, termFrequency, termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType,
|
inArrearsTolerance, termFrequency, termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType,
|
||||||
repaymentFrequencyNthDayType, repaymentFrequencyDayOfWeekType, transactionStrategyId, transactionStrategyName,
|
repaymentFrequencyNthDayType, repaymentFrequencyDayOfWeekType, transactionStrategyId, transactionStrategyName,
|
||||||
amortizationType, interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType,
|
amortizationType, interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType,
|
||||||
interestCalculationPeriodType, expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment,
|
isFloatingInterestRate, interestRateDifferential, interestCalculationPeriodType, expectedFirstRepaymentOnDate,
|
||||||
graceOnInterestCharged, interestChargedFromDate, timeline, loanSummary, feeChargesDueAtDisbursementCharged,
|
graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, timeline,
|
||||||
syncDisbursementWithMeeting, loanCounter, loanProductCounter, multiDisburseLoan, canDefineInstallmentAmount,
|
loanSummary, feeChargesDueAtDisbursementCharged, syncDisbursementWithMeeting, loanCounter, loanProductCounter,
|
||||||
fixedEmiAmount, outstandingLoanBalance, inArrears, graceOnArrearsAgeing, isNPA, daysInMonthType, daysInYearType,
|
multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, outstandingLoanBalance, inArrears, graceOnArrearsAgeing,
|
||||||
isInterestRecalculationEnabled, interestRecalculationData, createStandingInstructionAtDisbursement);
|
isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData,
|
||||||
|
createStandingInstructionAtDisbursement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -895,7 +926,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
+ " ls.fee_charges_amount as feeChargesDue, ls.fee_charges_completed_derived as feeChargesPaid, ls.fee_charges_waived_derived as feeChargesWaived, ls.fee_charges_writtenoff_derived as feeChargesWrittenOff, "
|
+ " ls.fee_charges_amount as feeChargesDue, ls.fee_charges_completed_derived as feeChargesPaid, ls.fee_charges_waived_derived as feeChargesWaived, ls.fee_charges_writtenoff_derived as feeChargesWrittenOff, "
|
||||||
+ " ls.penalty_charges_amount as penaltyChargesDue, ls.penalty_charges_completed_derived as penaltyChargesPaid, ls.penalty_charges_waived_derived as penaltyChargesWaived, ls.penalty_charges_writtenoff_derived as penaltyChargesWrittenOff, "
|
+ " ls.penalty_charges_amount as penaltyChargesDue, ls.penalty_charges_completed_derived as penaltyChargesPaid, ls.penalty_charges_waived_derived as penaltyChargesWaived, ls.penalty_charges_writtenoff_derived as penaltyChargesWrittenOff, "
|
||||||
+ " ls.total_paid_in_advance_derived as totalPaidInAdvanceForPeriod, ls.total_paid_late_derived as totalPaidLateForPeriod, "
|
+ " ls.total_paid_in_advance_derived as totalPaidInAdvanceForPeriod, ls.total_paid_late_derived as totalPaidLateForPeriod, "
|
||||||
+ " mc.amount,mc.id as chargeId " + " from m_loan_repayment_schedule ls "
|
+ " mc.amount,mc.id as chargeId "
|
||||||
|
+ " from m_loan_repayment_schedule ls "
|
||||||
+ " inner join m_loan ml on ml.id = ls.loan_id "
|
+ " inner join m_loan ml on ml.id = ls.loan_id "
|
||||||
+ " join m_product_loan_charge plc on plc.product_loan_id = ml.product_id "
|
+ " join m_product_loan_charge plc on plc.product_loan_id = ml.product_id "
|
||||||
+ " join m_charge mc on mc.id = plc.charge_id ";
|
+ " join m_charge mc on mc.id = plc.charge_id ";
|
||||||
@@ -1032,8 +1064,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
}
|
}
|
||||||
this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(data.amount());
|
this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(data.amount());
|
||||||
} else if (data.isDueForDisbursement(fromDate, dueDate)) {
|
} else if (data.isDueForDisbursement(fromDate, dueDate)) {
|
||||||
if (!excludePastUndisbursed || (excludePastUndisbursed
|
if (!excludePastUndisbursed
|
||||||
&& (data.isDisbursed() || !data.disbursementDate().isBefore(LocalDate.now())))) {
|
|| (excludePastUndisbursed && (data.isDisbursed() || !data.disbursementDate().isBefore(LocalDate.now())))) {
|
||||||
principal = principal.add(data.amount());
|
principal = principal.add(data.amount());
|
||||||
if (data.getChargeAmount() == null) {
|
if (data.getChargeAmount() == null) {
|
||||||
final LoanSchedulePeriodData periodData = LoanSchedulePeriodData.disbursementOnlyPeriod(
|
final LoanSchedulePeriodData periodData = LoanSchedulePeriodData.disbursementOnlyPeriod(
|
||||||
@@ -1093,12 +1125,12 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
"totalPaidInAdvanceForPeriod");
|
"totalPaidInAdvanceForPeriod");
|
||||||
final BigDecimal totalPaidLateForPeriod = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "totalPaidLateForPeriod");
|
final BigDecimal totalPaidLateForPeriod = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "totalPaidLateForPeriod");
|
||||||
|
|
||||||
final BigDecimal penaltyChargesActualDue = penaltyChargesExpectedDue.subtract(penaltyChargesWaived)
|
final BigDecimal penaltyChargesActualDue = penaltyChargesExpectedDue.subtract(penaltyChargesWaived).subtract(
|
||||||
.subtract(penaltyChargesWrittenOff);
|
penaltyChargesWrittenOff);
|
||||||
final BigDecimal penaltyChargesOutstanding = penaltyChargesActualDue.subtract(penaltyChargesPaid);
|
final BigDecimal penaltyChargesOutstanding = penaltyChargesActualDue.subtract(penaltyChargesPaid);
|
||||||
|
|
||||||
final BigDecimal totalExpectedCostOfLoanForPeriod = interestExpectedDue.add(feeChargesExpectedDue)
|
final BigDecimal totalExpectedCostOfLoanForPeriod = interestExpectedDue.add(feeChargesExpectedDue).add(
|
||||||
.add(penaltyChargesExpectedDue);
|
penaltyChargesExpectedDue);
|
||||||
|
|
||||||
final BigDecimal totalDueForPeriod = principalDue.add(totalExpectedCostOfLoanForPeriod);
|
final BigDecimal totalDueForPeriod = principalDue.add(totalExpectedCostOfLoanForPeriod);
|
||||||
final BigDecimal totalPaidForPeriod = principalPaid.add(interestPaid).add(feeChargesPaid).add(penaltyChargesPaid);
|
final BigDecimal totalPaidForPeriod = principalPaid.add(interestPaid).add(feeChargesPaid).add(penaltyChargesPaid);
|
||||||
@@ -1139,11 +1171,11 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
periods.add(periodData);
|
periods.add(periodData);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new LoanScheduleData(this.currency, periods, loanTermInDays, totalPrincipalDisbursed, totalPrincipalExpected.getAmount(),
|
return new LoanScheduleData(this.currency, periods, loanTermInDays, totalPrincipalDisbursed,
|
||||||
totalPrincipalPaid.getAmount(), totalInterestCharged.getAmount(), totalFeeChargesCharged.getAmount(),
|
totalPrincipalExpected.getAmount(), totalPrincipalPaid.getAmount(), totalInterestCharged.getAmount(),
|
||||||
totalPenaltyChargesCharged.getAmount(), totalWaived.getAmount(), totalWrittenOff.getAmount(),
|
totalFeeChargesCharged.getAmount(), totalPenaltyChargesCharged.getAmount(), totalWaived.getAmount(),
|
||||||
totalRepaymentExpected.getAmount(), totalRepayment.getAmount(), totalPaidInAdvance.getAmount(),
|
totalWrittenOff.getAmount(), totalRepaymentExpected.getAmount(), totalRepayment.getAmount(),
|
||||||
totalPaidLate.getAmount(), totalOutstanding.getAmount());
|
totalPaidInAdvance.getAmount(), totalPaidLate.getAmount(), totalOutstanding.getAmount());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1156,7 +1188,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
+ " tr.principal_portion_derived as principal, tr.interest_portion_derived as interest, "
|
+ " tr.principal_portion_derived as principal, tr.interest_portion_derived as interest, "
|
||||||
+ " tr.fee_charges_portion_derived as fees, tr.penalty_charges_portion_derived as penalties, "
|
+ " tr.fee_charges_portion_derived as fees, tr.penalty_charges_portion_derived as penalties, "
|
||||||
+ " tr.overpayment_portion_derived as overpayment, tr.outstanding_loan_balance_derived as outstandingLoanBalance, "
|
+ " tr.overpayment_portion_derived as overpayment, tr.outstanding_loan_balance_derived as outstandingLoanBalance, "
|
||||||
+ " tr.unrecognized_income_portion as unrecognizedIncome," + " tr.submitted_on_date as submittedOnDate, "
|
+ " tr.unrecognized_income_portion as unrecognizedIncome,"
|
||||||
|
+ " tr.submitted_on_date as submittedOnDate, "
|
||||||
+ " tr.manually_adjusted_or_reversed as manuallyReversed, "
|
+ " tr.manually_adjusted_or_reversed as manuallyReversed, "
|
||||||
+ " pd.payment_type_id as paymentType,pd.account_number as accountNumber,pd.check_number as checkNumber, "
|
+ " pd.payment_type_id as paymentType,pd.account_number as accountNumber,pd.check_number as checkNumber, "
|
||||||
+ " pd.receipt_number as receiptNumber, pd.bank_number as bankNumber,pd.routing_code as routingCode, "
|
+ " pd.receipt_number as receiptNumber, pd.bank_number as bankNumber,pd.routing_code as routingCode, "
|
||||||
@@ -1260,7 +1293,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
+ " fromtran.description as fromTransferDescription,"
|
+ " fromtran.description as fromTransferDescription,"
|
||||||
+ " totran.id as toTransferId, totran.is_reversed as toTransferReversed,"
|
+ " totran.id as toTransferId, totran.is_reversed as toTransferReversed,"
|
||||||
+ " totran.transaction_date as toTransferDate, totran.amount as toTransferAmount,"
|
+ " totran.transaction_date as toTransferDate, totran.amount as toTransferAmount,"
|
||||||
+ " totran.description as toTransferDescription " + " from m_loan l join m_loan_transaction tr on tr.loan_id = l.id"
|
+ " totran.description as toTransferDescription "
|
||||||
|
+ " from m_loan l join m_loan_transaction tr on tr.loan_id = l.id"
|
||||||
+ " join m_currency rc on rc.`code` = l.currency_code "
|
+ " join m_currency rc on rc.`code` = l.currency_code "
|
||||||
+ " left join m_account_transfer_transaction fromtran on fromtran.from_loan_transaction_id = tr.id "
|
+ " left join m_account_transfer_transaction fromtran on fromtran.from_loan_transaction_id = tr.id "
|
||||||
+ " left join m_account_transfer_transaction totran on totran.to_loan_transaction_id = tr.id ";
|
+ " left join m_account_transfer_transaction totran on totran.to_loan_transaction_id = tr.id ";
|
||||||
@@ -1320,7 +1354,12 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
.retrieveInterestRateFrequencyTypeOptions();
|
.retrieveInterestRateFrequencyTypeOptions();
|
||||||
final Collection<EnumOptionData> amortizationTypeOptions = this.loanDropdownReadPlatformService
|
final Collection<EnumOptionData> amortizationTypeOptions = this.loanDropdownReadPlatformService
|
||||||
.retrieveLoanAmortizationTypeOptions();
|
.retrieveLoanAmortizationTypeOptions();
|
||||||
final Collection<EnumOptionData> interestTypeOptions = this.loanDropdownReadPlatformService.retrieveLoanInterestTypeOptions();
|
Collection<EnumOptionData> interestTypeOptions = null;
|
||||||
|
if (loanProduct.isLinkedToFloatingInterestRates()) {
|
||||||
|
interestTypeOptions = Arrays.asList(interestType(InterestMethod.DECLINING_BALANCE));
|
||||||
|
} else {
|
||||||
|
interestTypeOptions = this.loanDropdownReadPlatformService.retrieveLoanInterestTypeOptions();
|
||||||
|
}
|
||||||
final Collection<EnumOptionData> interestCalculationPeriodTypeOptions = this.loanDropdownReadPlatformService
|
final Collection<EnumOptionData> interestCalculationPeriodTypeOptions = this.loanDropdownReadPlatformService
|
||||||
.retrieveLoanInterestRateCalculatedInPeriodOptions();
|
.retrieveLoanInterestRateCalculatedInPeriodOptions();
|
||||||
final Collection<FundData> fundOptions = this.fundReadPlatformService.retrieveAllFunds();
|
final Collection<FundData> fundOptions = this.fundReadPlatformService.retrieveAllFunds();
|
||||||
@@ -1334,8 +1373,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
chargeOptions = this.chargeReadPlatformService.retrieveLoanProductApplicableCharges(productId,
|
chargeOptions = this.chargeReadPlatformService.retrieveLoanProductApplicableCharges(productId,
|
||||||
new ChargeTimeType[] { ChargeTimeType.OVERDUE_INSTALLMENT });
|
new ChargeTimeType[] { ChargeTimeType.OVERDUE_INSTALLMENT });
|
||||||
} else {
|
} else {
|
||||||
chargeOptions = this.chargeReadPlatformService.retrieveLoanProductApplicableCharges(productId,
|
chargeOptions = this.chargeReadPlatformService.retrieveLoanProductApplicableCharges(productId, new ChargeTimeType[] {
|
||||||
new ChargeTimeType[] { ChargeTimeType.OVERDUE_INSTALLMENT, ChargeTimeType.TRANCHE_DISBURSEMENT });
|
ChargeTimeType.OVERDUE_INSTALLMENT, ChargeTimeType.TRANCHE_DISBURSEMENT });
|
||||||
}
|
}
|
||||||
|
|
||||||
Integer loanCycleCounter = null;
|
Integer loanCycleCounter = null;
|
||||||
@@ -1395,8 +1434,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
@Override
|
@Override
|
||||||
public Collection<CalendarData> retrieveCalendars(final Long groupId) {
|
public Collection<CalendarData> retrieveCalendars(final Long groupId) {
|
||||||
Collection<CalendarData> calendarsData = new ArrayList<>();
|
Collection<CalendarData> calendarsData = new ArrayList<>();
|
||||||
calendarsData.addAll(
|
calendarsData.addAll(this.calendarReadPlatformService.retrieveParentCalendarsByEntity(groupId,
|
||||||
this.calendarReadPlatformService.retrieveParentCalendarsByEntity(groupId, CalendarEntityType.GROUPS.getValue(), null));
|
CalendarEntityType.GROUPS.getValue(), null));
|
||||||
calendarsData
|
calendarsData
|
||||||
.addAll(this.calendarReadPlatformService.retrieveCalendarsByEntity(groupId, CalendarEntityType.GROUPS.getValue(), null));
|
.addAll(this.calendarReadPlatformService.retrieveCalendarsByEntity(groupId, CalendarEntityType.GROUPS.getValue(), null));
|
||||||
calendarsData = this.calendarReadPlatformService.updateWithRecurringDates(calendarsData);
|
calendarsData = this.calendarReadPlatformService.updateWithRecurringDates(calendarsData);
|
||||||
@@ -1518,13 +1557,15 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
|
|
||||||
LoanScheduleAccrualMapper mapper = new LoanScheduleAccrualMapper();
|
LoanScheduleAccrualMapper mapper = new LoanScheduleAccrualMapper();
|
||||||
final StringBuilder sqlBuilder = new StringBuilder(400);
|
final StringBuilder sqlBuilder = new StringBuilder(400);
|
||||||
sqlBuilder.append("select ").append(mapper.schema())
|
sqlBuilder
|
||||||
|
.append("select ")
|
||||||
|
.append(mapper.schema())
|
||||||
.append(" where ((ls.fee_charges_amount <> if(ls.accrual_fee_charges_derived is null,0, ls.accrual_fee_charges_derived))")
|
.append(" where ((ls.fee_charges_amount <> if(ls.accrual_fee_charges_derived is null,0, ls.accrual_fee_charges_derived))")
|
||||||
.append(" or ( ls.penalty_charges_amount <> if(ls.accrual_penalty_charges_derived is null,0,ls.accrual_penalty_charges_derived))")
|
.append(" or ( ls.penalty_charges_amount <> if(ls.accrual_penalty_charges_derived is null,0,ls.accrual_penalty_charges_derived))")
|
||||||
.append(" or ( ls.interest_amount <> if(ls.accrual_interest_derived is null,0,ls.accrual_interest_derived)))")
|
.append(" or ( ls.interest_amount <> if(ls.accrual_interest_derived is null,0,ls.accrual_interest_derived)))")
|
||||||
.append(" and loan.loan_status_id=? and mpl.accounting_type=? and loan.is_npa=0 and ls.duedate <= CURDATE() order by loan.id,ls.duedate");
|
.append(" and loan.loan_status_id=? and mpl.accounting_type=? and loan.is_npa=0 and ls.duedate <= CURDATE() order by loan.id,ls.duedate");
|
||||||
return this.jdbcTemplate.query(sqlBuilder.toString(), mapper,
|
return this.jdbcTemplate.query(sqlBuilder.toString(), mapper, new Object[] { LoanStatus.ACTIVE.getValue(),
|
||||||
new Object[] { LoanStatus.ACTIVE.getValue(), AccountingRuleType.ACCRUAL_PERIODIC.getValue() });
|
AccountingRuleType.ACCRUAL_PERIODIC.getValue() });
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1532,7 +1573,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
|
|
||||||
LoanSchedulePeriodicAccrualMapper mapper = new LoanSchedulePeriodicAccrualMapper();
|
LoanSchedulePeriodicAccrualMapper mapper = new LoanSchedulePeriodicAccrualMapper();
|
||||||
final StringBuilder sqlBuilder = new StringBuilder(400);
|
final StringBuilder sqlBuilder = new StringBuilder(400);
|
||||||
sqlBuilder.append("select ").append(mapper.schema())
|
sqlBuilder
|
||||||
|
.append("select ")
|
||||||
|
.append(mapper.schema())
|
||||||
.append(" where ((ls.fee_charges_amount <> if(ls.accrual_fee_charges_derived is null,0, ls.accrual_fee_charges_derived))")
|
.append(" where ((ls.fee_charges_amount <> if(ls.accrual_fee_charges_derived is null,0, ls.accrual_fee_charges_derived))")
|
||||||
.append(" or (ls.penalty_charges_amount <> if(ls.accrual_penalty_charges_derived is null,0,ls.accrual_penalty_charges_derived))")
|
.append(" or (ls.penalty_charges_amount <> if(ls.accrual_penalty_charges_derived is null,0,ls.accrual_penalty_charges_derived))")
|
||||||
.append(" or (ls.interest_amount <> if(ls.accrual_interest_derived is null,0,ls.accrual_interest_derived)))")
|
.append(" or (ls.interest_amount <> if(ls.accrual_interest_derived is null,0,ls.accrual_interest_derived)))")
|
||||||
@@ -1549,13 +1592,16 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
|
|
||||||
public String schema() {
|
public String schema() {
|
||||||
final StringBuilder sqlBuilder = new StringBuilder(400);
|
final StringBuilder sqlBuilder = new StringBuilder(400);
|
||||||
sqlBuilder.append("loan.id as loanId ,if(loan.client_id is null,mg.office_id,mc.office_id) as officeId,")
|
sqlBuilder
|
||||||
|
.append("loan.id as loanId ,if(loan.client_id is null,mg.office_id,mc.office_id) as officeId,")
|
||||||
.append("loan.accrued_till as accruedTill, loan.repayment_period_frequency_enum as frequencyEnum, ")
|
.append("loan.accrued_till as accruedTill, loan.repayment_period_frequency_enum as frequencyEnum, ")
|
||||||
.append("loan.interest_calculated_from_date as interestCalculatedFrom, ").append("loan.repay_every as repayEvery,")
|
.append("loan.interest_calculated_from_date as interestCalculatedFrom, ")
|
||||||
|
.append("loan.repay_every as repayEvery,")
|
||||||
.append("ls.installment as installmentNumber, ")
|
.append("ls.installment as installmentNumber, ")
|
||||||
.append("ls.duedate as duedate,ls.fromdate as fromdate ,ls.id as scheduleId,loan.product_id as productId,")
|
.append("ls.duedate as duedate,ls.fromdate as fromdate ,ls.id as scheduleId,loan.product_id as productId,")
|
||||||
.append("ls.interest_amount as interest, ls.interest_waived_derived as interestWaived,")
|
.append("ls.interest_amount as interest, ls.interest_waived_derived as interestWaived,")
|
||||||
.append("ls.penalty_charges_amount as penalty, ").append("ls.fee_charges_amount as charges, ")
|
.append("ls.penalty_charges_amount as penalty, ")
|
||||||
|
.append("ls.fee_charges_amount as charges, ")
|
||||||
.append("ls.accrual_interest_derived as accinterest,ls.accrual_fee_charges_derived as accfeecharege,ls.accrual_penalty_charges_derived as accpenalty,")
|
.append("ls.accrual_interest_derived as accinterest,ls.accrual_fee_charges_derived as accfeecharege,ls.accrual_penalty_charges_derived as accpenalty,")
|
||||||
.append(" loan.currency_code as currencyCode,loan.currency_digits as currencyDigits,loan.currency_multiplesof as inMultiplesOf,")
|
.append(" loan.currency_code as currencyCode,loan.currency_digits as currencyDigits,loan.currency_multiplesof as inMultiplesOf,")
|
||||||
.append("curr.display_symbol as currencyDisplaySymbol,curr.name as currencyName,curr.internationalized_name_code as currencyNameCode")
|
.append("curr.display_symbol as currencyDisplaySymbol,curr.name as currencyName,curr.internationalized_name_code as currencyNameCode")
|
||||||
@@ -1610,11 +1656,13 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
|
|
||||||
public String schema() {
|
public String schema() {
|
||||||
final StringBuilder sqlBuilder = new StringBuilder(400);
|
final StringBuilder sqlBuilder = new StringBuilder(400);
|
||||||
sqlBuilder.append("loan.id as loanId ,if(loan.client_id is null,mg.office_id,mc.office_id) as officeId,")
|
sqlBuilder
|
||||||
|
.append("loan.id as loanId ,if(loan.client_id is null,mg.office_id,mc.office_id) as officeId,")
|
||||||
.append("ls.duedate as duedate,ls.fromdate as fromdate,ls.id as scheduleId,loan.product_id as productId,")
|
.append("ls.duedate as duedate,ls.fromdate as fromdate,ls.id as scheduleId,loan.product_id as productId,")
|
||||||
.append("ls.installment as installmentNumber, ")
|
.append("ls.installment as installmentNumber, ")
|
||||||
.append("ls.interest_amount as interest, ls.interest_waived_derived as interestWaived,")
|
.append("ls.interest_amount as interest, ls.interest_waived_derived as interestWaived,")
|
||||||
.append("ls.penalty_charges_amount as penalty, ").append("ls.fee_charges_amount as charges, ")
|
.append("ls.penalty_charges_amount as penalty, ")
|
||||||
|
.append("ls.fee_charges_amount as charges, ")
|
||||||
.append("ls.accrual_interest_derived as accinterest,ls.accrual_fee_charges_derived as accfeecharege,ls.accrual_penalty_charges_derived as accpenalty,")
|
.append("ls.accrual_interest_derived as accinterest,ls.accrual_fee_charges_derived as accfeecharege,ls.accrual_penalty_charges_derived as accpenalty,")
|
||||||
.append(" loan.currency_code as currencyCode,loan.currency_digits as currencyDigits,loan.currency_multiplesof as inMultiplesOf,")
|
.append(" loan.currency_code as currencyCode,loan.currency_digits as currencyDigits,loan.currency_multiplesof as inMultiplesOf,")
|
||||||
.append("curr.display_symbol as currencyDisplaySymbol,curr.name as currencyName,curr.internationalized_name_code as currencyNameCode")
|
.append("curr.display_symbol as currencyDisplaySymbol,curr.name as currencyName,curr.internationalized_name_code as currencyNameCode")
|
||||||
@@ -1687,24 +1735,42 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Long> fetchArrearLoans() {
|
public Collection<Long> fetchLoansForInterestRecalculation() {
|
||||||
StringBuilder sqlBuilder = new StringBuilder();
|
StringBuilder sqlBuilder = new StringBuilder();
|
||||||
sqlBuilder.append("SELECT ml.id FROM m_loan ml ");
|
sqlBuilder.append("SELECT ml.id FROM m_loan ml ");
|
||||||
sqlBuilder.append(" INNER JOIN m_loan_repayment_schedule mr on mr.loan_id = ml.id ");
|
sqlBuilder.append(" INNER JOIN m_loan_repayment_schedule mr on mr.loan_id = ml.id ");
|
||||||
sqlBuilder.append(" LEFT JOIN m_loan_disbursement_detail dd on dd.loan_id=ml.id and dd.disbursedon_date is null ");
|
sqlBuilder.append(" LEFT JOIN m_loan_disbursement_detail dd on dd.loan_id=ml.id and dd.disbursedon_date is null ");
|
||||||
|
// For Floating rate changes
|
||||||
|
sqlBuilder
|
||||||
|
.append(" left join m_product_loan_floating_rates pfr on ml.product_id = pfr.loan_product_id and ml.is_floating_interest_rate = 1");
|
||||||
|
sqlBuilder.append(" left join m_floating_rates fr on pfr.floating_rates_id = fr.id");
|
||||||
|
sqlBuilder.append(" left join m_floating_rates_periods frp on fr.id = frp.floating_rates_id ");
|
||||||
|
sqlBuilder.append(" left join m_loan_reschedule_request lrr on lrr.loan_id = ml.id");
|
||||||
|
// this is to identify the applicable rates when base rate is changed
|
||||||
|
sqlBuilder.append(" left join m_floating_rates bfr on bfr.is_base_lending_rate = 1");
|
||||||
|
sqlBuilder.append(" left join m_floating_rates_periods bfrp on bfr.id = bfrp.floating_rates_id and bfrp.created_date >= ?");
|
||||||
sqlBuilder.append(" WHERE ml.loan_status_id = ? ");
|
sqlBuilder.append(" WHERE ml.loan_status_id = ? ");
|
||||||
sqlBuilder.append(" and ml.interest_recalculation_enabled = 1 ");
|
|
||||||
sqlBuilder.append(" and ml.is_npa = 0 ");
|
sqlBuilder.append(" and ml.is_npa = 0 ");
|
||||||
|
sqlBuilder.append(" and ((");
|
||||||
|
sqlBuilder.append("ml.interest_recalculation_enabled = 1 ");
|
||||||
sqlBuilder.append(" and (ml.interest_recalcualated_on is null or ml.interest_recalcualated_on <> ?)");
|
sqlBuilder.append(" and (ml.interest_recalcualated_on is null or ml.interest_recalcualated_on <> ?)");
|
||||||
sqlBuilder.append(" and ((");
|
sqlBuilder.append(" and ((");
|
||||||
sqlBuilder.append(" mr.completed_derived is false ");
|
sqlBuilder.append(" mr.completed_derived is false ");
|
||||||
sqlBuilder.append(" and mr.duedate < ? )");
|
sqlBuilder.append(" and mr.duedate < ? )");
|
||||||
sqlBuilder.append(" or dd.expected_disburse_date < ? ) ");
|
sqlBuilder.append(" or dd.expected_disburse_date < ? )) ");
|
||||||
|
sqlBuilder.append(" or (");
|
||||||
|
sqlBuilder.append(" fr.is_active = 1 and frp.is_active = 1");
|
||||||
|
sqlBuilder.append(" and (frp.created_date >= ? or ");
|
||||||
|
sqlBuilder.append("(bfrp.id is not null and frp.is_differential_to_base_lending_rate = 1 and frp.from_date >= bfrp.from_date)) ");
|
||||||
|
sqlBuilder.append("and lrr.loan_id is null");
|
||||||
|
sqlBuilder.append(" ))");
|
||||||
sqlBuilder.append(" group by ml.id");
|
sqlBuilder.append(" group by ml.id");
|
||||||
try {
|
try {
|
||||||
String currentdate = formatter.print(DateUtils.getLocalDateOfTenant());
|
String currentdate = formatter.print(DateUtils.getLocalDateOfTenant());
|
||||||
return this.jdbcTemplate.queryForList(sqlBuilder.toString(), Long.class,
|
// will look only for yesterday modified rates
|
||||||
new Object[] { LoanStatus.ACTIVE.getValue(), currentdate, currentdate, currentdate });
|
String yesterday = formatter.print(DateUtils.getLocalDateOfTenant().minusDays(1));
|
||||||
|
return this.jdbcTemplate.queryForList(sqlBuilder.toString(), Long.class, new Object[] { yesterday,
|
||||||
|
LoanStatus.ACTIVE.getValue(), currentdate, currentdate, currentdate, yesterday });
|
||||||
} catch (final EmptyResultDataAccessException e) {
|
} catch (final EmptyResultDataAccessException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -1835,10 +1901,10 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
|
|
||||||
return LoanSchedulePeriodData.repaymentPeriodWithPayments(loanId, period, fromDate, dueDate, obligationsMetOnDate, complete,
|
return LoanSchedulePeriodData.repaymentPeriodWithPayments(loanId, period, fromDate, dueDate, obligationsMetOnDate, complete,
|
||||||
principalOriginalDue, principalPaid, principalWrittenOff, principalOutstanding, outstandingPrincipalBalanceOfLoan,
|
principalOriginalDue, principalPaid, principalWrittenOff, principalOutstanding, outstandingPrincipalBalanceOfLoan,
|
||||||
interestDueOnPrincipalOutstanding, interestPaid, interestWaived, interestWrittenOff, interestOutstanding, feeChargesDue,
|
interestDueOnPrincipalOutstanding, interestPaid, interestWaived, interestWrittenOff, interestOutstanding,
|
||||||
feeChargesPaid, feeChargesWaived, feeChargesWrittenOff, feeChargesOutstanding, penaltyChargesDue, penaltyChargesPaid,
|
feeChargesDue, feeChargesPaid, feeChargesWaived, feeChargesWrittenOff, feeChargesOutstanding, penaltyChargesDue,
|
||||||
penaltyChargesWaived, penaltyChargesWrittenOff, penaltyChargesOutstanding, totalDueForPeriod, totalPaid,
|
penaltyChargesPaid, penaltyChargesWaived, penaltyChargesWrittenOff, penaltyChargesOutstanding, totalDueForPeriod,
|
||||||
totalPaidInAdvanceForPeriod, totalPaidLateForPeriod, totalWaived, totalWrittenOff, totalOutstanding,
|
totalPaid, totalPaidInAdvanceForPeriod, totalPaidLateForPeriod, totalWaived, totalWrittenOff, totalOutstanding,
|
||||||
totalActualCostOfLoanForPeriod);
|
totalActualCostOfLoanForPeriod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1847,8 +1913,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
public Date retrieveMinimumDateOfRepaymentTransaction(Long loanId) {
|
public Date retrieveMinimumDateOfRepaymentTransaction(Long loanId) {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
Date date = this.jdbcTemplate.queryForObject(
|
Date date = this.jdbcTemplate.queryForObject(
|
||||||
"select min(transaction_date) from m_loan_transaction where loan_id=? and transaction_type_enum=2", new Object[] { loanId },
|
"select min(transaction_date) from m_loan_transaction where loan_id=? and transaction_type_enum=2",
|
||||||
Date.class);
|
new Object[] { loanId }, Date.class);
|
||||||
|
|
||||||
return date;
|
return date;
|
||||||
}
|
}
|
||||||
@@ -1894,8 +1960,66 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
final Collection<PaymentTypeData> paymentOptions = this.paymentTypeReadPlatformService.retrieveAllPaymentTypes();
|
final Collection<PaymentTypeData> paymentOptions = this.paymentTypeReadPlatformService.retrieveAllPaymentTypes();
|
||||||
|
|
||||||
return new LoanTransactionData(null, null, null, transactionType, null, currencyData, earliestUnpaidInstallmentDate,
|
return new LoanTransactionData(null, null, null, transactionType, null, currencyData, earliestUnpaidInstallmentDate,
|
||||||
retrieveTotalPaidInAdvance(loan.getId()).getPaidInAdvance(), null, null, null, null, null, null, paymentOptions, null, null,
|
retrieveTotalPaidInAdvance(loan.getId()).getPaidInAdvance(), null, null, null, null, null, null, paymentOptions, null,
|
||||||
null, null, false);
|
null, null, null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FloatingRateDTO constructFloatingRateDTO(final Loan loan) {
|
||||||
|
FloatingRateDTO floatingRateDTO = null;
|
||||||
|
if (loan.loanProduct().isLinkedToFloatingInterestRate()) {
|
||||||
|
boolean isFloatingInterestRate = loan.getIsFloatingInterestRate();
|
||||||
|
BigDecimal interestRateDiff = loan.getInterestRateDifferential();
|
||||||
|
List<FloatingRatePeriodData> baseLendingRatePeriods = this.floatingRatesReadPlatformService.retrieveBaseLendingRate()
|
||||||
|
.getRatePeriods();
|
||||||
|
floatingRateDTO = new FloatingRateDTO(isFloatingInterestRate, loan.getDisbursementDate(), interestRateDiff,
|
||||||
|
baseLendingRatePeriods);
|
||||||
|
}
|
||||||
|
return floatingRateDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<InterestRatePeriodData> retrieveLoanInterestRatePeriodData(Long loanId) {
|
||||||
|
this.context.authenticatedUser();
|
||||||
|
|
||||||
|
final Loan loan = this.loanRepository.findOne(loanId);
|
||||||
|
if (loan == null) { throw new LoanNotFoundException(loanId); }
|
||||||
|
|
||||||
|
if (loan.loanProduct().isLinkedToFloatingInterestRate()) {
|
||||||
|
final Collection<InterestRatePeriodData> intRatePeriodData = new ArrayList<>();
|
||||||
|
final Collection<InterestRatePeriodData> intRates = this.floatingRatesReadPlatformService.retrieveInterestRatePeriods(loan
|
||||||
|
.loanProduct().getFloatingRates().getFloatingRate().getId());
|
||||||
|
for (final InterestRatePeriodData rate : intRates) {
|
||||||
|
if (rate.getFromDate().compareTo(loan.getSubmittedOnDate().toDate()) > 0 && loan.getIsFloatingInterestRate()) {
|
||||||
|
updateInterestRatePeriodData(rate, loan);
|
||||||
|
intRatePeriodData.add(rate);
|
||||||
|
} else if (rate.getFromDate().compareTo(loan.getSubmittedOnDate().toDate()) <= 0) {
|
||||||
|
updateInterestRatePeriodData(rate, loan);
|
||||||
|
intRatePeriodData.add(rate);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return intRatePeriodData;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateInterestRatePeriodData(InterestRatePeriodData rate, Loan loan) {
|
||||||
|
rate.setLoanProductDifferentialInterestRate(loan.loanProduct().getFloatingRates().getInterestRateDifferential());
|
||||||
|
rate.setLoanDifferentialInterestRate(loan.getInterestRateDifferential());
|
||||||
|
|
||||||
|
BigDecimal effectiveInterestRate = BigDecimal.ZERO;
|
||||||
|
effectiveInterestRate = effectiveInterestRate.add(rate.getLoanDifferentialInterestRate());
|
||||||
|
effectiveInterestRate = effectiveInterestRate.add(rate.getLoanProductDifferentialInterestRate());
|
||||||
|
effectiveInterestRate = effectiveInterestRate.add(rate.getInterestRate());
|
||||||
|
if (rate.getBlrInterestRate() != null && rate.isDifferentialToBLR()) {
|
||||||
|
effectiveInterestRate = effectiveInterestRate.add(rate.getBlrInterestRate());
|
||||||
|
}
|
||||||
|
rate.setEffectiveInterestRate(effectiveInterestRate);
|
||||||
|
|
||||||
|
if (rate.getFromDate().compareTo(loan.getSubmittedOnDate().toDate()) < 0) {
|
||||||
|
rate.setFromDate(loan.getSubmittedOnDate().toDate());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+7
-3
@@ -18,6 +18,7 @@ import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidation
|
|||||||
import org.mifosplatform.infrastructure.jobs.annotation.CronTarget;
|
import org.mifosplatform.infrastructure.jobs.annotation.CronTarget;
|
||||||
import org.mifosplatform.infrastructure.jobs.exception.JobExecutionException;
|
import org.mifosplatform.infrastructure.jobs.exception.JobExecutionException;
|
||||||
import org.mifosplatform.infrastructure.jobs.service.JobName;
|
import org.mifosplatform.infrastructure.jobs.service.JobName;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.OverdueLoanScheduleData;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.OverdueLoanScheduleData;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -31,13 +32,16 @@ public class LoanSchedularServiceImpl implements LoanSchedularService {
|
|||||||
private final ConfigurationDomainService configurationDomainService;
|
private final ConfigurationDomainService configurationDomainService;
|
||||||
private final LoanReadPlatformService loanReadPlatformService;
|
private final LoanReadPlatformService loanReadPlatformService;
|
||||||
private final LoanWritePlatformService loanWritePlatformService;
|
private final LoanWritePlatformService loanWritePlatformService;
|
||||||
|
private final FloatingRatesReadPlatformService floatingRatesReadPlatformService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanSchedularServiceImpl(final ConfigurationDomainService configurationDomainService,
|
public LoanSchedularServiceImpl(final ConfigurationDomainService configurationDomainService,
|
||||||
final LoanReadPlatformService loanReadPlatformService, final LoanWritePlatformService loanWritePlatformService) {
|
final LoanReadPlatformService loanReadPlatformService, final LoanWritePlatformService loanWritePlatformService,
|
||||||
|
final FloatingRatesReadPlatformService floatingRatesReadPlatformService) {
|
||||||
this.configurationDomainService = configurationDomainService;
|
this.configurationDomainService = configurationDomainService;
|
||||||
this.loanReadPlatformService = loanReadPlatformService;
|
this.loanReadPlatformService = loanReadPlatformService;
|
||||||
this.loanWritePlatformService = loanWritePlatformService;
|
this.loanWritePlatformService = loanWritePlatformService;
|
||||||
|
this.floatingRatesReadPlatformService = floatingRatesReadPlatformService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -92,11 +96,11 @@ public class LoanSchedularServiceImpl implements LoanSchedularService {
|
|||||||
if (sb.length() > 0) { throw new JobExecutionException(sb.toString()); }
|
if (sb.length() > 0) { throw new JobExecutionException(sb.toString()); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@CronTarget(jobName = JobName.RECALCULATE_INTEREST_FOR_LOAN)
|
@CronTarget(jobName = JobName.RECALCULATE_INTEREST_FOR_LOAN)
|
||||||
public void recalculateInterest() {
|
public void recalculateInterest() {
|
||||||
Collection<Long> loanIds = this.loanReadPlatformService.fetchArrearLoans();
|
Collection<Long> loanIds = this.loanReadPlatformService.fetchLoansForInterestRecalculation();
|
||||||
for (Long loanId : loanIds) {
|
for (Long loanId : loanIds) {
|
||||||
this.loanWritePlatformService.recalculateInterest(loanId);
|
this.loanWritePlatformService.recalculateInterest(loanId);
|
||||||
}
|
}
|
||||||
|
|||||||
+76
-37
@@ -97,6 +97,9 @@ import org.mifosplatform.portfolio.common.BusinessEventNotificationConstants.BUS
|
|||||||
import org.mifosplatform.portfolio.common.BusinessEventNotificationConstants.BUSINESS_EVENTS;
|
import org.mifosplatform.portfolio.common.BusinessEventNotificationConstants.BUSINESS_EVENTS;
|
||||||
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
||||||
import org.mifosplatform.portfolio.common.service.BusinessEventNotifierService;
|
import org.mifosplatform.portfolio.common.service.BusinessEventNotifierService;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRateDTO;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRatePeriodData;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.group.domain.Group;
|
import org.mifosplatform.portfolio.group.domain.Group;
|
||||||
import org.mifosplatform.portfolio.group.exception.GroupNotActiveException;
|
import org.mifosplatform.portfolio.group.exception.GroupNotActiveException;
|
||||||
import org.mifosplatform.portfolio.loanaccount.api.LoanApiConstants;
|
import org.mifosplatform.portfolio.loanaccount.api.LoanApiConstants;
|
||||||
@@ -206,6 +209,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
private final AccountTransferDetailRepository accountTransferDetailRepository;
|
private final AccountTransferDetailRepository accountTransferDetailRepository;
|
||||||
private final BusinessEventNotifierService businessEventNotifierService;
|
private final BusinessEventNotifierService businessEventNotifierService;
|
||||||
private final GuarantorDomainService guarantorDomainService;
|
private final GuarantorDomainService guarantorDomainService;
|
||||||
|
private final FloatingRatesReadPlatformService floatingRatesReadPlatformService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||||
@@ -231,7 +235,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
final LoanApplicationCommandFromApiJsonHelper loanApplicationCommandFromApiJsonHelper,
|
final LoanApplicationCommandFromApiJsonHelper loanApplicationCommandFromApiJsonHelper,
|
||||||
final AccountAssociationsRepository accountAssociationRepository,
|
final AccountAssociationsRepository accountAssociationRepository,
|
||||||
final AccountTransferDetailRepository accountTransferDetailRepository,
|
final AccountTransferDetailRepository accountTransferDetailRepository,
|
||||||
final BusinessEventNotifierService businessEventNotifierService, final GuarantorDomainService guarantorDomainService) {
|
final BusinessEventNotifierService businessEventNotifierService, final GuarantorDomainService guarantorDomainService,
|
||||||
|
final FloatingRatesReadPlatformService floatingRatesReadPlatformService) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.loanEventApiJsonValidator = loanEventApiJsonValidator;
|
this.loanEventApiJsonValidator = loanEventApiJsonValidator;
|
||||||
this.loanAssembler = loanAssembler;
|
this.loanAssembler = loanAssembler;
|
||||||
@@ -266,6 +271,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
this.accountTransferDetailRepository = accountTransferDetailRepository;
|
this.accountTransferDetailRepository = accountTransferDetailRepository;
|
||||||
this.businessEventNotifierService = businessEventNotifierService;
|
this.businessEventNotifierService = businessEventNotifierService;
|
||||||
this.guarantorDomainService = guarantorDomainService;
|
this.guarantorDomainService = guarantorDomainService;
|
||||||
|
this.floatingRatesReadPlatformService = floatingRatesReadPlatformService;
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
|
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
|
||||||
@@ -354,9 +360,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
}
|
}
|
||||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays, allowTransactionsOnHoliday,
|
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays, allowTransactionsOnHoliday,
|
||||||
allowTransactionsOnNonWorkingDay);
|
allowTransactionsOnNonWorkingDay);
|
||||||
|
FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
|
||||||
|
|
||||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance,
|
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance,
|
||||||
recalculateFrom, overdurPenaltyWaitPeriod);
|
recalculateFrom, overdurPenaltyWaitPeriod, floatingRateDTO);
|
||||||
|
|
||||||
regenerateScheduleOnDisbursement(command, loan, recalculateSchedule, scheduleGeneratorDTO);
|
regenerateScheduleOnDisbursement(command, loan, recalculateSchedule, scheduleGeneratorDTO);
|
||||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
@@ -513,7 +521,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
for (LoanRepaymentScheduleInstallment installment : installments) {
|
for (LoanRepaymentScheduleInstallment installment : installments) {
|
||||||
if (installment.getId() == null) {
|
if (installment.getId() == null) {
|
||||||
this.repaymentScheduleInstallmentRepository.save(installment);
|
this.repaymentScheduleInstallmentRepository.save(installment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.loanRepository.save(loan);
|
this.loanRepository.save(loan);
|
||||||
} catch (final DataIntegrityViolationException e) {
|
} catch (final DataIntegrityViolationException e) {
|
||||||
@@ -608,9 +616,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
}
|
}
|
||||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays,
|
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays,
|
||||||
allowTransactionsOnHoliday, allowTransactionsOnNonWorkingDay);
|
allowTransactionsOnHoliday, allowTransactionsOnNonWorkingDay);
|
||||||
|
FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
|
||||||
|
|
||||||
final ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
final ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||||
firstRepaymentOnDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
firstRepaymentOnDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
||||||
overdurPenaltyWaitPeriod);
|
overdurPenaltyWaitPeriod, floatingRateDTO);
|
||||||
regenerateScheduleOnDisbursement(command, loan, recalculateSchedule, scheduleGeneratorDTO);
|
regenerateScheduleOnDisbursement(command, loan, recalculateSchedule, scheduleGeneratorDTO);
|
||||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
this.loanScheduleHistoryWritePlatformService.createAndSaveLoanScheduleArchive(
|
this.loanScheduleHistoryWritePlatformService.createAndSaveLoanScheduleArchive(
|
||||||
@@ -707,9 +717,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||||
}
|
}
|
||||||
|
FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
|
||||||
|
|
||||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(this.loanScheduleFactory, applicationCurrency,
|
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(this.loanScheduleFactory, applicationCurrency,
|
||||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance);
|
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, floatingRateDTO);
|
||||||
|
|
||||||
final Map<String, Object> changes = loan.undoDisbursal(scheduleGeneratorDTO, existingTransactionIds,
|
final Map<String, Object> changes = loan.undoDisbursal(scheduleGeneratorDTO, existingTransactionIds,
|
||||||
existingReversedTransactionIds, currentUser);
|
existingReversedTransactionIds, currentUser);
|
||||||
@@ -893,11 +904,13 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
.getTransactionDate();
|
.getTransactionDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
|
||||||
|
|
||||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays, allowTransactionsOnHoliday,
|
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays, allowTransactionsOnHoliday,
|
||||||
allowTransactionsOnNonWorkingDay);
|
allowTransactionsOnNonWorkingDay);
|
||||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
||||||
overdurPenaltyWaitPeriod);
|
overdurPenaltyWaitPeriod, floatingRateDTO);
|
||||||
|
|
||||||
final ChangedTransactionDetail changedTransactionDetail = loan.adjustExistingTransaction(newTransactionDetail,
|
final ChangedTransactionDetail changedTransactionDetail = loan.adjustExistingTransaction(newTransactionDetail,
|
||||||
defaultLoanLifecycleStateMachine(), transactionToAdjust, existingTransactionIds, existingReversedTransactionIds,
|
defaultLoanLifecycleStateMachine(), transactionToAdjust, existingTransactionIds, existingReversedTransactionIds,
|
||||||
@@ -1042,9 +1055,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
}
|
}
|
||||||
|
|
||||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||||
|
FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
|
||||||
|
|
||||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
||||||
overdurPenaltyWaitPeriod);
|
overdurPenaltyWaitPeriod, floatingRateDTO);
|
||||||
final ChangedTransactionDetail changedTransactionDetail = loan.waiveInterest(waiveInterestTransaction,
|
final ChangedTransactionDetail changedTransactionDetail = loan.waiveInterest(waiveInterestTransaction,
|
||||||
defaultLoanLifecycleStateMachine(), existingTransactionIds, existingReversedTransactionIds, scheduleGeneratorDTO,
|
defaultLoanLifecycleStateMachine(), existingTransactionIds, existingReversedTransactionIds, scheduleGeneratorDTO,
|
||||||
currentUser);
|
currentUser);
|
||||||
@@ -1137,9 +1152,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
recalculateFrom = command.localDateValueOfParameterNamed("transactionDate");
|
recalculateFrom = command.localDateValueOfParameterNamed("transactionDate");
|
||||||
}
|
}
|
||||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||||
|
FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
|
||||||
|
|
||||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
||||||
overdurPenaltyWaitPeriod);
|
overdurPenaltyWaitPeriod, floatingRateDTO);
|
||||||
|
|
||||||
final ChangedTransactionDetail changedTransactionDetail = loan.closeAsWrittenOff(command, defaultLoanLifecycleStateMachine(),
|
final ChangedTransactionDetail changedTransactionDetail = loan.closeAsWrittenOff(command, defaultLoanLifecycleStateMachine(),
|
||||||
changes, existingTransactionIds, existingReversedTransactionIds, currentUser, scheduleGeneratorDTO);
|
changes, existingTransactionIds, existingReversedTransactionIds, currentUser, scheduleGeneratorDTO);
|
||||||
@@ -1221,9 +1238,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
}
|
}
|
||||||
|
|
||||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||||
|
FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
|
||||||
|
|
||||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(this.loanScheduleFactory, applicationCurrency,
|
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(this.loanScheduleFactory, applicationCurrency,
|
||||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
||||||
overdurPenaltyWaitPeriod);
|
overdurPenaltyWaitPeriod, floatingRateDTO);
|
||||||
ChangedTransactionDetail changedTransactionDetail = loan.close(command, defaultLoanLifecycleStateMachine(), changes,
|
ChangedTransactionDetail changedTransactionDetail = loan.close(command, defaultLoanLifecycleStateMachine(), changes,
|
||||||
existingTransactionIds, existingReversedTransactionIds, scheduleGeneratorDTO, currentUser);
|
existingTransactionIds, existingReversedTransactionIds, scheduleGeneratorDTO, currentUser);
|
||||||
final LoanTransaction possibleClosingTransaction = changedTransactionDetail.getNewTransactionMappings().remove(0L);
|
final LoanTransaction possibleClosingTransaction = changedTransactionDetail.getNewTransactionMappings().remove(0L);
|
||||||
@@ -1357,7 +1376,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
|
|
||||||
boolean isAppliedOnBackDate = false;
|
boolean isAppliedOnBackDate = false;
|
||||||
LoanCharge loanCharge = null;
|
LoanCharge loanCharge = null;
|
||||||
LocalDate recalculateFrom =loan.fetchInterestRecalculateFromDate();
|
LocalDate recalculateFrom = loan.fetchInterestRecalculateFromDate();
|
||||||
if (chargeDefinition.isPercentageOfDisbursementAmount()) {
|
if (chargeDefinition.isPercentageOfDisbursementAmount()) {
|
||||||
LoanTrancheDisbursementCharge loanTrancheDisbursementCharge = null;
|
LoanTrancheDisbursementCharge loanTrancheDisbursementCharge = null;
|
||||||
for (LoanDisbursementDetails disbursementDetail : loanDisburseDetails) {
|
for (LoanDisbursementDetails disbursementDetail : loanDisburseDetails) {
|
||||||
@@ -1478,9 +1497,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
final Long overdurPenaltyWaitPeriod = this.configurationDomainService.retrievePenaltyWaitPeriod();
|
final Long overdurPenaltyWaitPeriod = this.configurationDomainService.retrievePenaltyWaitPeriod();
|
||||||
|
|
||||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||||
|
FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
|
||||||
|
|
||||||
ScheduleGeneratorDTO generatorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
ScheduleGeneratorDTO generatorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance,
|
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance,
|
||||||
recalculateFrom, overdurPenaltyWaitPeriod);
|
recalculateFrom, overdurPenaltyWaitPeriod, floatingRateDTO);
|
||||||
ChangedTransactionDetail changedTransactionDetail = loan.handleRegenerateRepaymentScheduleWithInterestRecalculation(
|
ChangedTransactionDetail changedTransactionDetail = loan.handleRegenerateRepaymentScheduleWithInterestRecalculation(
|
||||||
generatorDTO, currentUser);
|
generatorDTO, currentUser);
|
||||||
saveLoanWithDataIntegrityViolationChecks(loan);
|
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||||
@@ -1521,9 +1542,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||||
}
|
}
|
||||||
|
FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
|
||||||
|
|
||||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance);
|
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance,
|
||||||
|
floatingRateDTO);
|
||||||
createLoanScheduleArchive(loan, scheduleGeneratorDTO);
|
createLoanScheduleArchive(loan, scheduleGeneratorDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1678,9 +1701,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
}
|
}
|
||||||
|
|
||||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||||
|
FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
|
||||||
|
|
||||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
||||||
overdurPenaltyWaitPeriod);
|
overdurPenaltyWaitPeriod, floatingRateDTO);
|
||||||
|
|
||||||
Money accruedCharge = Money.zero(loan.getCurrency());
|
Money accruedCharge = Money.zero(loan.getCurrency());
|
||||||
if (loan.isPeriodicAccrualAccountingEnabledOnLoanProduct()) {
|
if (loan.isPeriodicAccrualAccountingEnabledOnLoanProduct()) {
|
||||||
@@ -2440,7 +2465,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
if (loan != null) {
|
if (loan != null) {
|
||||||
boolean reprocessRequired = true;
|
boolean reprocessRequired = true;
|
||||||
LocalDate recalculatedTill = loan.fetchInterestRecalculateFromDate();
|
LocalDate recalculatedTill = loan.fetchInterestRecalculateFromDate();
|
||||||
if(recalculateFrom.isAfter(recalculatedTill)){
|
if (recalculateFrom.isAfter(recalculatedTill)) {
|
||||||
recalculateFrom = recalculatedTill;
|
recalculateFrom = recalculatedTill;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2590,9 +2615,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
}
|
}
|
||||||
|
|
||||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||||
|
FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
|
||||||
|
|
||||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
||||||
overdurPenaltyWaitPeriod);
|
overdurPenaltyWaitPeriod, floatingRateDTO);
|
||||||
|
|
||||||
ChangedTransactionDetail changedTransactionDetail = loan.undoWrittenOff(existingTransactionIds, existingReversedTransactionIds,
|
ChangedTransactionDetail changedTransactionDetail = loan.undoWrittenOff(existingTransactionIds, existingReversedTransactionIds,
|
||||||
scheduleGeneratorDTO, currentUser);
|
scheduleGeneratorDTO, currentUser);
|
||||||
@@ -2717,10 +2744,12 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
overdurPenaltyWaitPeriod = this.configurationDomainService.retrievePenaltyWaitPeriod();
|
overdurPenaltyWaitPeriod = this.configurationDomainService.retrievePenaltyWaitPeriod();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
|
||||||
|
|
||||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(this.loanScheduleFactory, applicationCurrency,
|
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(this.loanScheduleFactory, applicationCurrency,
|
||||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
||||||
overdurPenaltyWaitPeriod);
|
overdurPenaltyWaitPeriod, floatingRateDTO);
|
||||||
|
|
||||||
ChangedTransactionDetail changedTransactionDetail = null;
|
ChangedTransactionDetail changedTransactionDetail = null;
|
||||||
AppUser currentUser = getAppUserIfPresent();
|
AppUser currentUser = getAppUserIfPresent();
|
||||||
@@ -2857,19 +2886,13 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
@Transactional
|
@Transactional
|
||||||
@Override
|
@Override
|
||||||
public void recalculateInterest(final long loanId) {
|
public void recalculateInterest(final long loanId) {
|
||||||
AppUser currentUser = getAppUserIfPresent();
|
|
||||||
Loan loan = this.loanAssembler.assembleFrom(loanId);
|
Loan loan = this.loanAssembler.assembleFrom(loanId);
|
||||||
|
LocalDate recalculateFrom = loan.fetchInterestRecalculateFromDate();
|
||||||
|
AppUser currentUser = getAppUserIfPresent();
|
||||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.LOAN_INTEREST_RECALCULATION,
|
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.LOAN_INTEREST_RECALCULATION,
|
||||||
constructEntityMap(BUSINESS_ENTITY.LOAN, loan));
|
constructEntityMap(BUSINESS_ENTITY.LOAN, loan));
|
||||||
CalendarInstance restCalendarInstance = null;
|
CalendarInstance restCalendarInstance = null;
|
||||||
CalendarInstance compoundingCalendarInstance = null;
|
CalendarInstance compoundingCalendarInstance = null;
|
||||||
ApplicationCurrency applicationCurrency = null;
|
|
||||||
LocalDate calculatedRepaymentsStartingFromDate = null;
|
|
||||||
List<Holiday> holidays = null;
|
|
||||||
boolean isHolidayEnabled = false;
|
|
||||||
WorkingDays workingDays = null;
|
|
||||||
LocalDate recalculateFrom = loan.fetchInterestRecalculateFromDate();
|
|
||||||
Long overdurPenaltyWaitPeriod = null;
|
|
||||||
final List<Long> existingTransactionIds = new ArrayList<>();
|
final List<Long> existingTransactionIds = new ArrayList<>();
|
||||||
final List<Long> existingReversedTransactionIds = new ArrayList<>();
|
final List<Long> existingReversedTransactionIds = new ArrayList<>();
|
||||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
@@ -2877,23 +2900,26 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||||
|
|
||||||
final MonetaryCurrency currency = loan.getCurrency();
|
|
||||||
applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
|
||||||
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
|
|
||||||
CalendarEntityType.LOANS.getValue());
|
|
||||||
calculatedRepaymentsStartingFromDate = this.loanAccountDomainService.getCalculatedRepaymentsStartingFromDate(
|
|
||||||
loan.getDisbursementDate(), loan, calendarInstance);
|
|
||||||
|
|
||||||
isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
|
||||||
holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan.getDisbursementDate().toDate());
|
|
||||||
workingDays = this.workingDaysRepository.findOne();
|
|
||||||
overdurPenaltyWaitPeriod = this.configurationDomainService.retrievePenaltyWaitPeriod();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final MonetaryCurrency currency = loan.getCurrency();
|
||||||
|
ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
||||||
|
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
|
||||||
|
CalendarEntityType.LOANS.getValue());
|
||||||
|
LocalDate calculatedRepaymentsStartingFromDate = this.loanAccountDomainService.getCalculatedRepaymentsStartingFromDate(
|
||||||
|
loan.getDisbursementDate(), loan, calendarInstance);
|
||||||
|
|
||||||
|
boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
||||||
|
List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan.getDisbursementDate()
|
||||||
|
.toDate());
|
||||||
|
WorkingDays workingDays = this.workingDaysRepository.findOne();
|
||||||
|
Long overdurPenaltyWaitPeriod = this.configurationDomainService.retrievePenaltyWaitPeriod();
|
||||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||||
|
FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
|
||||||
|
|
||||||
ScheduleGeneratorDTO generatorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
ScheduleGeneratorDTO generatorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
||||||
overdurPenaltyWaitPeriod);
|
overdurPenaltyWaitPeriod, floatingRateDTO);
|
||||||
|
|
||||||
ChangedTransactionDetail changedTransactionDetail = loan.recalculateScheduleFromLastTransaction(generatorDTO,
|
ChangedTransactionDetail changedTransactionDetail = loan.recalculateScheduleFromLastTransaction(generatorDTO,
|
||||||
existingTransactionIds, existingReversedTransactionIds, currentUser);
|
existingTransactionIds, existingReversedTransactionIds, currentUser);
|
||||||
@@ -3022,4 +3048,17 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private FloatingRateDTO constructFloatingRateDTO(final Loan loan) {
|
||||||
|
FloatingRateDTO floatingRateDTO = null;
|
||||||
|
if (loan.loanProduct().isLinkedToFloatingInterestRate()) {
|
||||||
|
boolean isFloatingInterestRate = loan.getIsFloatingInterestRate();
|
||||||
|
BigDecimal interestRateDiff = loan.getInterestRateDifferential();
|
||||||
|
List<FloatingRatePeriodData> baseLendingRatePeriods = this.floatingRatesReadPlatformService.retrieveBaseLendingRate()
|
||||||
|
.getRatePeriods();
|
||||||
|
floatingRateDTO = new FloatingRateDTO(isFloatingInterestRate, loan.getDisbursementDate(), interestRateDiff,
|
||||||
|
baseLendingRatePeriods);
|
||||||
|
}
|
||||||
|
return floatingRateDTO;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+11
-3
@@ -44,6 +44,8 @@ import org.mifosplatform.organisation.monetary.service.CurrencyReadPlatformServi
|
|||||||
import org.mifosplatform.portfolio.charge.data.ChargeData;
|
import org.mifosplatform.portfolio.charge.data.ChargeData;
|
||||||
import org.mifosplatform.portfolio.charge.service.ChargeReadPlatformService;
|
import org.mifosplatform.portfolio.charge.service.ChargeReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.common.service.DropdownReadPlatformService;
|
import org.mifosplatform.portfolio.common.service.DropdownReadPlatformService;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRateData;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.fund.data.FundData;
|
import org.mifosplatform.portfolio.fund.data.FundData;
|
||||||
import org.mifosplatform.portfolio.fund.service.FundReadPlatformService;
|
import org.mifosplatform.portfolio.fund.service.FundReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
|
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
|
||||||
@@ -73,7 +75,9 @@ public class LoanProductsApiResource {
|
|||||||
"paymentTypeOptions", "currencyOptions", "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions",
|
"paymentTypeOptions", "currencyOptions", "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions",
|
||||||
"amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions",
|
"amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions",
|
||||||
"transactionProcessingStrategyOptions", "chargeOptions", "accountingOptions", "accountingRuleOptions",
|
"transactionProcessingStrategyOptions", "chargeOptions", "accountingOptions", "accountingRuleOptions",
|
||||||
"accountingMappingOptions"));
|
"accountingMappingOptions", "floatingRateOptions", "isLinkedToFloatingInterestRates", "floatingRatesId", "interestRateDifferential",
|
||||||
|
"minDifferentialLendingRate", "defaultDifferentialLendingRate", "maxDifferentialLendingRate",
|
||||||
|
"isFloatingInterestRateCalculationAllowed"));
|
||||||
|
|
||||||
private final Set<String> PRODUCT_MIX_DATA_PARAMETERS = new HashSet<>(Arrays.asList("productId", "productName", "restrictedProducts",
|
private final Set<String> PRODUCT_MIX_DATA_PARAMETERS = new HashSet<>(Arrays.asList("productId", "productName", "restrictedProducts",
|
||||||
"allowedProducts", "productOptions"));
|
"allowedProducts", "productOptions"));
|
||||||
@@ -95,6 +99,7 @@ public class LoanProductsApiResource {
|
|||||||
private final ProductMixReadPlatformService productMixReadPlatformService;
|
private final ProductMixReadPlatformService productMixReadPlatformService;
|
||||||
private final DropdownReadPlatformService commonDropdownReadPlatformService;
|
private final DropdownReadPlatformService commonDropdownReadPlatformService;
|
||||||
private final PaymentTypeReadPlatformService paymentTypeReadPlatformService;
|
private final PaymentTypeReadPlatformService paymentTypeReadPlatformService;
|
||||||
|
private final FloatingRatesReadPlatformService floatingRateReadPlatformService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanProductsApiResource(final PlatformSecurityContext context, final LoanProductReadPlatformService readPlatformService,
|
public LoanProductsApiResource(final PlatformSecurityContext context, final LoanProductReadPlatformService readPlatformService,
|
||||||
@@ -108,7 +113,8 @@ public class LoanProductsApiResource {
|
|||||||
final DefaultToApiJsonSerializer<ProductMixData> productMixDataApiJsonSerializer,
|
final DefaultToApiJsonSerializer<ProductMixData> productMixDataApiJsonSerializer,
|
||||||
final ProductMixReadPlatformService productMixReadPlatformService,
|
final ProductMixReadPlatformService productMixReadPlatformService,
|
||||||
final DropdownReadPlatformService commonDropdownReadPlatformService,
|
final DropdownReadPlatformService commonDropdownReadPlatformService,
|
||||||
PaymentTypeReadPlatformService paymentTypeReadPlatformService) {
|
PaymentTypeReadPlatformService paymentTypeReadPlatformService,
|
||||||
|
final FloatingRatesReadPlatformService floatingRateReadPlatformService) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.loanProductReadPlatformService = readPlatformService;
|
this.loanProductReadPlatformService = readPlatformService;
|
||||||
this.chargeReadPlatformService = chargeReadPlatformService;
|
this.chargeReadPlatformService = chargeReadPlatformService;
|
||||||
@@ -124,6 +130,7 @@ public class LoanProductsApiResource {
|
|||||||
this.productMixReadPlatformService = productMixReadPlatformService;
|
this.productMixReadPlatformService = productMixReadPlatformService;
|
||||||
this.commonDropdownReadPlatformService = commonDropdownReadPlatformService;
|
this.commonDropdownReadPlatformService = commonDropdownReadPlatformService;
|
||||||
this.paymentTypeReadPlatformService = paymentTypeReadPlatformService;
|
this.paymentTypeReadPlatformService = paymentTypeReadPlatformService;
|
||||||
|
this.floatingRateReadPlatformService = floatingRateReadPlatformService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
@@ -279,13 +286,14 @@ public class LoanProductsApiResource {
|
|||||||
.retrieveInterestRecalculationFrequencyTypeOptions();
|
.retrieveInterestRecalculationFrequencyTypeOptions();
|
||||||
final List<EnumOptionData> preCloseInterestCalculationStrategyOptions = dropdownReadPlatformService
|
final List<EnumOptionData> preCloseInterestCalculationStrategyOptions = dropdownReadPlatformService
|
||||||
.retrivePreCloseInterestCalculationStrategyOptions();
|
.retrivePreCloseInterestCalculationStrategyOptions();
|
||||||
|
final List<FloatingRateData> floatingRateOptions = this.floatingRateReadPlatformService.retrieveLookupActive();
|
||||||
|
|
||||||
return new LoanProductData(productData, chargeOptions, penaltyOptions, paymentTypeOptions, currencyOptions,
|
return new LoanProductData(productData, chargeOptions, penaltyOptions, paymentTypeOptions, currencyOptions,
|
||||||
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, repaymentFrequencyTypeOptions,
|
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, repaymentFrequencyTypeOptions,
|
||||||
interestRateFrequencyTypeOptions, fundOptions, transactionProcessingStrategyOptions, accountOptions,
|
interestRateFrequencyTypeOptions, fundOptions, transactionProcessingStrategyOptions, accountOptions,
|
||||||
accountingRuleTypeOptions, loanCycleValueConditionTypeOptions, daysInMonthTypeOptions, daysInYearTypeOptions,
|
accountingRuleTypeOptions, loanCycleValueConditionTypeOptions, daysInMonthTypeOptions, daysInYearTypeOptions,
|
||||||
interestRecalculationCompoundingTypeOptions, rescheduleStrategyTypeOptions, interestRecalculationFrequencyTypeOptions,
|
interestRecalculationCompoundingTypeOptions, rescheduleStrategyTypeOptions, interestRecalculationFrequencyTypeOptions,
|
||||||
preCloseInterestCalculationStrategyOptions);
|
preCloseInterestCalculationStrategyOptions, floatingRateOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+90
-5
@@ -25,6 +25,7 @@ import org.mifosplatform.portfolio.common.domain.DaysInMonthType;
|
|||||||
import org.mifosplatform.portfolio.common.domain.DaysInYearType;
|
import org.mifosplatform.portfolio.common.domain.DaysInYearType;
|
||||||
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
||||||
import org.mifosplatform.portfolio.common.service.CommonEnumerations;
|
import org.mifosplatform.portfolio.common.service.CommonEnumerations;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRateData;
|
||||||
import org.mifosplatform.portfolio.fund.data.FundData;
|
import org.mifosplatform.portfolio.fund.data.FundData;
|
||||||
import org.mifosplatform.portfolio.loanaccount.data.LoanInterestRecalculationData;
|
import org.mifosplatform.portfolio.loanaccount.data.LoanInterestRecalculationData;
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
|
import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
|
||||||
@@ -67,6 +68,15 @@ public class LoanProductData {
|
|||||||
private final BigDecimal maxInterestRatePerPeriod;
|
private final BigDecimal maxInterestRatePerPeriod;
|
||||||
private final EnumOptionData interestRateFrequencyType;
|
private final EnumOptionData interestRateFrequencyType;
|
||||||
private final BigDecimal annualInterestRate;
|
private final BigDecimal annualInterestRate;
|
||||||
|
|
||||||
|
private final boolean isLinkedToFloatingInterestRates;
|
||||||
|
private final Integer floatingRateId;
|
||||||
|
private final String floatingRateName;
|
||||||
|
private final BigDecimal interestRateDifferential;
|
||||||
|
private final BigDecimal minDifferentialLendingRate;
|
||||||
|
private final BigDecimal defaultDifferentialLendingRate;
|
||||||
|
private final BigDecimal maxDifferentialLendingRate;
|
||||||
|
private final boolean isFloatingInterestRateCalculationAllowed;
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
private final EnumOptionData amortizationType;
|
private final EnumOptionData amortizationType;
|
||||||
@@ -135,6 +145,8 @@ public class LoanProductData {
|
|||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private final List<EnumOptionData> interestRecalculationFrequencyTypeOptions;
|
private final List<EnumOptionData> interestRecalculationFrequencyTypeOptions;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final List<FloatingRateData> floatingRateOptions;
|
||||||
|
|
||||||
private final Boolean multiDisburseLoan;
|
private final Boolean multiDisburseLoan;
|
||||||
private final Integer maxTrancheCount;
|
private final Integer maxTrancheCount;
|
||||||
@@ -165,6 +177,14 @@ public class LoanProductData {
|
|||||||
final BigDecimal minInterestRatePerPeriod = null;
|
final BigDecimal minInterestRatePerPeriod = null;
|
||||||
final BigDecimal maxInterestRatePerPeriod = null;
|
final BigDecimal maxInterestRatePerPeriod = null;
|
||||||
final BigDecimal annualInterestRate = null;
|
final BigDecimal annualInterestRate = null;
|
||||||
|
final boolean isLinkedToFloatingInterestRates = false;
|
||||||
|
final Integer floatingRateId = null;
|
||||||
|
final String floatingRateName = null;
|
||||||
|
final BigDecimal interestRateDifferential = null;
|
||||||
|
final BigDecimal minDifferentialLendingRate = null;
|
||||||
|
final BigDecimal defaultDifferentialLendingRate = null;
|
||||||
|
final BigDecimal maxDifferentialLendingRate = null;
|
||||||
|
final boolean isFloatingInterestRateCalculationAllowed = false;
|
||||||
final EnumOptionData repaymentFrequencyType = null;
|
final EnumOptionData repaymentFrequencyType = null;
|
||||||
final EnumOptionData interestRateFrequencyType = null;
|
final EnumOptionData interestRateFrequencyType = null;
|
||||||
final EnumOptionData amortizationType = null;
|
final EnumOptionData amortizationType = null;
|
||||||
@@ -217,7 +237,9 @@ public class LoanProductData {
|
|||||||
graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||||
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, productGuaranteeData,
|
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, productGuaranteeData,
|
||||||
principalThresholdForLastInstallment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount,
|
principalThresholdForLastInstallment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount,
|
||||||
installmentAmountInMultiplesOf, loanProductConfigurableAttributes);
|
installmentAmountInMultiplesOf, loanProductConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRateId,
|
||||||
|
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
||||||
|
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,6 +258,14 @@ public class LoanProductData {
|
|||||||
final BigDecimal minInterestRatePerPeriod = null;
|
final BigDecimal minInterestRatePerPeriod = null;
|
||||||
final BigDecimal maxInterestRatePerPeriod = null;
|
final BigDecimal maxInterestRatePerPeriod = null;
|
||||||
final BigDecimal annualInterestRate = null;
|
final BigDecimal annualInterestRate = null;
|
||||||
|
final boolean isLinkedToFloatingInterestRates = false;
|
||||||
|
final Integer floatingRateId = null;
|
||||||
|
final String floatingRateName = null;
|
||||||
|
final BigDecimal interestRateDifferential = null;
|
||||||
|
final BigDecimal minDifferentialLendingRate = null;
|
||||||
|
final BigDecimal defaultDifferentialLendingRate = null;
|
||||||
|
final BigDecimal maxDifferentialLendingRate = null;
|
||||||
|
final boolean isFloatingInterestRateCalculationAllowed = false;
|
||||||
final EnumOptionData repaymentFrequencyType = null;
|
final EnumOptionData repaymentFrequencyType = null;
|
||||||
final EnumOptionData interestRateFrequencyType = null;
|
final EnumOptionData interestRateFrequencyType = null;
|
||||||
final EnumOptionData amortizationType = null;
|
final EnumOptionData amortizationType = null;
|
||||||
@@ -290,7 +320,9 @@ public class LoanProductData {
|
|||||||
graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||||
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, productGuaranteeData,
|
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, productGuaranteeData,
|
||||||
principalThresholdForLastInstallment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount,
|
principalThresholdForLastInstallment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount,
|
||||||
installmentAmountInMultiplesOf, loanProductConfigurableAttributes);
|
installmentAmountInMultiplesOf, loanProductConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRateId,
|
||||||
|
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
||||||
|
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,6 +345,14 @@ public class LoanProductData {
|
|||||||
final BigDecimal minInterestRatePerPeriod = null;
|
final BigDecimal minInterestRatePerPeriod = null;
|
||||||
final BigDecimal maxInterestRatePerPeriod = null;
|
final BigDecimal maxInterestRatePerPeriod = null;
|
||||||
final BigDecimal annualInterestRate = null;
|
final BigDecimal annualInterestRate = null;
|
||||||
|
final boolean isLinkedToFloatingInterestRates = false;
|
||||||
|
final Integer floatingRateId = null;
|
||||||
|
final String floatingRateName = null;
|
||||||
|
final BigDecimal interestRateDifferential = null;
|
||||||
|
final BigDecimal minDifferentialLendingRate = null;
|
||||||
|
final BigDecimal defaultDifferentialLendingRate = null;
|
||||||
|
final BigDecimal maxDifferentialLendingRate = null;
|
||||||
|
final boolean isFloatingInterestRateCalculationAllowed = false;
|
||||||
final EnumOptionData repaymentFrequencyType = LoanEnumerations.repaymentFrequencyType(PeriodFrequencyType.MONTHS);
|
final EnumOptionData repaymentFrequencyType = LoanEnumerations.repaymentFrequencyType(PeriodFrequencyType.MONTHS);
|
||||||
final EnumOptionData interestRateFrequencyType = LoanEnumerations.interestRateFrequencyType(PeriodFrequencyType.MONTHS);
|
final EnumOptionData interestRateFrequencyType = LoanEnumerations.interestRateFrequencyType(PeriodFrequencyType.MONTHS);
|
||||||
final EnumOptionData amortizationType = LoanEnumerations.amortizationType(AmortizationMethod.EQUAL_INSTALLMENTS);
|
final EnumOptionData amortizationType = LoanEnumerations.amortizationType(AmortizationMethod.EQUAL_INSTALLMENTS);
|
||||||
@@ -371,7 +411,9 @@ public class LoanProductData {
|
|||||||
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment,
|
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment,
|
||||||
holdGuaranteeFunds, productGuaranteeData, principalThresholdForLastInstallment,
|
holdGuaranteeFunds, productGuaranteeData, principalThresholdForLastInstallment,
|
||||||
accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, installmentAmountInMultiplesOf,
|
accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, installmentAmountInMultiplesOf,
|
||||||
loanProductConfigurableAttributes);
|
loanProductConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRateId,
|
||||||
|
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
||||||
|
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,7 +448,10 @@ public class LoanProductData {
|
|||||||
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, boolean holdGuaranteeFunds,
|
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, boolean holdGuaranteeFunds,
|
||||||
final LoanProductGuaranteeData loanProductGuaranteeData, final BigDecimal principalThresholdForLastInstallment,
|
final LoanProductGuaranteeData loanProductGuaranteeData, final BigDecimal principalThresholdForLastInstallment,
|
||||||
final boolean accountMovesOutOfNPAOnlyOnArrearsCompletion, boolean canDefineInstallmentAmount,
|
final boolean accountMovesOutOfNPAOnlyOnArrearsCompletion, boolean canDefineInstallmentAmount,
|
||||||
Integer installmentAmountInMultiplesOf, LoanProductConfigurableAttributes allowAttributeOverrides) {
|
Integer installmentAmountInMultiplesOf, LoanProductConfigurableAttributes allowAttributeOverrides,
|
||||||
|
boolean isLinkedToFloatingInterestRates, Integer floatingRateId, String floatingRateName,
|
||||||
|
BigDecimal interestRateDifferential, BigDecimal minDifferentialLendingRate, BigDecimal defaultDifferentialLendingRate,
|
||||||
|
BigDecimal maxDifferentialLendingRate, boolean isFloatingInterestRateCalculationAllowed) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.shortName = shortName;
|
this.shortName = shortName;
|
||||||
@@ -427,6 +472,14 @@ public class LoanProductData {
|
|||||||
this.minInterestRatePerPeriod = minInterestRatePerPeriod;
|
this.minInterestRatePerPeriod = minInterestRatePerPeriod;
|
||||||
this.maxInterestRatePerPeriod = maxInterestRatePerPeriod;
|
this.maxInterestRatePerPeriod = maxInterestRatePerPeriod;
|
||||||
this.annualInterestRate = annualInterestRate;
|
this.annualInterestRate = annualInterestRate;
|
||||||
|
this.isLinkedToFloatingInterestRates = isLinkedToFloatingInterestRates;
|
||||||
|
this.floatingRateId = floatingRateId;
|
||||||
|
this.floatingRateName = floatingRateName;
|
||||||
|
this.interestRateDifferential = interestRateDifferential;
|
||||||
|
this.minDifferentialLendingRate = minDifferentialLendingRate;
|
||||||
|
this.defaultDifferentialLendingRate = defaultDifferentialLendingRate;
|
||||||
|
this.maxDifferentialLendingRate = maxDifferentialLendingRate;
|
||||||
|
this.isFloatingInterestRateCalculationAllowed = isFloatingInterestRateCalculationAllowed;
|
||||||
this.repaymentFrequencyType = repaymentFrequencyType;
|
this.repaymentFrequencyType = repaymentFrequencyType;
|
||||||
this.interestRateFrequencyType = interestRateFrequencyType;
|
this.interestRateFrequencyType = interestRateFrequencyType;
|
||||||
this.amortizationType = amortizationType;
|
this.amortizationType = amortizationType;
|
||||||
@@ -457,6 +510,7 @@ public class LoanProductData {
|
|||||||
this.interestCalculationPeriodTypeOptions = null;
|
this.interestCalculationPeriodTypeOptions = null;
|
||||||
this.repaymentFrequencyTypeOptions = null;
|
this.repaymentFrequencyTypeOptions = null;
|
||||||
this.interestRateFrequencyTypeOptions = null;
|
this.interestRateFrequencyTypeOptions = null;
|
||||||
|
this.floatingRateOptions = null;
|
||||||
|
|
||||||
this.accountingMappingOptions = null;
|
this.accountingMappingOptions = null;
|
||||||
this.accountingRuleOptions = null;
|
this.accountingRuleOptions = null;
|
||||||
@@ -505,7 +559,7 @@ public class LoanProductData {
|
|||||||
final List<EnumOptionData> valueConditionTypeOptions, final List<EnumOptionData> daysInMonthTypeOptions,
|
final List<EnumOptionData> valueConditionTypeOptions, final List<EnumOptionData> daysInMonthTypeOptions,
|
||||||
final List<EnumOptionData> daysInYearTypeOptions, final List<EnumOptionData> interestRecalculationCompoundingTypeOptions,
|
final List<EnumOptionData> daysInYearTypeOptions, final List<EnumOptionData> interestRecalculationCompoundingTypeOptions,
|
||||||
final List<EnumOptionData> rescheduleStrategyTypeOptions, final List<EnumOptionData> interestRecalculationFrequencyTypeOptions,
|
final List<EnumOptionData> rescheduleStrategyTypeOptions, final List<EnumOptionData> interestRecalculationFrequencyTypeOptions,
|
||||||
final List<EnumOptionData> preCloseInterestCalculationStrategyOptions) {
|
final List<EnumOptionData> preCloseInterestCalculationStrategyOptions, final List<FloatingRateData> floatingRateOptions) {
|
||||||
this.id = productData.id;
|
this.id = productData.id;
|
||||||
this.name = productData.name;
|
this.name = productData.name;
|
||||||
this.shortName = productData.shortName;
|
this.shortName = productData.shortName;
|
||||||
@@ -525,6 +579,14 @@ public class LoanProductData {
|
|||||||
this.minInterestRatePerPeriod = productData.minInterestRatePerPeriod;
|
this.minInterestRatePerPeriod = productData.minInterestRatePerPeriod;
|
||||||
this.maxInterestRatePerPeriod = productData.maxInterestRatePerPeriod;
|
this.maxInterestRatePerPeriod = productData.maxInterestRatePerPeriod;
|
||||||
this.annualInterestRate = productData.annualInterestRate;
|
this.annualInterestRate = productData.annualInterestRate;
|
||||||
|
this.isLinkedToFloatingInterestRates = productData.isLinkedToFloatingInterestRates;
|
||||||
|
this.floatingRateId = productData.floatingRateId;
|
||||||
|
this.floatingRateName = productData.floatingRateName;
|
||||||
|
this.interestRateDifferential = productData.interestRateDifferential;
|
||||||
|
this.minDifferentialLendingRate = productData.minDifferentialLendingRate;
|
||||||
|
this.defaultDifferentialLendingRate = productData.defaultDifferentialLendingRate;
|
||||||
|
this.maxDifferentialLendingRate = productData.maxDifferentialLendingRate;
|
||||||
|
this.isFloatingInterestRateCalculationAllowed = productData.isFloatingInterestRateCalculationAllowed;
|
||||||
this.repaymentFrequencyType = productData.repaymentFrequencyType;
|
this.repaymentFrequencyType = productData.repaymentFrequencyType;
|
||||||
this.interestRateFrequencyType = productData.interestRateFrequencyType;
|
this.interestRateFrequencyType = productData.interestRateFrequencyType;
|
||||||
this.amortizationType = productData.amortizationType;
|
this.amortizationType = productData.amortizationType;
|
||||||
@@ -552,6 +614,7 @@ public class LoanProductData {
|
|||||||
this.currency = productData.currency;
|
this.currency = productData.currency;
|
||||||
this.fundOptions = fundOptions;
|
this.fundOptions = fundOptions;
|
||||||
this.transactionProcessingStrategyOptions = transactionStrategyOptions;
|
this.transactionProcessingStrategyOptions = transactionStrategyOptions;
|
||||||
|
this.floatingRateOptions = floatingRateOptions;
|
||||||
if (this.transactionProcessingStrategyOptions != null && this.transactionProcessingStrategyOptions.size() == 1) {
|
if (this.transactionProcessingStrategyOptions != null && this.transactionProcessingStrategyOptions.size() == 1) {
|
||||||
final List<TransactionProcessingStrategyData> listOfOptions = new ArrayList<>(this.transactionProcessingStrategyOptions);
|
final List<TransactionProcessingStrategyData> listOfOptions = new ArrayList<>(this.transactionProcessingStrategyOptions);
|
||||||
|
|
||||||
@@ -886,4 +949,26 @@ public class LoanProductData {
|
|||||||
public void setloanProductConfigurableAttributes(LoanProductConfigurableAttributes loanProductConfigurableAttributes) {
|
public void setloanProductConfigurableAttributes(LoanProductConfigurableAttributes loanProductConfigurableAttributes) {
|
||||||
this.allowAttributeOverrides = loanProductConfigurableAttributes;
|
this.allowAttributeOverrides = loanProductConfigurableAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isLinkedToFloatingInterestRates() {
|
||||||
|
return this.isLinkedToFloatingInterestRates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMinDifferentialLendingRate() {
|
||||||
|
return this.minDifferentialLendingRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getDefaultDifferentialLendingRate() {
|
||||||
|
return this.defaultDifferentialLendingRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMaxDifferentialLendingRate() {
|
||||||
|
return this.maxDifferentialLendingRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFloatingInterestRateCalculationAllowed() {
|
||||||
|
return this.isFloatingInterestRateCalculationAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
+94
-13
@@ -7,6 +7,7 @@ package org.mifosplatform.portfolio.loanproduct.domain;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -43,6 +44,9 @@ import org.mifosplatform.portfolio.charge.domain.Charge;
|
|||||||
import org.mifosplatform.portfolio.common.domain.DaysInMonthType;
|
import org.mifosplatform.portfolio.common.domain.DaysInMonthType;
|
||||||
import org.mifosplatform.portfolio.common.domain.DaysInYearType;
|
import org.mifosplatform.portfolio.common.domain.DaysInYearType;
|
||||||
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRateDTO;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRatePeriodData;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.domain.FloatingRate;
|
||||||
import org.mifosplatform.portfolio.fund.domain.Fund;
|
import org.mifosplatform.portfolio.fund.domain.Fund;
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.AprCalculator;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.AprCalculator;
|
||||||
import org.mifosplatform.portfolio.loanproduct.LoanProductConstants;
|
import org.mifosplatform.portfolio.loanproduct.LoanProductConstants;
|
||||||
@@ -153,8 +157,15 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
|||||||
@Column(name = "instalment_amount_in_multiples_of", nullable = true)
|
@Column(name = "instalment_amount_in_multiples_of", nullable = true)
|
||||||
private Integer installmentAmountInMultiplesOf;
|
private Integer installmentAmountInMultiplesOf;
|
||||||
|
|
||||||
|
@Column(name = "is_linked_to_floating_interest_rates", nullable = false)
|
||||||
|
private boolean isLinkedToFloatingInterestRate;
|
||||||
|
|
||||||
|
@LazyCollection(LazyCollectionOption.FALSE)
|
||||||
|
@OneToOne(cascade = CascadeType.ALL, mappedBy = "loanProduct", optional = true, orphanRemoval = true)
|
||||||
|
private LoanProductFloatingRates floatingRates;
|
||||||
|
|
||||||
public static LoanProduct assembleFromJson(final Fund fund, final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy,
|
public static LoanProduct assembleFromJson(final Fund fund, final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy,
|
||||||
final List<Charge> productCharges, final JsonCommand command, final AprCalculator aprCalculator) {
|
final List<Charge> productCharges, final JsonCommand command, final AprCalculator aprCalculator, FloatingRate floatingRate) {
|
||||||
|
|
||||||
final String name = command.stringValueOfParameterNamed("name");
|
final String name = command.stringValueOfParameterNamed("name");
|
||||||
final String shortName = command.stringValueOfParameterNamed(LoanProductConstants.shortName);
|
final String shortName = command.stringValueOfParameterNamed(LoanProductConstants.shortName);
|
||||||
@@ -174,12 +185,31 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
|||||||
final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.integerValueOfParameterNamed("amortizationType"));
|
final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.integerValueOfParameterNamed("amortizationType"));
|
||||||
final PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.fromInt(command
|
final PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.fromInt(command
|
||||||
.integerValueOfParameterNamed("repaymentFrequencyType"));
|
.integerValueOfParameterNamed("repaymentFrequencyType"));
|
||||||
final PeriodFrequencyType interestFrequencyType = PeriodFrequencyType.fromInt(command
|
PeriodFrequencyType interestFrequencyType = PeriodFrequencyType.INVALID;
|
||||||
.integerValueOfParameterNamed("interestRateFrequencyType"));
|
BigDecimal interestRatePerPeriod = null;
|
||||||
final BigDecimal interestRatePerPeriod = command.bigDecimalValueOfParameterNamed("interestRatePerPeriod");
|
BigDecimal minInterestRatePerPeriod = null;
|
||||||
final BigDecimal minInterestRatePerPeriod = command.bigDecimalValueOfParameterNamed("minInterestRatePerPeriod");
|
BigDecimal maxInterestRatePerPeriod = null;
|
||||||
final BigDecimal maxInterestRatePerPeriod = command.bigDecimalValueOfParameterNamed("maxInterestRatePerPeriod");
|
BigDecimal annualInterestRate = null;
|
||||||
final BigDecimal annualInterestRate = aprCalculator.calculateFrom(interestFrequencyType, interestRatePerPeriod);
|
BigDecimal interestRateDifferential = null;
|
||||||
|
BigDecimal minDifferentialLendingRate = null;
|
||||||
|
BigDecimal maxDifferentialLendingRate = null;
|
||||||
|
BigDecimal defaultDifferentialLendingRate = null;
|
||||||
|
Boolean isFloatingInterestRateCalculationAllowed = null;
|
||||||
|
final Boolean isLinkedToFloatingInterestRates = command.booleanObjectValueOfParameterNamed("isLinkedToFloatingInterestRates");
|
||||||
|
if (isLinkedToFloatingInterestRates != null && isLinkedToFloatingInterestRates) {
|
||||||
|
interestRateDifferential = command.bigDecimalValueOfParameterNamed("interestRateDifferential");
|
||||||
|
minDifferentialLendingRate = command.bigDecimalValueOfParameterNamed("minDifferentialLendingRate");
|
||||||
|
maxDifferentialLendingRate = command.bigDecimalValueOfParameterNamed("maxDifferentialLendingRate");
|
||||||
|
defaultDifferentialLendingRate = command.bigDecimalValueOfParameterNamed("defaultDifferentialLendingRate");
|
||||||
|
isFloatingInterestRateCalculationAllowed = command
|
||||||
|
.booleanObjectValueOfParameterNamed("isFloatingInterestRateCalculationAllowed");
|
||||||
|
} else {
|
||||||
|
interestFrequencyType = PeriodFrequencyType.fromInt(command.integerValueOfParameterNamed("interestRateFrequencyType"));
|
||||||
|
interestRatePerPeriod = command.bigDecimalValueOfParameterNamed("interestRatePerPeriod");
|
||||||
|
minInterestRatePerPeriod = command.bigDecimalValueOfParameterNamed("minInterestRatePerPeriod");
|
||||||
|
maxInterestRatePerPeriod = command.bigDecimalValueOfParameterNamed("maxInterestRatePerPeriod");
|
||||||
|
annualInterestRate = aprCalculator.calculateFrom(interestFrequencyType, interestRatePerPeriod);
|
||||||
|
}
|
||||||
|
|
||||||
final Integer repaymentEvery = command.integerValueOfParameterNamed("repaymentEvery");
|
final Integer repaymentEvery = command.integerValueOfParameterNamed("repaymentEvery");
|
||||||
final Integer numberOfRepayments = command.integerValueOfParameterNamed("numberOfRepayments");
|
final Integer numberOfRepayments = command.integerValueOfParameterNamed("numberOfRepayments");
|
||||||
@@ -271,7 +301,10 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
|||||||
outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType,
|
outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType,
|
||||||
isInterestRecalculationEnabled, interestRecalculationSettings, minimumDaysBetweenDisbursalAndFirstRepayment,
|
isInterestRecalculationEnabled, interestRecalculationSettings, minimumDaysBetweenDisbursalAndFirstRepayment,
|
||||||
holdGuarantorFunds, loanProductGuaranteeDetails, principalThresholdForLastInstallment,
|
holdGuarantorFunds, loanProductGuaranteeDetails, principalThresholdForLastInstallment,
|
||||||
accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineEmiAmount, installmentAmountInMultiplesOf, loanConfigurableAttributes);
|
accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineEmiAmount, installmentAmountInMultiplesOf,
|
||||||
|
loanConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRate, interestRateDifferential,
|
||||||
|
minDifferentialLendingRate, maxDifferentialLendingRate, defaultDifferentialLendingRate,
|
||||||
|
isFloatingInterestRateCalculationAllowed);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -498,7 +531,10 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
|||||||
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, final boolean holdGuarantorFunds,
|
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, final boolean holdGuarantorFunds,
|
||||||
final LoanProductGuaranteeDetails loanProductGuaranteeDetails, final BigDecimal principalThresholdForLastInstallment,
|
final LoanProductGuaranteeDetails loanProductGuaranteeDetails, final BigDecimal principalThresholdForLastInstallment,
|
||||||
final boolean accountMovesOutOfNPAOnlyOnArrearsCompletion, final boolean canDefineEmiAmount,
|
final boolean accountMovesOutOfNPAOnlyOnArrearsCompletion, final boolean canDefineEmiAmount,
|
||||||
final Integer installmentAmountInMultiplesOf, final LoanProductConfigurableAttributes loanProductConfigurableAttributes) {
|
final Integer installmentAmountInMultiplesOf, final LoanProductConfigurableAttributes loanProductConfigurableAttributes,
|
||||||
|
Boolean isLinkedToFloatingInterestRates, FloatingRate floatingRate, BigDecimal interestRateDifferential,
|
||||||
|
BigDecimal minDifferentialLendingRate, BigDecimal maxDifferentialLendingRate, BigDecimal defaultDifferentialLendingRate,
|
||||||
|
Boolean isFloatingInterestRateCalculationAllowed) {
|
||||||
this.fund = fund;
|
this.fund = fund;
|
||||||
this.transactionProcessingStrategy = transactionProcessingStrategy;
|
this.transactionProcessingStrategy = transactionProcessingStrategy;
|
||||||
this.name = name.trim();
|
this.name = name.trim();
|
||||||
@@ -513,6 +549,12 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
|||||||
this.charges = charges;
|
this.charges = charges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.isLinkedToFloatingInterestRate = isLinkedToFloatingInterestRates == null ? false : isLinkedToFloatingInterestRates;
|
||||||
|
if (isLinkedToFloatingInterestRate) {
|
||||||
|
this.floatingRates = new LoanProductFloatingRates(floatingRate, this, interestRateDifferential, minDifferentialLendingRate,
|
||||||
|
maxDifferentialLendingRate, defaultDifferentialLendingRate, isFloatingInterestRateCalculationAllowed);
|
||||||
|
}
|
||||||
|
|
||||||
this.loanProductRelatedDetail = new LoanProductRelatedDetail(currency, defaultPrincipal, defaultNominalInterestRatePerPeriod,
|
this.loanProductRelatedDetail = new LoanProductRelatedDetail(currency, defaultPrincipal, defaultNominalInterestRatePerPeriod,
|
||||||
interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery,
|
interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery,
|
||||||
repaymentFrequencyType, defaultNumberOfInstallments, graceOnPrincipalPayment, graceOnInterestPayment,
|
repaymentFrequencyType, defaultNumberOfInstallments, graceOnPrincipalPayment, graceOnInterestPayment,
|
||||||
@@ -603,9 +645,9 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
|||||||
public Integer getAccountingType() {
|
public Integer getAccountingType() {
|
||||||
return this.accountingRule;
|
return this.accountingRule;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Charge> getLoanProductCharges(){
|
public List<Charge> getLoanProductCharges() {
|
||||||
return this.charges;
|
return this.charges;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(final LoanProductConfigurableAttributes loanConfigurableAttributes) {
|
public void update(final LoanProductConfigurableAttributes loanConfigurableAttributes) {
|
||||||
@@ -616,11 +658,26 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
|||||||
return this.loanConfigurableAttributes;
|
return this.loanConfigurableAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Object> update(final JsonCommand command, final AprCalculator aprCalculator) {
|
public Map<String, Object> update(final JsonCommand command, final AprCalculator aprCalculator, FloatingRate floatingRate) {
|
||||||
|
|
||||||
final Map<String, Object> actualChanges = this.loanProductRelatedDetail.update(command, aprCalculator);
|
final Map<String, Object> actualChanges = this.loanProductRelatedDetail.update(command, aprCalculator);
|
||||||
actualChanges.putAll(loanProductMinMaxConstraints().update(command));
|
actualChanges.putAll(loanProductMinMaxConstraints().update(command));
|
||||||
|
|
||||||
|
final String isLinkedToFloatingInterestRates = "isLinkedToFloatingInterestRates";
|
||||||
|
if (command.isChangeInBooleanParameterNamed(isLinkedToFloatingInterestRates, this.isLinkedToFloatingInterestRate)) {
|
||||||
|
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(isLinkedToFloatingInterestRates);
|
||||||
|
actualChanges.put(isLinkedToFloatingInterestRates, newValue);
|
||||||
|
this.isLinkedToFloatingInterestRate = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isLinkedToFloatingInterestRate) {
|
||||||
|
actualChanges.putAll(loanProductFloatingRates().update(command, floatingRate));
|
||||||
|
this.loanProductRelatedDetail.updateForFloatingInterestRates();
|
||||||
|
this.loanProductMinMaxConstraints.updateForFloatingInterestRates();
|
||||||
|
}else{
|
||||||
|
this.floatingRates = null;
|
||||||
|
}
|
||||||
|
|
||||||
final String accountingTypeParamName = "accountingRule";
|
final String accountingTypeParamName = "accountingRule";
|
||||||
if (command.isChangeInIntegerParameterNamed(accountingTypeParamName, this.accountingRule)) {
|
if (command.isChangeInIntegerParameterNamed(accountingTypeParamName, this.accountingRule)) {
|
||||||
final Integer newValue = command.integerValueOfParameterNamed(accountingTypeParamName);
|
final Integer newValue = command.integerValueOfParameterNamed(accountingTypeParamName);
|
||||||
@@ -907,6 +964,13 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
|||||||
return actualChanges;
|
return actualChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private LoanProductFloatingRates loanProductFloatingRates() {
|
||||||
|
this.floatingRates = this.floatingRates == null
|
||||||
|
? new LoanProductFloatingRates(null, this, null, null, null, null, false)
|
||||||
|
: this.floatingRates;
|
||||||
|
return this.floatingRates;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isAccountingDisabled() {
|
public boolean isAccountingDisabled() {
|
||||||
return AccountingRuleType.NONE.getValue().equals(this.accountingRule);
|
return AccountingRuleType.NONE.getValue().equals(this.accountingRule);
|
||||||
}
|
}
|
||||||
@@ -1187,4 +1251,21 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
|||||||
public LoanProductRelatedDetail getLoanProductRelatedDetail() {
|
public LoanProductRelatedDetail getLoanProductRelatedDetail() {
|
||||||
return loanProductRelatedDetail;
|
return loanProductRelatedDetail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isLinkedToFloatingInterestRate() {
|
||||||
|
return this.isLinkedToFloatingInterestRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoanProductFloatingRates getFloatingRates() {
|
||||||
|
return this.floatingRates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<FloatingRatePeriodData> fetchInterestRates(final FloatingRateDTO floatingRateDTO) {
|
||||||
|
Collection<FloatingRatePeriodData> applicableRates = new ArrayList<>(1);
|
||||||
|
if (isLinkedToFloatingInterestRate()) {
|
||||||
|
applicableRates = getFloatingRates().fetchInterestRates(floatingRateDTO);
|
||||||
|
}
|
||||||
|
return applicableRates;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+148
@@ -0,0 +1,148 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.loanproduct.domain;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.OneToOne;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRateDTO;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.data.FloatingRatePeriodData;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.domain.FloatingRate;
|
||||||
|
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "m_product_loan_floating_rates")
|
||||||
|
public class LoanProductFloatingRates extends AbstractPersistable<Long> {
|
||||||
|
|
||||||
|
@OneToOne
|
||||||
|
@JoinColumn(name = "loan_product_id", nullable = false)
|
||||||
|
private LoanProduct loanProduct;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "floating_rates_id", nullable = false)
|
||||||
|
private FloatingRate floatingRate;
|
||||||
|
|
||||||
|
@Column(name = "interest_rate_differential", nullable = false)
|
||||||
|
private BigDecimal interestRateDifferential;
|
||||||
|
|
||||||
|
@Column(name = "min_differential_lending_rate", nullable = false)
|
||||||
|
private BigDecimal minDifferentialLendingRate;
|
||||||
|
|
||||||
|
@Column(name = "default_differential_lending_rate", nullable = false)
|
||||||
|
private BigDecimal defaultDifferentialLendingRate;
|
||||||
|
|
||||||
|
@Column(name = "max_differential_lending_rate", nullable = false)
|
||||||
|
private BigDecimal maxDifferentialLendingRate;
|
||||||
|
|
||||||
|
@Column(name = "is_floating_interest_rate_calculation_allowed", nullable = false)
|
||||||
|
private boolean isFloatingInterestRateCalculationAllowed;
|
||||||
|
|
||||||
|
public LoanProductFloatingRates(){
|
||||||
|
|
||||||
|
}
|
||||||
|
public LoanProductFloatingRates(FloatingRate floatingRate, LoanProduct loanProduct, BigDecimal interestRateDifferential,
|
||||||
|
BigDecimal minDifferentialLendingRate, BigDecimal maxDifferentialLendingRate, BigDecimal defaultDifferentialLendingRate,
|
||||||
|
boolean isFloatingInterestRateCalculationAllowed){
|
||||||
|
this.floatingRate = floatingRate;
|
||||||
|
this.loanProduct = loanProduct;
|
||||||
|
this.interestRateDifferential = interestRateDifferential;
|
||||||
|
this.minDifferentialLendingRate = minDifferentialLendingRate;
|
||||||
|
this.maxDifferentialLendingRate = maxDifferentialLendingRate;
|
||||||
|
this.defaultDifferentialLendingRate = defaultDifferentialLendingRate;
|
||||||
|
this.isFloatingInterestRateCalculationAllowed = isFloatingInterestRateCalculationAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoanProduct getLoanProduct() {
|
||||||
|
return this.loanProduct;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FloatingRate getFloatingRate() {
|
||||||
|
return this.floatingRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getInterestRateDifferential() {
|
||||||
|
return this.interestRateDifferential;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMinDifferentialLendingRate() {
|
||||||
|
return this.minDifferentialLendingRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getDefaultDifferentialLendingRate() {
|
||||||
|
return this.defaultDifferentialLendingRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMaxDifferentialLendingRate() {
|
||||||
|
return this.maxDifferentialLendingRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFloatingInterestRateCalculationAllowed() {
|
||||||
|
return this.isFloatingInterestRateCalculationAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<? extends String, ? extends Object> update(JsonCommand command, FloatingRate floatingRate) {
|
||||||
|
final Map<String, Object> actualChanges = new LinkedHashMap<>(20);
|
||||||
|
if (floatingRate != null) {
|
||||||
|
final String floatingRatesId = "floatingRatesId";
|
||||||
|
if (this.floatingRate == null || command.isChangeInLongParameterNamed(floatingRatesId, this.floatingRate.getId())) {
|
||||||
|
final long newValue = command.longValueOfParameterNamed(floatingRatesId);
|
||||||
|
actualChanges.put(floatingRatesId, newValue);
|
||||||
|
this.floatingRate = floatingRate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final String interestRateDifferential = "interestRateDifferential";
|
||||||
|
if (command.isChangeInBigDecimalParameterNamed(interestRateDifferential, this.interestRateDifferential)) {
|
||||||
|
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(interestRateDifferential);
|
||||||
|
actualChanges.put(interestRateDifferential, newValue);
|
||||||
|
this.interestRateDifferential = newValue;
|
||||||
|
}
|
||||||
|
final String minDifferentialLendingRate = "minDifferentialLendingRate";
|
||||||
|
if (command.isChangeInBigDecimalParameterNamed(minDifferentialLendingRate, this.minDifferentialLendingRate)) {
|
||||||
|
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(minDifferentialLendingRate);
|
||||||
|
actualChanges.put(minDifferentialLendingRate, newValue);
|
||||||
|
this.minDifferentialLendingRate = newValue;
|
||||||
|
}
|
||||||
|
final String defaultDifferentialLendingRate = "defaultDifferentialLendingRate";
|
||||||
|
if (command.isChangeInBigDecimalParameterNamed(defaultDifferentialLendingRate, this.defaultDifferentialLendingRate)) {
|
||||||
|
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(defaultDifferentialLendingRate);
|
||||||
|
actualChanges.put(defaultDifferentialLendingRate, newValue);
|
||||||
|
this.defaultDifferentialLendingRate = newValue;
|
||||||
|
}
|
||||||
|
final String maxDifferentialLendingRate = "maxDifferentialLendingRate";
|
||||||
|
if (command.isChangeInBigDecimalParameterNamed(maxDifferentialLendingRate, this.maxDifferentialLendingRate)) {
|
||||||
|
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(maxDifferentialLendingRate);
|
||||||
|
actualChanges.put(maxDifferentialLendingRate, newValue);
|
||||||
|
this.maxDifferentialLendingRate = newValue;
|
||||||
|
}
|
||||||
|
final String isFloatingInterestRateCalculationAllowed = "isFloatingInterestRateCalculationAllowed";
|
||||||
|
if (command
|
||||||
|
.isChangeInBooleanParameterNamed(isFloatingInterestRateCalculationAllowed, this.isFloatingInterestRateCalculationAllowed)) {
|
||||||
|
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(isFloatingInterestRateCalculationAllowed);
|
||||||
|
actualChanges.put(isFloatingInterestRateCalculationAllowed, newValue);
|
||||||
|
this.isFloatingInterestRateCalculationAllowed = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return actualChanges;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<FloatingRatePeriodData> fetchInterestRates(final FloatingRateDTO floatingRateDTO) {
|
||||||
|
floatingRateDTO.addInterestRateDiff(this.interestRateDifferential);
|
||||||
|
return floatingRate.fetchInterestRates(floatingRateDTO);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+5
@@ -147,4 +147,9 @@ public class LoanProductMinMaxConstraints {
|
|||||||
return this.maxNumberOfRepayments;
|
return this.maxNumberOfRepayments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateForFloatingInterestRates() {
|
||||||
|
this.minNominalInterestRatePerPeriod = null;
|
||||||
|
this.maxNominalInterestRatePerPeriod = null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+18
-7
@@ -43,16 +43,16 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
|
|||||||
@Column(name = "principal_amount", scale = 6, precision = 19, nullable = true)
|
@Column(name = "principal_amount", scale = 6, precision = 19, nullable = true)
|
||||||
private BigDecimal principal;
|
private BigDecimal principal;
|
||||||
|
|
||||||
@Column(name = "nominal_interest_rate_per_period", scale = 6, precision = 19, nullable = false)
|
@Column(name = "nominal_interest_rate_per_period", scale = 6, precision = 19, nullable = true)
|
||||||
private BigDecimal nominalInterestRatePerPeriod;
|
private BigDecimal nominalInterestRatePerPeriod;
|
||||||
|
|
||||||
// FIXME - move away form JPA ordinal use for enums using just integer -
|
// FIXME - move away form JPA ordinal use for enums using just integer -
|
||||||
// requires sql patch for existing users of software.
|
// requires sql patch for existing users of software.
|
||||||
@Enumerated(EnumType.ORDINAL)
|
@Enumerated(EnumType.ORDINAL)
|
||||||
@Column(name = "interest_period_frequency_enum", nullable = false)
|
@Column(name = "interest_period_frequency_enum", nullable = true)
|
||||||
private PeriodFrequencyType interestPeriodFrequencyType;
|
private PeriodFrequencyType interestPeriodFrequencyType;
|
||||||
|
|
||||||
@Column(name = "annual_nominal_interest_rate", scale = 6, precision = 19, nullable = false)
|
@Column(name = "annual_nominal_interest_rate", scale = 6, precision = 19, nullable = true)
|
||||||
private BigDecimal annualNominalInterestRate;
|
private BigDecimal annualNominalInterestRate;
|
||||||
|
|
||||||
// FIXME - move away form JPA ordinal use for enums using just integer -
|
// FIXME - move away form JPA ordinal use for enums using just integer -
|
||||||
@@ -205,17 +205,20 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BigDecimal getNominalInterestRatePerPeriod() {
|
public BigDecimal getNominalInterestRatePerPeriod() {
|
||||||
return BigDecimal.valueOf(Double.valueOf(this.nominalInterestRatePerPeriod.stripTrailingZeros().toString()));
|
return this.nominalInterestRatePerPeriod == null? null
|
||||||
|
: BigDecimal.valueOf(Double.valueOf(this.nominalInterestRatePerPeriod.stripTrailingZeros().toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PeriodFrequencyType getInterestPeriodFrequencyType() {
|
public PeriodFrequencyType getInterestPeriodFrequencyType() {
|
||||||
return this.interestPeriodFrequencyType;
|
return this.interestPeriodFrequencyType == null? PeriodFrequencyType.INVALID
|
||||||
|
: this.interestPeriodFrequencyType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BigDecimal getAnnualNominalInterestRate() {
|
public BigDecimal getAnnualNominalInterestRate() {
|
||||||
return BigDecimal.valueOf(Double.valueOf(this.annualNominalInterestRate.stripTrailingZeros().toString()));
|
return this.annualNominalInterestRate == null? null
|
||||||
|
:BigDecimal.valueOf(Double.valueOf(this.annualNominalInterestRate.stripTrailingZeros().toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -365,7 +368,9 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
|
|||||||
}
|
}
|
||||||
|
|
||||||
final String interestRateFrequencyTypeParamName = "interestRateFrequencyType";
|
final String interestRateFrequencyTypeParamName = "interestRateFrequencyType";
|
||||||
if (command.isChangeInIntegerParameterNamed(interestRateFrequencyTypeParamName, this.interestPeriodFrequencyType.getValue())) {
|
final int interestPeriodFrequencyType = this.interestPeriodFrequencyType == null?
|
||||||
|
PeriodFrequencyType.INVALID.getValue() : this.interestPeriodFrequencyType.getValue();
|
||||||
|
if (command.isChangeInIntegerParameterNamed(interestRateFrequencyTypeParamName, interestPeriodFrequencyType)) {
|
||||||
final Integer newValue = command.integerValueOfParameterNamed(interestRateFrequencyTypeParamName);
|
final Integer newValue = command.integerValueOfParameterNamed(interestRateFrequencyTypeParamName);
|
||||||
actualChanges.put(interestRateFrequencyTypeParamName, newValue);
|
actualChanges.put(interestRateFrequencyTypeParamName, newValue);
|
||||||
actualChanges.put("locale", localeAsInput);
|
actualChanges.put("locale", localeAsInput);
|
||||||
@@ -567,4 +572,10 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
|
|||||||
return this.inArrearsTolerance;
|
return this.inArrearsTolerance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateForFloatingInterestRates() {
|
||||||
|
this.nominalInterestRatePerPeriod = null;
|
||||||
|
this.interestPeriodFrequencyType = PeriodFrequencyType.INVALID;
|
||||||
|
this.annualNominalInterestRate = null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.loanproduct.exception;
|
||||||
|
|
||||||
|
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||||
|
|
||||||
|
public class LoanProductCannotBeModifiedDueToNonClosedLoansException extends AbstractPlatformDomainRuleException {
|
||||||
|
public LoanProductCannotBeModifiedDueToNonClosedLoansException(final Long id) {
|
||||||
|
super("error.msg.loanproduct.not.modifiable.due.to.non.closed.loans",
|
||||||
|
"Loan product with identifier " + id + " cannot be modified due to non closed loans associated with it.", id);
|
||||||
|
}
|
||||||
|
}
|
||||||
+340
-73
@@ -54,7 +54,9 @@ public final class LoanProductDataValidator {
|
|||||||
"minInterestRatePerPeriod", "maxInterestRatePerPeriod", "interestRateFrequencyType", "amortizationType", "interestType",
|
"minInterestRatePerPeriod", "maxInterestRatePerPeriod", "interestRateFrequencyType", "amortizationType", "interestType",
|
||||||
"interestCalculationPeriodType", "inArrearsTolerance", "transactionProcessingStrategyId", "graceOnPrincipalPayment",
|
"interestCalculationPeriodType", "inArrearsTolerance", "transactionProcessingStrategyId", "graceOnPrincipalPayment",
|
||||||
"graceOnInterestPayment", "graceOnInterestCharged", "charges", "accountingRule", "includeInBorrowerCycle", "startDate",
|
"graceOnInterestPayment", "graceOnInterestCharged", "charges", "accountingRule", "includeInBorrowerCycle", "startDate",
|
||||||
"closeDate", "externalId", LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(),
|
"closeDate", "externalId", "isLinkedToFloatingInterestRates", "floatingRatesId", "interestRateDifferential",
|
||||||
|
"minDifferentialLendingRate", "defaultDifferentialLendingRate", "maxDifferentialLendingRate",
|
||||||
|
"isFloatingInterestRateCalculationAllowed", LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(),
|
||||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(),
|
LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(),
|
||||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(),
|
LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(),
|
||||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(),
|
LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(),
|
||||||
@@ -214,48 +216,6 @@ public final class LoanProductDataValidator {
|
|||||||
Locale.getDefault());
|
Locale.getDefault());
|
||||||
baseDataValidator.reset().parameter("repaymentFrequencyType").value(repaymentFrequencyType).notNull().inMinMaxRange(0, 3);
|
baseDataValidator.reset().parameter("repaymentFrequencyType").value(repaymentFrequencyType).notNull().inMinMaxRange(0, 3);
|
||||||
|
|
||||||
final BigDecimal interestRatePerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element);
|
|
||||||
baseDataValidator.reset().parameter("interestRatePerPeriod").value(interestRatePerPeriod).notNull().zeroOrPositiveAmount();
|
|
||||||
|
|
||||||
final String minInterestRatePerPeriodParameterName = "minInterestRatePerPeriod";
|
|
||||||
BigDecimal minInterestRatePerPeriod = null;
|
|
||||||
if (this.fromApiJsonHelper.parameterExists(minInterestRatePerPeriodParameterName, element)) {
|
|
||||||
minInterestRatePerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minInterestRatePerPeriodParameterName,
|
|
||||||
element);
|
|
||||||
baseDataValidator.reset().parameter(minInterestRatePerPeriodParameterName).value(minInterestRatePerPeriod).ignoreIfNull()
|
|
||||||
.zeroOrPositiveAmount();
|
|
||||||
}
|
|
||||||
|
|
||||||
final String maxInterestRatePerPeriodParameterName = "maxInterestRatePerPeriod";
|
|
||||||
BigDecimal maxInterestRatePerPeriod = null;
|
|
||||||
if (this.fromApiJsonHelper.parameterExists(maxInterestRatePerPeriodParameterName, element)) {
|
|
||||||
maxInterestRatePerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxInterestRatePerPeriodParameterName,
|
|
||||||
element);
|
|
||||||
baseDataValidator.reset().parameter(maxInterestRatePerPeriodParameterName).value(maxInterestRatePerPeriod).ignoreIfNull()
|
|
||||||
.zeroOrPositiveAmount();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maxInterestRatePerPeriod != null && maxInterestRatePerPeriod.compareTo(BigDecimal.ZERO) != -1) {
|
|
||||||
if (minInterestRatePerPeriod != null && minInterestRatePerPeriod.compareTo(BigDecimal.ZERO) != -1) {
|
|
||||||
baseDataValidator.reset().parameter(maxInterestRatePerPeriodParameterName).value(maxInterestRatePerPeriod)
|
|
||||||
.notLessThanMin(minInterestRatePerPeriod);
|
|
||||||
if (minInterestRatePerPeriod.compareTo(maxInterestRatePerPeriod) <= 0) {
|
|
||||||
baseDataValidator.reset().parameter("interestRatePerPeriod").value(interestRatePerPeriod)
|
|
||||||
.inMinAndMaxAmountRange(minInterestRatePerPeriod, maxInterestRatePerPeriod);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
baseDataValidator.reset().parameter("interestRatePerPeriod").value(interestRatePerPeriod)
|
|
||||||
.notGreaterThanMax(maxInterestRatePerPeriod);
|
|
||||||
}
|
|
||||||
} else if (minInterestRatePerPeriod != null && minInterestRatePerPeriod.compareTo(BigDecimal.ZERO) != -1) {
|
|
||||||
baseDataValidator.reset().parameter("interestRatePerPeriod").value(interestRatePerPeriod)
|
|
||||||
.notLessThanMin(minInterestRatePerPeriod);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Integer interestRateFrequencyType = this.fromApiJsonHelper.extractIntegerNamed("interestRateFrequencyType", element,
|
|
||||||
Locale.getDefault());
|
|
||||||
baseDataValidator.reset().parameter("interestRateFrequencyType").value(interestRateFrequencyType).notNull().inMinMaxRange(0, 3);
|
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
final Integer amortizationType = this.fromApiJsonHelper.extractIntegerNamed("amortizationType", element, Locale.getDefault());
|
final Integer amortizationType = this.fromApiJsonHelper.extractIntegerNamed("amortizationType", element, Locale.getDefault());
|
||||||
baseDataValidator.reset().parameter("amortizationType").value(amortizationType).notNull().inMinMaxRange(0, 1);
|
baseDataValidator.reset().parameter("amortizationType").value(amortizationType).notNull().inMinMaxRange(0, 1);
|
||||||
@@ -330,6 +290,168 @@ public final class LoanProductDataValidator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//interest rates
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("isLinkedToFloatingInterestRates", element)
|
||||||
|
&& this.fromApiJsonHelper.extractBooleanNamed("isLinkedToFloatingInterestRates", element) == true){
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("interestRatePerPeriod", element)){
|
||||||
|
baseDataValidator.reset().parameter("interestRatePerPeriod").failWithCode("not.supported.when.isLinkedToFloatingInterestRates.is.true",
|
||||||
|
"interestRatePerPeriod param is not supported when isLinkedToFloatingInterestRates is true");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("minInterestRatePerPeriod", element)){
|
||||||
|
baseDataValidator.reset().parameter("minInterestRatePerPeriod").failWithCode("not.supported.when.isLinkedToFloatingInterestRates.is.true",
|
||||||
|
"minInterestRatePerPeriod param is not supported when isLinkedToFloatingInterestRates is true");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("maxInterestRatePerPeriod", element)){
|
||||||
|
baseDataValidator.reset().parameter("maxInterestRatePerPeriod").failWithCode("not.supported.when.isLinkedToFloatingInterestRates.is.true",
|
||||||
|
"maxInterestRatePerPeriod param is not supported when isLinkedToFloatingInterestRates is true");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("interestRateFrequencyType", element)){
|
||||||
|
baseDataValidator.reset().parameter("interestRateFrequencyType").failWithCode("not.supported.when.isLinkedToFloatingInterestRates.is.true",
|
||||||
|
"interestRateFrequencyType param is not supported when isLinkedToFloatingInterestRates is true");
|
||||||
|
}
|
||||||
|
if((interestType == null || interestType != InterestMethod.DECLINING_BALANCE.getValue())
|
||||||
|
|| (isInterestRecalculationEnabled == null || isInterestRecalculationEnabled == false)){
|
||||||
|
baseDataValidator.reset().parameter("isLinkedToFloatingInterestRates").failWithCode("supported.only.for.declining.balance.interest.recalculation.enabled",
|
||||||
|
"Floating interest rates are supported only for declining balance and interest recalculation enabled loan products");
|
||||||
|
}
|
||||||
|
|
||||||
|
final Integer floatingRatesId = this.fromApiJsonHelper.extractIntegerNamed("floatingRatesId", element,
|
||||||
|
Locale.getDefault());
|
||||||
|
baseDataValidator.reset().parameter("floatingRatesId").value(floatingRatesId).notNull();
|
||||||
|
|
||||||
|
final BigDecimal interestRateDifferential = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRateDifferential", element);
|
||||||
|
baseDataValidator.reset().parameter("interestRateDifferential").value(interestRateDifferential).notNull().zeroOrPositiveAmount();
|
||||||
|
|
||||||
|
final String minDifferentialLendingRateParameterName = "minDifferentialLendingRate";
|
||||||
|
BigDecimal minDifferentialLendingRate = null;
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(minDifferentialLendingRateParameterName, element)) {
|
||||||
|
minDifferentialLendingRate = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minDifferentialLendingRateParameterName,
|
||||||
|
element);
|
||||||
|
baseDataValidator.reset().parameter(minDifferentialLendingRateParameterName).value(minDifferentialLendingRate).ignoreIfNull()
|
||||||
|
.zeroOrPositiveAmount();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String defaultDifferentialLendingRateParameterName = "defaultDifferentialLendingRate";
|
||||||
|
BigDecimal defaultDifferentialLendingRate = null;
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(defaultDifferentialLendingRateParameterName, element)) {
|
||||||
|
defaultDifferentialLendingRate = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(defaultDifferentialLendingRateParameterName,
|
||||||
|
element);
|
||||||
|
baseDataValidator.reset().parameter(defaultDifferentialLendingRateParameterName).value(defaultDifferentialLendingRate).ignoreIfNull()
|
||||||
|
.zeroOrPositiveAmount();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String maxDifferentialLendingRateParameterName = "maxDifferentialLendingRate";
|
||||||
|
BigDecimal maxDifferentialLendingRate = null;
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(maxDifferentialLendingRateParameterName, element)) {
|
||||||
|
maxDifferentialLendingRate = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxDifferentialLendingRateParameterName,
|
||||||
|
element);
|
||||||
|
baseDataValidator.reset().parameter(maxDifferentialLendingRateParameterName).value(maxDifferentialLendingRate).ignoreIfNull()
|
||||||
|
.zeroOrPositiveAmount();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defaultDifferentialLendingRate != null && defaultDifferentialLendingRate.compareTo(BigDecimal.ZERO) != -1) {
|
||||||
|
if (minDifferentialLendingRate != null && minDifferentialLendingRate.compareTo(BigDecimal.ZERO) != -1) {
|
||||||
|
baseDataValidator.reset().parameter("defaultDifferentialLendingRate").value(defaultDifferentialLendingRate)
|
||||||
|
.notLessThanMin(minDifferentialLendingRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxDifferentialLendingRate != null && maxDifferentialLendingRate.compareTo(BigDecimal.ZERO) != -1) {
|
||||||
|
if (minDifferentialLendingRate != null && minDifferentialLendingRate.compareTo(BigDecimal.ZERO) != -1) {
|
||||||
|
baseDataValidator.reset().parameter("maxDifferentialLendingRate").value(maxDifferentialLendingRate)
|
||||||
|
.notLessThanMin(minDifferentialLendingRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxDifferentialLendingRate != null && maxDifferentialLendingRate.compareTo(BigDecimal.ZERO) != -1) {
|
||||||
|
if (defaultDifferentialLendingRate != null && defaultDifferentialLendingRate.compareTo(BigDecimal.ZERO) != -1) {
|
||||||
|
baseDataValidator.reset().parameter("maxDifferentialLendingRate").value(maxDifferentialLendingRate)
|
||||||
|
.notLessThanMin(defaultDifferentialLendingRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final Boolean isFloatingInterestRateCalculationAllowed = this.fromApiJsonHelper.extractBooleanNamed(
|
||||||
|
"isFloatingInterestRateCalculationAllowed", element);
|
||||||
|
baseDataValidator.reset().parameter("isFloatingInterestRateCalculationAllowed")
|
||||||
|
.value(isFloatingInterestRateCalculationAllowed).notNull().isOneOfTheseValues(true, false);
|
||||||
|
} else {
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("floatingRatesId", element)){
|
||||||
|
baseDataValidator.reset().parameter("floatingRatesId").failWithCode("not.supported.when.isLinkedToFloatingInterestRates.is.false",
|
||||||
|
"floatingRatesId param is not supported when isLinkedToFloatingInterestRates is not supplied or false");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("interestRateDifferential", element)){
|
||||||
|
baseDataValidator.reset().parameter("interestRateDifferential").failWithCode("not.supported.when.isLinkedToFloatingInterestRates.is.false",
|
||||||
|
"interestRateDifferential param is not supported when isLinkedToFloatingInterestRates is not supplied or false");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("minDifferentialLendingRate", element)){
|
||||||
|
baseDataValidator.reset().parameter("minDifferentialLendingRate").failWithCode("not.supported.when.isLinkedToFloatingInterestRates.is.false",
|
||||||
|
"minDifferentialLendingRate param is not supported when isLinkedToFloatingInterestRates is not supplied or false");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("defaultDifferentialLendingRate", element)){
|
||||||
|
baseDataValidator.reset().parameter("defaultDifferentialLendingRate").failWithCode("not.supported.when.isLinkedToFloatingInterestRates.is.false",
|
||||||
|
"defaultDifferentialLendingRate param is not supported when isLinkedToFloatingInterestRates is not supplied or false");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("maxDifferentialLendingRate", element)){
|
||||||
|
baseDataValidator.reset().parameter("maxDifferentialLendingRate").failWithCode("not.supported.when.isLinkedToFloatingInterestRates.is.false",
|
||||||
|
"maxDifferentialLendingRate param is not supported when isLinkedToFloatingInterestRates is not supplied or false");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("isFloatingInterestRateCalculationAllowed", element)){
|
||||||
|
baseDataValidator.reset().parameter("isFloatingInterestRateCalculationAllowed").failWithCode("not.supported.when.isLinkedToFloatingInterestRates.is.false",
|
||||||
|
"isFloatingInterestRateCalculationAllowed param is not supported when isLinkedToFloatingInterestRates is not supplied or false");
|
||||||
|
}
|
||||||
|
|
||||||
|
final BigDecimal interestRatePerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element);
|
||||||
|
baseDataValidator.reset().parameter("interestRatePerPeriod").value(interestRatePerPeriod).notNull().zeroOrPositiveAmount();
|
||||||
|
|
||||||
|
final String minInterestRatePerPeriodParameterName = "minInterestRatePerPeriod";
|
||||||
|
BigDecimal minInterestRatePerPeriod = null;
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(minInterestRatePerPeriodParameterName, element)) {
|
||||||
|
minInterestRatePerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minInterestRatePerPeriodParameterName,
|
||||||
|
element);
|
||||||
|
baseDataValidator.reset().parameter(minInterestRatePerPeriodParameterName).value(minInterestRatePerPeriod).ignoreIfNull()
|
||||||
|
.zeroOrPositiveAmount();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String maxInterestRatePerPeriodParameterName = "maxInterestRatePerPeriod";
|
||||||
|
BigDecimal maxInterestRatePerPeriod = null;
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(maxInterestRatePerPeriodParameterName, element)) {
|
||||||
|
maxInterestRatePerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxInterestRatePerPeriodParameterName,
|
||||||
|
element);
|
||||||
|
baseDataValidator.reset().parameter(maxInterestRatePerPeriodParameterName).value(maxInterestRatePerPeriod).ignoreIfNull()
|
||||||
|
.zeroOrPositiveAmount();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxInterestRatePerPeriod != null && maxInterestRatePerPeriod.compareTo(BigDecimal.ZERO) != -1) {
|
||||||
|
if (minInterestRatePerPeriod != null && minInterestRatePerPeriod.compareTo(BigDecimal.ZERO) != -1) {
|
||||||
|
baseDataValidator.reset().parameter(maxInterestRatePerPeriodParameterName).value(maxInterestRatePerPeriod)
|
||||||
|
.notLessThanMin(minInterestRatePerPeriod);
|
||||||
|
if (minInterestRatePerPeriod.compareTo(maxInterestRatePerPeriod) <= 0) {
|
||||||
|
baseDataValidator.reset().parameter("interestRatePerPeriod").value(interestRatePerPeriod)
|
||||||
|
.inMinAndMaxAmountRange(minInterestRatePerPeriod, maxInterestRatePerPeriod);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
baseDataValidator.reset().parameter("interestRatePerPeriod").value(interestRatePerPeriod)
|
||||||
|
.notGreaterThanMax(maxInterestRatePerPeriod);
|
||||||
|
}
|
||||||
|
} else if (minInterestRatePerPeriod != null && minInterestRatePerPeriod.compareTo(BigDecimal.ZERO) != -1) {
|
||||||
|
baseDataValidator.reset().parameter("interestRatePerPeriod").value(interestRatePerPeriod)
|
||||||
|
.notLessThanMin(minInterestRatePerPeriod);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Integer interestRateFrequencyType = this.fromApiJsonHelper.extractIntegerNamed("interestRateFrequencyType", element,
|
||||||
|
Locale.getDefault());
|
||||||
|
baseDataValidator.reset().parameter("interestRateFrequencyType").value(interestRateFrequencyType).notNull().inMinMaxRange(0, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Guarantee Funds
|
// Guarantee Funds
|
||||||
Boolean holdGuaranteeFunds = false;
|
Boolean holdGuaranteeFunds = false;
|
||||||
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.holdGuaranteeFundsParamName, element)) {
|
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.holdGuaranteeFundsParamName, element)) {
|
||||||
@@ -746,30 +868,6 @@ public final class LoanProductDataValidator {
|
|||||||
baseDataValidator.reset().parameter("inArrearsTolerance").value(inArrearsTolerance).ignoreIfNull().zeroOrPositiveAmount();
|
baseDataValidator.reset().parameter("inArrearsTolerance").value(inArrearsTolerance).ignoreIfNull().zeroOrPositiveAmount();
|
||||||
}
|
}
|
||||||
|
|
||||||
final String minInterestRatePerPeriodParameterName = "minInterestRatePerPeriod";
|
|
||||||
BigDecimal minInterestRatePerPeriod = null;
|
|
||||||
if (this.fromApiJsonHelper.parameterExists(minInterestRatePerPeriodParameterName, element)) {
|
|
||||||
minInterestRatePerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minInterestRatePerPeriodParameterName,
|
|
||||||
element);
|
|
||||||
baseDataValidator.reset().parameter(minInterestRatePerPeriodParameterName).value(minInterestRatePerPeriod).ignoreIfNull()
|
|
||||||
.zeroOrPositiveAmount();
|
|
||||||
}
|
|
||||||
|
|
||||||
final String maxInterestRatePerPeriodParameterName = "maxInterestRatePerPeriod";
|
|
||||||
BigDecimal maxInterestRatePerPeriod = null;
|
|
||||||
if (this.fromApiJsonHelper.parameterExists(maxInterestRatePerPeriodParameterName, element)) {
|
|
||||||
maxInterestRatePerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxInterestRatePerPeriodParameterName,
|
|
||||||
element);
|
|
||||||
baseDataValidator.reset().parameter(maxInterestRatePerPeriodParameterName).value(maxInterestRatePerPeriod).ignoreIfNull()
|
|
||||||
.zeroOrPositiveAmount();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.fromApiJsonHelper.parameterExists("interestRatePerPeriod", element)) {
|
|
||||||
final BigDecimal interestRatePerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod",
|
|
||||||
element);
|
|
||||||
baseDataValidator.reset().parameter("interestRatePerPeriod").value(interestRatePerPeriod).notNull().zeroOrPositiveAmount();
|
|
||||||
}
|
|
||||||
|
|
||||||
final String minNumberOfRepaymentsParameterName = "minNumberOfRepayments";
|
final String minNumberOfRepaymentsParameterName = "minNumberOfRepayments";
|
||||||
Integer minNumberOfRepayments = null;
|
Integer minNumberOfRepayments = null;
|
||||||
if (this.fromApiJsonHelper.parameterExists(minNumberOfRepaymentsParameterName, element)) {
|
if (this.fromApiJsonHelper.parameterExists(minNumberOfRepaymentsParameterName, element)) {
|
||||||
@@ -841,12 +939,6 @@ public final class LoanProductDataValidator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
if (this.fromApiJsonHelper.parameterExists("interestRateFrequencyType", element)) {
|
|
||||||
final Integer interestRateFrequencyType = this.fromApiJsonHelper.extractIntegerNamed("interestRateFrequencyType", element,
|
|
||||||
Locale.getDefault());
|
|
||||||
baseDataValidator.reset().parameter("interestRateFrequencyType").value(interestRateFrequencyType).notNull().inMinMaxRange(0, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.fromApiJsonHelper.parameterExists("amortizationType", element)) {
|
if (this.fromApiJsonHelper.parameterExists("amortizationType", element)) {
|
||||||
final Integer amortizationType = this.fromApiJsonHelper.extractIntegerNamed("amortizationType", element, Locale.getDefault());
|
final Integer amortizationType = this.fromApiJsonHelper.extractIntegerNamed("amortizationType", element, Locale.getDefault());
|
||||||
baseDataValidator.reset().parameter("amortizationType").value(amortizationType).notNull().inMinMaxRange(0, 1);
|
baseDataValidator.reset().parameter("amortizationType").value(amortizationType).notNull().inMinMaxRange(0, 1);
|
||||||
@@ -906,6 +998,176 @@ public final class LoanProductDataValidator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//interest rates
|
||||||
|
boolean isLinkedToFloatingInterestRates = loanProduct.isLinkedToFloatingInterestRate();
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("isLinkedToFloatingInterestRates", element)){
|
||||||
|
isLinkedToFloatingInterestRates = this.fromApiJsonHelper.extractBooleanNamed("isLinkedToFloatingInterestRates", element);
|
||||||
|
}
|
||||||
|
if(isLinkedToFloatingInterestRates){
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("interestRatePerPeriod", element)){
|
||||||
|
baseDataValidator.reset().parameter("interestRatePerPeriod").failWithCode("not.supported.when.isLinkedToFloatingInterestRates.is.true",
|
||||||
|
"interestRatePerPeriod param is not supported when isLinkedToFloatingInterestRates is true");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("minInterestRatePerPeriod", element)){
|
||||||
|
baseDataValidator.reset().parameter("minInterestRatePerPeriod").failWithCode("not.supported.when.isLinkedToFloatingInterestRates.is.true",
|
||||||
|
"minInterestRatePerPeriod param is not supported when isLinkedToFloatingInterestRates is true");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("maxInterestRatePerPeriod", element)){
|
||||||
|
baseDataValidator.reset().parameter("maxInterestRatePerPeriod").failWithCode("not.supported.when.isLinkedToFloatingInterestRates.is.true",
|
||||||
|
"maxInterestRatePerPeriod param is not supported when isLinkedToFloatingInterestRates is true");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("interestRateFrequencyType", element)){
|
||||||
|
baseDataValidator.reset().parameter("interestRateFrequencyType").failWithCode("not.supported.when.isLinkedToFloatingInterestRates.is.true",
|
||||||
|
"interestRateFrequencyType param is not supported when isLinkedToFloatingInterestRates is true");
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer interestType = this.fromApiJsonHelper.parameterExists("interestType", element)
|
||||||
|
? this.fromApiJsonHelper.extractIntegerNamed("interestType", element, Locale.getDefault())
|
||||||
|
: loanProduct.getLoanProductRelatedDetail().getInterestMethod().getValue();
|
||||||
|
if((interestType == null || interestType != InterestMethod.DECLINING_BALANCE.getValue())
|
||||||
|
|| (isInterestRecalculationEnabled == null || isInterestRecalculationEnabled == false)){
|
||||||
|
baseDataValidator.reset().parameter("isLinkedToFloatingInterestRates").failWithCode("supported.only.for.declining.balance.interest.recalculation.enabled",
|
||||||
|
"Floating interest rates are supported only for declining balance and interest recalculation enabled loan products");
|
||||||
|
}
|
||||||
|
|
||||||
|
Long floatingRatesId = loanProduct.getFloatingRates() == null? null: loanProduct.getFloatingRates().getFloatingRate().getId();
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("floatingRatesId", element)){
|
||||||
|
floatingRatesId = this.fromApiJsonHelper.extractLongNamed("floatingRatesId", element);
|
||||||
|
}
|
||||||
|
baseDataValidator.reset().parameter("floatingRatesId").value(floatingRatesId).notNull();
|
||||||
|
|
||||||
|
BigDecimal interestRateDifferential = loanProduct.getFloatingRates() == null? null: loanProduct.getFloatingRates().getInterestRateDifferential();
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("interestRateDifferential", element)){
|
||||||
|
interestRateDifferential = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRateDifferential", element);
|
||||||
|
}
|
||||||
|
baseDataValidator.reset().parameter("interestRateDifferential").value(interestRateDifferential).notNull().zeroOrPositiveAmount();
|
||||||
|
|
||||||
|
final String minDifferentialLendingRateParameterName = "minDifferentialLendingRate";
|
||||||
|
BigDecimal minDifferentialLendingRate = loanProduct.getFloatingRates() == null
|
||||||
|
? null:loanProduct.getFloatingRates().getMinDifferentialLendingRate();
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(minDifferentialLendingRateParameterName, element)) {
|
||||||
|
minDifferentialLendingRate = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minDifferentialLendingRateParameterName,
|
||||||
|
element);
|
||||||
|
}
|
||||||
|
baseDataValidator.reset().parameter(minDifferentialLendingRateParameterName).value(minDifferentialLendingRate).ignoreIfNull()
|
||||||
|
.zeroOrPositiveAmount();
|
||||||
|
|
||||||
|
final String defaultDifferentialLendingRateParameterName = "defaultDifferentialLendingRate";
|
||||||
|
BigDecimal defaultDifferentialLendingRate = loanProduct.getFloatingRates() == null
|
||||||
|
? null:loanProduct.getFloatingRates().getDefaultDifferentialLendingRate();
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(defaultDifferentialLendingRateParameterName, element)) {
|
||||||
|
defaultDifferentialLendingRate = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(defaultDifferentialLendingRateParameterName,
|
||||||
|
element);
|
||||||
|
}
|
||||||
|
baseDataValidator.reset().parameter(defaultDifferentialLendingRateParameterName).value(defaultDifferentialLendingRate).ignoreIfNull()
|
||||||
|
.zeroOrPositiveAmount();
|
||||||
|
|
||||||
|
final String maxDifferentialLendingRateParameterName = "maxDifferentialLendingRate";
|
||||||
|
BigDecimal maxDifferentialLendingRate = loanProduct.getFloatingRates() == null
|
||||||
|
? null:loanProduct.getFloatingRates().getMaxDifferentialLendingRate();
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(maxDifferentialLendingRateParameterName, element)) {
|
||||||
|
maxDifferentialLendingRate = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxDifferentialLendingRateParameterName,
|
||||||
|
element);
|
||||||
|
}
|
||||||
|
baseDataValidator.reset().parameter(maxDifferentialLendingRateParameterName).value(maxDifferentialLendingRate).ignoreIfNull()
|
||||||
|
.zeroOrPositiveAmount();
|
||||||
|
|
||||||
|
if (defaultDifferentialLendingRate != null && defaultDifferentialLendingRate.compareTo(BigDecimal.ZERO) != -1) {
|
||||||
|
if (minDifferentialLendingRate != null && minDifferentialLendingRate.compareTo(BigDecimal.ZERO) != -1) {
|
||||||
|
baseDataValidator.reset().parameter("defaultDifferentialLendingRate").value(defaultDifferentialLendingRate)
|
||||||
|
.notLessThanMin(minDifferentialLendingRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxDifferentialLendingRate != null && maxDifferentialLendingRate.compareTo(BigDecimal.ZERO) != -1) {
|
||||||
|
if (minDifferentialLendingRate != null && minDifferentialLendingRate.compareTo(BigDecimal.ZERO) != -1) {
|
||||||
|
baseDataValidator.reset().parameter("maxDifferentialLendingRate").value(maxDifferentialLendingRate)
|
||||||
|
.notLessThanMin(minDifferentialLendingRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxDifferentialLendingRate != null && maxDifferentialLendingRate.compareTo(BigDecimal.ZERO) != -1) {
|
||||||
|
if (defaultDifferentialLendingRate != null && defaultDifferentialLendingRate.compareTo(BigDecimal.ZERO) != -1) {
|
||||||
|
baseDataValidator.reset().parameter("maxDifferentialLendingRate").value(maxDifferentialLendingRate)
|
||||||
|
.notLessThanMin(defaultDifferentialLendingRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Boolean isFloatingInterestRateCalculationAllowed = loanProduct.getFloatingRates() == null ? null
|
||||||
|
: loanProduct.getFloatingRates().isFloatingInterestRateCalculationAllowed();
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("isFloatingInterestRateCalculationAllowed", element)){
|
||||||
|
isFloatingInterestRateCalculationAllowed = this.fromApiJsonHelper.extractBooleanNamed(
|
||||||
|
"isFloatingInterestRateCalculationAllowed", element);
|
||||||
|
}
|
||||||
|
baseDataValidator.reset().parameter("isFloatingInterestRateCalculationAllowed")
|
||||||
|
.value(isFloatingInterestRateCalculationAllowed).notNull().isOneOfTheseValues(true, false);
|
||||||
|
} else {
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("floatingRatesId", element)){
|
||||||
|
baseDataValidator.reset().parameter("floatingRatesId").failWithCode("not.supported.when.isLinkedToFloatingInterestRates.is.false",
|
||||||
|
"floatingRatesId param is not supported when isLinkedToFloatingInterestRates is not supplied or false");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("interestRateDifferential", element)){
|
||||||
|
baseDataValidator.reset().parameter("interestRateDifferential").failWithCode("not.supported.when.isLinkedToFloatingInterestRates.is.false",
|
||||||
|
"interestRateDifferential param is not supported when isLinkedToFloatingInterestRates is not supplied or false");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("minDifferentialLendingRate", element)){
|
||||||
|
baseDataValidator.reset().parameter("minDifferentialLendingRate").failWithCode("not.supported.when.isLinkedToFloatingInterestRates.is.false",
|
||||||
|
"minDifferentialLendingRate param is not supported when isLinkedToFloatingInterestRates is not supplied or false");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("defaultDifferentialLendingRate", element)){
|
||||||
|
baseDataValidator.reset().parameter("defaultDifferentialLendingRate").failWithCode("not.supported.when.isLinkedToFloatingInterestRates.is.false",
|
||||||
|
"defaultDifferentialLendingRate param is not supported when isLinkedToFloatingInterestRates is not supplied or false");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("maxDifferentialLendingRate", element)){
|
||||||
|
baseDataValidator.reset().parameter("maxDifferentialLendingRate").failWithCode("not.supported.when.isLinkedToFloatingInterestRates.is.false",
|
||||||
|
"maxDifferentialLendingRate param is not supported when isLinkedToFloatingInterestRates is not supplied or false");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.fromApiJsonHelper.parameterExists("isFloatingInterestRateCalculationAllowed", element)){
|
||||||
|
baseDataValidator.reset().parameter("isFloatingInterestRateCalculationAllowed").failWithCode("not.supported.when.isLinkedToFloatingInterestRates.is.false",
|
||||||
|
"isFloatingInterestRateCalculationAllowed param is not supported when isLinkedToFloatingInterestRates is not supplied or false");
|
||||||
|
}
|
||||||
|
|
||||||
|
final String minInterestRatePerPeriodParameterName = "minInterestRatePerPeriod";
|
||||||
|
BigDecimal minInterestRatePerPeriod = loanProduct.getMinNominalInterestRatePerPeriod();
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(minInterestRatePerPeriodParameterName, element)) {
|
||||||
|
minInterestRatePerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minInterestRatePerPeriodParameterName,
|
||||||
|
element);
|
||||||
|
}
|
||||||
|
baseDataValidator.reset().parameter(minInterestRatePerPeriodParameterName).value(minInterestRatePerPeriod).ignoreIfNull()
|
||||||
|
.zeroOrPositiveAmount();
|
||||||
|
|
||||||
|
final String maxInterestRatePerPeriodParameterName = "maxInterestRatePerPeriod";
|
||||||
|
BigDecimal maxInterestRatePerPeriod = loanProduct.getMaxNominalInterestRatePerPeriod();
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(maxInterestRatePerPeriodParameterName, element)) {
|
||||||
|
maxInterestRatePerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxInterestRatePerPeriodParameterName,
|
||||||
|
element);
|
||||||
|
}
|
||||||
|
baseDataValidator.reset().parameter(maxInterestRatePerPeriodParameterName).value(maxInterestRatePerPeriod).ignoreIfNull()
|
||||||
|
.zeroOrPositiveAmount();
|
||||||
|
|
||||||
|
BigDecimal interestRatePerPeriod = loanProduct.getLoanProductRelatedDetail().getNominalInterestRatePerPeriod();
|
||||||
|
if (this.fromApiJsonHelper.parameterExists("interestRatePerPeriod", element)) {
|
||||||
|
interestRatePerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod",
|
||||||
|
element);
|
||||||
|
}
|
||||||
|
baseDataValidator.reset().parameter("interestRatePerPeriod").value(interestRatePerPeriod).notNull().zeroOrPositiveAmount();
|
||||||
|
|
||||||
|
Integer interestRateFrequencyType = loanProduct.getLoanProductRelatedDetail().getInterestPeriodFrequencyType().getValue();
|
||||||
|
if (this.fromApiJsonHelper.parameterExists("interestRateFrequencyType", element)) {
|
||||||
|
interestRateFrequencyType = this.fromApiJsonHelper.extractIntegerNamed("interestRateFrequencyType", element,
|
||||||
|
Locale.getDefault());
|
||||||
|
}
|
||||||
|
baseDataValidator.reset().parameter("interestRateFrequencyType").value(interestRateFrequencyType).notNull().inMinMaxRange(0, 3);
|
||||||
|
}
|
||||||
|
|
||||||
// Guarantee Funds
|
// Guarantee Funds
|
||||||
Boolean holdGuaranteeFunds = loanProduct.isHoldGuaranteeFundsEnabled();
|
Boolean holdGuaranteeFunds = loanProduct.isHoldGuaranteeFundsEnabled();
|
||||||
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.holdGuaranteeFundsParamName, element)) {
|
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.holdGuaranteeFundsParamName, element)) {
|
||||||
@@ -1303,6 +1565,11 @@ public final class LoanProductDataValidator {
|
|||||||
private void validateNominalInterestRatePerPeriodMinMaxConstraint(final JsonElement element, final LoanProduct loanProduct,
|
private void validateNominalInterestRatePerPeriodMinMaxConstraint(final JsonElement element, final LoanProduct loanProduct,
|
||||||
final DataValidatorBuilder baseDataValidator) {
|
final DataValidatorBuilder baseDataValidator) {
|
||||||
|
|
||||||
|
if((this.fromApiJsonHelper.parameterExists("isLinkedToFloatingInterestRates", element)
|
||||||
|
&& this.fromApiJsonHelper.extractBooleanNamed("isLinkedToFloatingInterestRates", element) == true)
|
||||||
|
|| loanProduct.isLinkedToFloatingInterestRate()){
|
||||||
|
return;
|
||||||
|
}
|
||||||
boolean iRPUpdated = false;
|
boolean iRPUpdated = false;
|
||||||
boolean minIRPUpdated = false;
|
boolean minIRPUpdated = false;
|
||||||
boolean maxIRPUpdated = false;
|
boolean maxIRPUpdated = false;
|
||||||
|
|||||||
+5
-1
@@ -199,7 +199,7 @@ public class LoanEnumerations {
|
|||||||
return optionData;
|
return optionData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static EnumOptionData interestRateFrequencyType(final int id) {
|
public static EnumOptionData interestRateFrequencyType(final Integer id) {
|
||||||
return interestRateFrequencyType(PeriodFrequencyType.fromInt(id));
|
return interestRateFrequencyType(PeriodFrequencyType.fromInt(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -503,6 +503,10 @@ public class LoanEnumerations {
|
|||||||
optionData = new EnumOptionData(LoanTermVariationType.EMI_AMOUNT.getValue().longValue(),
|
optionData = new EnumOptionData(LoanTermVariationType.EMI_AMOUNT.getValue().longValue(),
|
||||||
LoanTermVariationType.EMI_AMOUNT.getCode(), "emiAmount");
|
LoanTermVariationType.EMI_AMOUNT.getCode(), "emiAmount");
|
||||||
break;
|
break;
|
||||||
|
case INTEREST_RATE:
|
||||||
|
optionData = new EnumOptionData(LoanTermVariationType.INTEREST_RATE.getValue().longValue(),
|
||||||
|
LoanTermVariationType.INTEREST_RATE.getCode(), "interestRate");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
optionData = new EnumOptionData(LoanTermVariationType.INVALID.getValue().longValue(),
|
optionData = new EnumOptionData(LoanTermVariationType.INVALID.getValue().longValue(),
|
||||||
LoanTermVariationType.INVALID.getCode(), "Invalid");
|
LoanTermVariationType.INVALID.getCode(), "Invalid");
|
||||||
|
|||||||
+24
-3
@@ -192,13 +192,23 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
+ "curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, curr.display_symbol as currencyDisplaySymbol, lp.external_id as externalId, "
|
+ "curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, curr.display_symbol as currencyDisplaySymbol, lp.external_id as externalId, "
|
||||||
+ "lca.id as lcaId, lca.amortization_method_enum as amortizationBoolean, lca.interest_method_enum as interestMethodConfigBoolean, "
|
+ "lca.id as lcaId, lca.amortization_method_enum as amortizationBoolean, lca.interest_method_enum as interestMethodConfigBoolean, "
|
||||||
+ "lca.loan_transaction_strategy_id as transactionProcessingStrategyBoolean,lca.interest_calculated_in_period_enum as interestCalcPeriodBoolean, lca.arrearstolerance_amount as arrearsToleranceBoolean, "
|
+ "lca.loan_transaction_strategy_id as transactionProcessingStrategyBoolean,lca.interest_calculated_in_period_enum as interestCalcPeriodBoolean, lca.arrearstolerance_amount as arrearsToleranceBoolean, "
|
||||||
+ "lca.repay_every as repaymentFrequencyBoolean, lca.moratorium as graceOnPrincipalAndInterestBoolean, lca.grace_on_arrears_ageing as graceOnArrearsAgingBoolean "
|
+ "lca.repay_every as repaymentFrequencyBoolean, lca.moratorium as graceOnPrincipalAndInterestBoolean, lca.grace_on_arrears_ageing as graceOnArrearsAgingBoolean, "
|
||||||
|
+ "lp.is_linked_to_floating_interest_rates as isLinkedToFloatingInterestRates, "
|
||||||
|
+ "lfr.floating_rates_id as floatingRateId, "
|
||||||
|
+ "fr.name as floatingRateName, "
|
||||||
|
+ "lfr.interest_rate_differential as interestRateDifferential, "
|
||||||
|
+ "lfr.min_differential_lending_rate as minDifferentialLendingRate, "
|
||||||
|
+ "lfr.default_differential_lending_rate as defaultDifferentialLendingRate, "
|
||||||
|
+ "lfr.max_differential_lending_rate as maxDifferentialLendingRate, "
|
||||||
|
+ "lfr.is_floating_interest_rate_calculation_allowed as isFloatingInterestRateCalculationAllowed "
|
||||||
+ " from m_product_loan lp "
|
+ " from m_product_loan lp "
|
||||||
+ " left join m_fund f on f.id = lp.fund_id "
|
+ " left join m_fund f on f.id = lp.fund_id "
|
||||||
+ " left join m_product_loan_recalculation_details lpr on lpr.product_id=lp.id "
|
+ " left join m_product_loan_recalculation_details lpr on lpr.product_id=lp.id "
|
||||||
+ " left join m_product_loan_guarantee_details lpg on lpg.loan_product_id=lp.id "
|
+ " left join m_product_loan_guarantee_details lpg on lpg.loan_product_id=lp.id "
|
||||||
+ " left join ref_loan_transaction_processing_strategy ltps on ltps.id = lp.loan_transaction_strategy_id"
|
+ " left join ref_loan_transaction_processing_strategy ltps on ltps.id = lp.loan_transaction_strategy_id"
|
||||||
+ " left join m_product_loan_configurable_attributes lca on lca.loan_product_id = lp.id "
|
+ " left join m_product_loan_configurable_attributes lca on lca.loan_product_id = lp.id "
|
||||||
|
+ " left join m_product_loan_floating_rates as lfr on lfr.loan_product_id = lp.id "
|
||||||
|
+ " left join m_floating_rates as fr on lfr.floating_rates_id = fr.id "
|
||||||
+ " join m_currency curr on curr.code = lp.currency_code";
|
+ " join m_currency curr on curr.code = lp.currency_code";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,13 +260,22 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
final BigDecimal maxInterestRatePerPeriod = rs.getBigDecimal("maxInterestRatePerPeriod");
|
final BigDecimal maxInterestRatePerPeriod = rs.getBigDecimal("maxInterestRatePerPeriod");
|
||||||
final BigDecimal annualInterestRate = rs.getBigDecimal("annualInterestRate");
|
final BigDecimal annualInterestRate = rs.getBigDecimal("annualInterestRate");
|
||||||
|
|
||||||
|
final boolean isLinkedToFloatingInterestRates = rs.getBoolean("isLinkedToFloatingInterestRates");
|
||||||
|
final Integer floatingRateId = JdbcSupport.getIntegerDefaultToNullIfZero(rs, "floatingRateId");
|
||||||
|
final String floatingRateName = rs.getString("floatingRateName");
|
||||||
|
final BigDecimal interestRateDifferential = rs.getBigDecimal("interestRateDifferential");
|
||||||
|
final BigDecimal minDifferentialLendingRate = rs.getBigDecimal("minDifferentialLendingRate");
|
||||||
|
final BigDecimal defaultDifferentialLendingRate = rs.getBigDecimal("defaultDifferentialLendingRate");
|
||||||
|
final BigDecimal maxDifferentialLendingRate = rs.getBigDecimal("maxDifferentialLendingRate");
|
||||||
|
final boolean isFloatingInterestRateCalculationAllowed = rs.getBoolean("isFloatingInterestRateCalculationAllowed");
|
||||||
|
|
||||||
final int repaymentFrequencyTypeId = JdbcSupport.getInteger(rs, "repaymentPeriodFrequency");
|
final int repaymentFrequencyTypeId = JdbcSupport.getInteger(rs, "repaymentPeriodFrequency");
|
||||||
final EnumOptionData repaymentFrequencyType = LoanEnumerations.repaymentFrequencyType(repaymentFrequencyTypeId);
|
final EnumOptionData repaymentFrequencyType = LoanEnumerations.repaymentFrequencyType(repaymentFrequencyTypeId);
|
||||||
|
|
||||||
final int amortizationTypeId = JdbcSupport.getInteger(rs, "amortizationMethod");
|
final int amortizationTypeId = JdbcSupport.getInteger(rs, "amortizationMethod");
|
||||||
final EnumOptionData amortizationType = LoanEnumerations.amortizationType(amortizationTypeId);
|
final EnumOptionData amortizationType = LoanEnumerations.amortizationType(amortizationTypeId);
|
||||||
|
|
||||||
final int interestRateFrequencyTypeId = JdbcSupport.getInteger(rs, "interestRatePerPeriodFreq");
|
final Integer interestRateFrequencyTypeId = JdbcSupport.getInteger(rs, "interestRatePerPeriodFreq");
|
||||||
final EnumOptionData interestRateFrequencyType = LoanEnumerations.interestRateFrequencyType(interestRateFrequencyTypeId);
|
final EnumOptionData interestRateFrequencyType = LoanEnumerations.interestRateFrequencyType(interestRateFrequencyTypeId);
|
||||||
|
|
||||||
final int interestTypeId = JdbcSupport.getInteger(rs, "interestMethod");
|
final int interestTypeId = JdbcSupport.getInteger(rs, "interestMethod");
|
||||||
@@ -377,7 +396,9 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||||
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, loanProductGuaranteeData,
|
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, loanProductGuaranteeData,
|
||||||
principalThresholdForLastInstallment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount,
|
principalThresholdForLastInstallment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount,
|
||||||
installmentAmountInMultiplesOf, allowAttributeOverrides);
|
installmentAmountInMultiplesOf, allowAttributeOverrides, isLinkedToFloatingInterestRates, floatingRateId,
|
||||||
|
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
||||||
|
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+38
-4
@@ -21,9 +21,12 @@ import org.mifosplatform.infrastructure.entityaccess.service.MifosEntityAccessUt
|
|||||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||||
import org.mifosplatform.portfolio.charge.domain.Charge;
|
import org.mifosplatform.portfolio.charge.domain.Charge;
|
||||||
import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper;
|
import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.domain.FloatingRate;
|
||||||
|
import org.mifosplatform.portfolio.floatingrates.domain.FloatingRateRepositoryWrapper;
|
||||||
import org.mifosplatform.portfolio.fund.domain.Fund;
|
import org.mifosplatform.portfolio.fund.domain.Fund;
|
||||||
import org.mifosplatform.portfolio.fund.domain.FundRepository;
|
import org.mifosplatform.portfolio.fund.domain.FundRepository;
|
||||||
import org.mifosplatform.portfolio.fund.exception.FundNotFoundException;
|
import org.mifosplatform.portfolio.fund.exception.FundNotFoundException;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionProcessingStrategyRepository;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionProcessingStrategyRepository;
|
||||||
import org.mifosplatform.portfolio.loanaccount.exception.LoanTransactionProcessingStrategyNotFoundException;
|
import org.mifosplatform.portfolio.loanaccount.exception.LoanTransactionProcessingStrategyNotFoundException;
|
||||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.AprCalculator;
|
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.AprCalculator;
|
||||||
@@ -31,6 +34,7 @@ import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
|
|||||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository;
|
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository;
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
|
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
|
||||||
import org.mifosplatform.portfolio.loanproduct.exception.InvalidCurrencyException;
|
import org.mifosplatform.portfolio.loanproduct.exception.InvalidCurrencyException;
|
||||||
|
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductCannotBeModifiedDueToNonClosedLoansException;
|
||||||
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductDateException;
|
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductDateException;
|
||||||
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
||||||
import org.mifosplatform.portfolio.loanproduct.serialization.LoanProductDataValidator;
|
import org.mifosplatform.portfolio.loanproduct.serialization.LoanProductDataValidator;
|
||||||
@@ -57,6 +61,8 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
|
|||||||
private final ChargeRepositoryWrapper chargeRepository;
|
private final ChargeRepositoryWrapper chargeRepository;
|
||||||
private final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService;
|
private final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService;
|
||||||
private final MifosEntityAccessUtil mifosEntityAccessUtil;
|
private final MifosEntityAccessUtil mifosEntityAccessUtil;
|
||||||
|
private final FloatingRateRepositoryWrapper floatingRateRepository;
|
||||||
|
private final LoanRepository loanRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanProductWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
public LoanProductWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||||
@@ -65,7 +71,9 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
|
|||||||
final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository,
|
final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository,
|
||||||
final ChargeRepositoryWrapper chargeRepository,
|
final ChargeRepositoryWrapper chargeRepository,
|
||||||
final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService,
|
final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService,
|
||||||
final MifosEntityAccessUtil mifosEntityAccessUtil) {
|
final MifosEntityAccessUtil mifosEntityAccessUtil,
|
||||||
|
final FloatingRateRepositoryWrapper floatingRateRepository,
|
||||||
|
final LoanRepository loanRepository) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||||
this.loanProductRepository = loanProductRepository;
|
this.loanProductRepository = loanProductRepository;
|
||||||
@@ -75,6 +83,8 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
|
|||||||
this.chargeRepository = chargeRepository;
|
this.chargeRepository = chargeRepository;
|
||||||
this.accountMappingWritePlatformService = accountMappingWritePlatformService;
|
this.accountMappingWritePlatformService = accountMappingWritePlatformService;
|
||||||
this.mifosEntityAccessUtil = mifosEntityAccessUtil;
|
this.mifosEntityAccessUtil = mifosEntityAccessUtil;
|
||||||
|
this.floatingRateRepository = floatingRateRepository;
|
||||||
|
this.loanRepository = loanRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@@ -96,8 +106,13 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
|
|||||||
final String currencyCode = command.stringValueOfParameterNamed("currencyCode");
|
final String currencyCode = command.stringValueOfParameterNamed("currencyCode");
|
||||||
final List<Charge> charges = assembleListOfProductCharges(command, currencyCode);
|
final List<Charge> charges = assembleListOfProductCharges(command, currencyCode);
|
||||||
|
|
||||||
|
FloatingRate floatingRate = null;
|
||||||
|
if(command.parameterExists("floatingRatesId")){
|
||||||
|
floatingRate = this.floatingRateRepository
|
||||||
|
.findOneWithNotFoundDetection(command.longValueOfParameterNamed("floatingRatesId"));
|
||||||
|
}
|
||||||
final LoanProduct loanproduct = LoanProduct.assembleFromJson(fund, loanTransactionProcessingStrategy, charges, command,
|
final LoanProduct loanproduct = LoanProduct.assembleFromJson(fund, loanTransactionProcessingStrategy, charges, command,
|
||||||
this.aprCalculator);
|
this.aprCalculator, floatingRate);
|
||||||
loanproduct.updateLoanProductInRelatedClasses();
|
loanproduct.updateLoanProductInRelatedClasses();
|
||||||
|
|
||||||
this.loanProductRepository.save(loanproduct);
|
this.loanProductRepository.save(loanproduct);
|
||||||
@@ -154,7 +169,18 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
|
|||||||
this.fromApiJsonDeserializer.validateForUpdate(command.json(), product);
|
this.fromApiJsonDeserializer.validateForUpdate(command.json(), product);
|
||||||
validateInputDates(command);
|
validateInputDates(command);
|
||||||
|
|
||||||
final Map<String, Object> changes = product.update(command, this.aprCalculator);
|
if(anyChangeInCriticalFloatingRateLinkedParams(command, product)
|
||||||
|
&& this.loanRepository.doNonClosedLoanAccountsExistForProduct(product.getId())){
|
||||||
|
throw new LoanProductCannotBeModifiedDueToNonClosedLoansException(product.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatingRate floatingRate = null;
|
||||||
|
if(command.parameterExists("floatingRatesId")){
|
||||||
|
floatingRate = this.floatingRateRepository
|
||||||
|
.findOneWithNotFoundDetection(command.longValueOfParameterNamed("floatingRatesId"));
|
||||||
|
}
|
||||||
|
|
||||||
|
final Map<String, Object> changes = product.update(command, this.aprCalculator, floatingRate);
|
||||||
|
|
||||||
if (changes.containsKey("fundId")) {
|
if (changes.containsKey("fundId")) {
|
||||||
final Long fundId = (Long) changes.get("fundId");
|
final Long fundId = (Long) changes.get("fundId");
|
||||||
@@ -199,7 +225,15 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Charge> assembleListOfProductCharges(final JsonCommand command, final String currencyCode) {
|
private boolean anyChangeInCriticalFloatingRateLinkedParams(JsonCommand command, LoanProduct product) {
|
||||||
|
final boolean isChangeFromFloatingToFlatOrViceVersa = command.isChangeInBooleanParameterNamed("isLinkedToFloatingInterestRates", product.isLinkedToFloatingInterestRate());
|
||||||
|
final boolean isChangeInCriticalFloatingRateParams = product.getFloatingRates() != null
|
||||||
|
&& (command.isChangeInLongParameterNamed("floatingRatesId", product.getFloatingRates().getFloatingRate().getId())
|
||||||
|
|| command.isChangeInBigDecimalParameterNamed("interestRateDifferential", product.getFloatingRates().getInterestRateDifferential()));
|
||||||
|
return isChangeFromFloatingToFlatOrViceVersa || isChangeInCriticalFloatingRateParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Charge> assembleListOfProductCharges(final JsonCommand command, final String currencyCode) {
|
||||||
|
|
||||||
final List<Charge> charges = new ArrayList<>();
|
final List<Charge> charges = new ArrayList<>();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
CREATE TABLE `m_floating_rates` (
|
||||||
|
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` VARCHAR(200) NOT NULL,
|
||||||
|
`is_base_lending_rate` BIT(1) NOT NULL DEFAULT 0,
|
||||||
|
`is_active` BIT(1) NOT NULL DEFAULT 1,
|
||||||
|
`createdby_id` BIGINT(20) NOT NULL,
|
||||||
|
`created_date` DATETIME NOT NULL,
|
||||||
|
`lastmodifiedby_id` BIGINT(20) NOT NULL,
|
||||||
|
`lastmodified_date` DATETIME NOT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE INDEX `unq_name` (`name`)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE `m_floating_rates_periods` (
|
||||||
|
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`floating_rates_id` BIGINT(20) NOT NULL,
|
||||||
|
`from_date` DATETIME NOT NULL,
|
||||||
|
`interest_rate` DECIMAL(19,6) NOT NULL,
|
||||||
|
`is_differential_to_base_lending_rate` BIT(1) NOT NULL DEFAULT 0,
|
||||||
|
`is_active` BIT(1) NOT NULL DEFAULT 1,
|
||||||
|
`createdby_id` BIGINT(20) NOT NULL,
|
||||||
|
`created_date` DATETIME NOT NULL,
|
||||||
|
`lastmodifiedby_id` BIGINT(20) NOT NULL,
|
||||||
|
`lastmodified_date` DATETIME NOT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
CONSTRAINT `FK_mappings_m_floating_rates` FOREIGN KEY (`floating_rates_id`) REFERENCES `m_floating_rates` (`id`)
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE `m_product_loan`
|
||||||
|
ADD COLUMN `is_linked_to_floating_interest_rates` BIT(1) NOT NULL DEFAULT 0 AFTER `fund_id`,
|
||||||
|
MODIFY COLUMN `nominal_interest_rate_per_period` DECIMAL(19,6) NULL DEFAULT NULL,
|
||||||
|
MODIFY COLUMN `interest_period_frequency_enum` SMALLINT(5) NULL DEFAULT NULL,
|
||||||
|
MODIFY COLUMN `annual_nominal_interest_rate` DECIMAL(19,6) NULL DEFAULT NULL;
|
||||||
|
|
||||||
|
CREATE TABLE `m_product_loan_floating_rates` (
|
||||||
|
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`loan_product_id` BIGINT(20) NOT NULL,
|
||||||
|
`floating_rates_id` BIGINT(20) NOT NULL,
|
||||||
|
`interest_rate_differential` DECIMAL(19,6) NOT NULL DEFAULT 0,
|
||||||
|
`min_differential_lending_rate` DECIMAL(19,6) NOT NULL DEFAULT 0,
|
||||||
|
`default_differential_lending_rate` DECIMAL(19,6) NOT NULL DEFAULT 0,
|
||||||
|
`max_differential_lending_rate` DECIMAL(19,6) NOT NULL DEFAULT 0,
|
||||||
|
`is_floating_interest_rate_calculation_allowed` BIT(1) NOT NULL DEFAULT 0,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
CONSTRAINT `FK_mappings_m_product_loan_id` FOREIGN KEY (`loan_product_id`) REFERENCES `m_product_loan` (`id`),
|
||||||
|
CONSTRAINT `FK_mappings_m_floating_rates_id` FOREIGN KEY (`floating_rates_id`) REFERENCES `m_floating_rates` (`id`)
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE `m_loan`
|
||||||
|
ADD COLUMN `is_floating_interest_rate` BIT(1) NULL DEFAULT 0 AFTER `arrearstolerance_amount`,
|
||||||
|
ADD COLUMN `interest_rate_differential` DECIMAL(19,6) NULL DEFAULT 0 AFTER `is_floating_interest_rate`,
|
||||||
|
MODIFY COLUMN `nominal_interest_rate_per_period` DECIMAL(19,6) NULL DEFAULT NULL,
|
||||||
|
MODIFY COLUMN `interest_period_frequency_enum` SMALLINT(5) NULL DEFAULT NULL,
|
||||||
|
MODIFY COLUMN `annual_nominal_interest_rate` DECIMAL(19,6) NULL DEFAULT NULL;
|
||||||
|
|
||||||
|
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`)
|
||||||
|
VALUES ('portfolio', 'READ_FLOATINGRATE', 'FLOATINGRATE', 'READ', 0),
|
||||||
|
('portfolio', 'CREATE_FLOATINGRATE', 'FLOATINGRATE', 'CREATE', 1),
|
||||||
|
('portfolio', 'CREATE_FLOATINGRATE_CHECKER', 'FLOATINGRATE', 'CREATE_CHECKER', 0),
|
||||||
|
('portfolio', 'UPDATE_FLOATINGRATE', 'FLOATINGRATE', 'UPDATE', 1),
|
||||||
|
('portfolio', 'UPDATE_FLOATINGRATE_CHECKER', 'FLOATINGRATE', 'UPDATE_CHECKER', 0);
|
||||||
Reference in New Issue
Block a user