blob: 428acb369ec1427cef92ed3d9b76c8150107cbb6 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.interestratechart.domain;
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.INTERESTRATE_CHART_RESOURCE_NAME;
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.deleteParamName;
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.descriptionParamName;
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.idParamName;
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.amountRangeFromParamName;
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.amountRangeToParamName;
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.annualInterestRateParamName;
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.fromPeriodParamName;
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.periodTypeParamName;
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.toPeriodParamName;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants;
import org.apache.fineract.portfolio.savings.SavingsPeriodFrequencyType;
import org.joda.time.LocalDate;
import org.springframework.data.jpa.domain.AbstractPersistable;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
@Entity
@Table(name = "m_interest_rate_chart")
public class InterestRateChart extends AbstractPersistable<Long> {
@Embedded
private InterestRateChartFields chartFields;
@OneToMany(mappedBy = "interestRateChart", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private Set<InterestRateChartSlab> chartSlabs = new HashSet<>();
protected InterestRateChart() {
//
}
public static InterestRateChart createNew(InterestRateChartFields chartFields, Collection<InterestRateChartSlab> interestRateChartSlabs) {
return new InterestRateChart(chartFields, new HashSet<>(interestRateChartSlabs));
}
private InterestRateChart(InterestRateChartFields chartFields, Set<InterestRateChartSlab> interestRateChartSlabs) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(INTERESTRATE_CHART_RESOURCE_NAME);
// validate before setting the other fields
this.validateChartSlabs(baseDataValidator);
this.throwExceptionIfValidationWarningsExist(dataValidationErrors);
this.chartFields = chartFields;
this.addChartSlabs(interestRateChartSlabs);
}
public void validateChartSlabs(DataValidatorBuilder baseDataValidator) {
Collection<InterestRateChartSlab> chartSlabs = this.setOfChartSlabs();
Integer tmpPeriodType = null;
List<InterestRateChartSlab> chartSlabsList = new ArrayList<>(chartSlabs);
for (int i = 0; i < chartSlabsList.size(); i++) {
InterestRateChartSlab iSlabs = chartSlabsList.get(i);
if (tmpPeriodType == null) {
tmpPeriodType = iSlabs.slabFields().periodType();
} else if (!iSlabs.slabFields().periodType().equals(tmpPeriodType)) {
baseDataValidator.parameter(periodTypeParamName).value(iSlabs.slabFields().periodType())
.failWithCode("period.type.is.not.same", tmpPeriodType);
}
for (int j = i + 1; j < chartSlabsList.size(); j++) {
InterestRateChartSlab jSlabs = chartSlabsList.get(j);
if (iSlabs.slabFields().isPeriodOverlapping(jSlabs.slabFields())) {
baseDataValidator
.failWithCodeNoParameterAddedToErrorCode("chart.slabs.period.overlapping", iSlabs.slabFields().fromPeriod(),
iSlabs.slabFields().toPeriod(), jSlabs.slabFields().fromPeriod(), jSlabs.slabFields().toPeriod());
}
}
}
}
public void addChartSlabs(Collection<InterestRateChartSlab> interestRateChartSlabsSet) {
Set<InterestRateChartSlab> existingChartSlabs = setOfChartSlabs();
for (InterestRateChartSlab newChartSlabs : interestRateChartSlabsSet) {
newChartSlabs.setInterestRateChart(this);
existingChartSlabs.add(newChartSlabs);
}
}
public void addChartSlab(InterestRateChartSlab newChartSlab) {
newChartSlab.setInterestRateChart(this);
setOfChartSlabs().add(newChartSlab);
}
public Set<InterestRateChartSlab> setOfChartSlabs() {
if (this.chartSlabs == null) {
this.chartSlabs = new HashSet<>();
}
return this.chartSlabs;
}
public void update(JsonCommand command, final Map<String, Object> actualChanges) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(INTERESTRATE_CHART_RESOURCE_NAME);
this.update(command, actualChanges, baseDataValidator, null, null);
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void update(JsonCommand command, final Map<String, Object> actualChanges, final DataValidatorBuilder baseDataValidator,
final Set<InterestRateChart> existingCharts, String currencyCode) {
this.chartFields.update(command, actualChanges, baseDataValidator);
// interestRateChartSlabs
if (command.hasParameter(InterestRateChartApiConstants.chartSlabs)) {
updateChartSlabs(command, actualChanges, baseDataValidator, currencyCode);
}
this.validateCharts(baseDataValidator, existingCharts);
}
private void validateCharts(final DataValidatorBuilder baseDataValidator, final Set<InterestRateChart> existingCharts) {
for (InterestRateChart existingChart : existingCharts) {
if (!existingChart.equals(this)) {
if (this.chartFields.isOverlapping(existingChart.chartFields)) {
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.overlapping.from.and.end.dates",
existingChart.getFromDateAsLocalDate(), existingChart.getEndDateAsLocalDate(), this.getFromDateAsLocalDate(),
this.getEndDateAsLocalDate());
}
}
}
}
public void updateChartSlabs(JsonCommand command, final Map<String, Object> actualChanges,
final DataValidatorBuilder baseDataValidator, String currencyCode) {
final Map<String, Object> deleteChartSlabs = new HashMap<>();
final Map<String, Object> chartSlabsChanges = new HashMap<>();
final Locale locale = command.extractLocale();
if (command.hasParameter(InterestRateChartApiConstants.chartSlabs)) {
final JsonArray array = command.arrayOfParameterNamed(InterestRateChartApiConstants.chartSlabs);
if (array != null) {
for (int i = 0; i < array.size(); i++) {
final JsonObject chartSlabsElement = array.get(i).getAsJsonObject();
JsonCommand chartSlabsCommand = JsonCommand.fromExistingCommand(command, chartSlabsElement);
if (chartSlabsCommand.parameterExists(idParamName)) {
final Long chartSlabId = chartSlabsCommand.longValueOfParameterNamed(idParamName);
final InterestRateChartSlab chartSlab = this.findChartSlab(chartSlabId);
if (chartSlab == null) {
baseDataValidator.parameter(idParamName).value(chartSlabId).failWithCode("no.chart.slab.associated.with.id");
} else if (chartSlabsCommand.parameterExists(deleteParamName)) {
if (this.removeChartSlab(chartSlab)) {
deleteChartSlabs.put(idParamName, chartSlabId);
}
} else {
chartSlab.update(chartSlabsCommand, chartSlabsChanges, baseDataValidator, locale);
}
} else {
/**
* TODO: AA: Move this code to
* InterestRateChartSlabAssembler
*/
final String description = chartSlabsCommand.stringValueOfParameterNamed(descriptionParamName);
final Integer periodTypeId = chartSlabsCommand.integerValueOfParameterNamed(periodTypeParamName, locale);
final SavingsPeriodFrequencyType periodFrequencyType = SavingsPeriodFrequencyType.fromInt(periodTypeId);
final Integer fromPeriod = chartSlabsCommand.integerValueOfParameterNamed(fromPeriodParamName, locale);
final Integer toPeriod = chartSlabsCommand.integerValueOfParameterNamed(toPeriodParamName, locale);
final BigDecimal amountRangeFrom = chartSlabsCommand.bigDecimalValueOfParameterNamed(amountRangeFromParamName,
locale);
final BigDecimal amountRangeTo = chartSlabsCommand.bigDecimalValueOfParameterNamed(amountRangeToParamName, locale);
final BigDecimal annualInterestRate = chartSlabsCommand.bigDecimalValueOfParameterNamed(
annualInterestRateParamName, locale);
final InterestRateChartSlabFields slabFields = InterestRateChartSlabFields
.createNew(description, periodFrequencyType, fromPeriod, toPeriod, amountRangeFrom, amountRangeTo,
annualInterestRate, currencyCode);
final InterestRateChartSlab chartSlab = InterestRateChartSlab.createNew(slabFields, this);
chartSlab.slabFields().validateChartSlabPlatformRules(chartSlabsCommand, baseDataValidator, locale);
chartSlab.updateIncentives(chartSlabsCommand, actualChanges, baseDataValidator, chartSlab, locale);
this.addChartSlab(chartSlab);
}
}
}
}
// add chart slab changes to actual changes list.
if (!chartSlabsChanges.isEmpty()) {
actualChanges.put(InterestRateChartApiConstants.chartSlabs, chartSlabsChanges);
}
// add deleted chart Slabs to actual changes
if (!deleteChartSlabs.isEmpty()) {
actualChanges.put("deletedChartSlabs", deleteChartSlabs);
}
this.validateChartSlabs(baseDataValidator);
}
public InterestRateChartSlab findChartSlab(Long chartSlabId) {
final Set<InterestRateChartSlab> chartSlabs = setOfChartSlabs();
for (InterestRateChartSlab interestRateChartSlab : chartSlabs) {
if (interestRateChartSlab.getId().equals(chartSlabId)) { return interestRateChartSlab; }
}
return null;
}
private boolean removeChartSlab(InterestRateChartSlab chartSlab) {
final Set<InterestRateChartSlab> chartSlabs = setOfChartSlabs();
return chartSlabs.remove(chartSlab);
}
public LocalDate getFromDateAsLocalDate() {
return this.chartFields.getFromDateAsLocalDate();
}
public LocalDate getEndDateAsLocalDate() {
return this.chartFields.getEndDateAsLocalDate();
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
public InterestRateChartFields chartFields() {
return this.chartFields;
}
public boolean isApplicableChartFor(final LocalDate target) {
return this.chartFields.isApplicableChartFor(target);
}
}