blob: b578443439baff8ba1bebe739410dde56d1c2afe [file] [log] [blame]
/*
* Copyright 2017 Kuelap, Inc.
*
* Licensed 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 io.mifos.individuallending.internal.service;
import io.mifos.portfolio.api.v1.domain.ChargeDefinition;
import io.mifos.portfolio.service.internal.repository.BalanceSegmentEntity;
import io.mifos.portfolio.service.internal.repository.BalanceSegmentRepository;
import io.mifos.portfolio.service.internal.service.ChargeDefinitionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Nonnull;
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author Myrle Krantz
*/
@Service
public class ScheduledChargesService {
private final ChargeDefinitionService chargeDefinitionService;
private final BalanceSegmentRepository balanceSegmentRepository;
@Autowired
public ScheduledChargesService(
final ChargeDefinitionService chargeDefinitionService,
final BalanceSegmentRepository balanceSegmentRepository) {
this.chargeDefinitionService = chargeDefinitionService;
this.balanceSegmentRepository = balanceSegmentRepository;
}
List<ScheduledCharge> getScheduledCharges(
final String productIdentifier,
final @Nonnull List<ScheduledAction> scheduledActions) {
final Map<String, List<ChargeDefinition>> chargeDefinitionsMappedByChargeAction
= chargeDefinitionService.getChargeDefinitionsMappedByChargeAction(productIdentifier);
final Map<String, List<ChargeDefinition>> chargeDefinitionsMappedByAccrueAction
= chargeDefinitionService.getChargeDefinitionsMappedByAccrueAction(productIdentifier);
return getScheduledCharges(
productIdentifier,
scheduledActions,
chargeDefinitionsMappedByChargeAction,
chargeDefinitionsMappedByAccrueAction);
}
private List<ScheduledCharge> getScheduledCharges(
final String productIdentifier,
final List<ScheduledAction> scheduledActions,
final Map<String, List<ChargeDefinition>> chargeDefinitionsMappedByChargeAction,
final Map<String, List<ChargeDefinition>> chargeDefinitionsMappedByAccrueAction) {
return scheduledActions.stream()
.flatMap(scheduledAction ->
getChargeDefinitionStream(
chargeDefinitionsMappedByChargeAction,
chargeDefinitionsMappedByAccrueAction,
scheduledAction)
.map(chargeDefinition -> new ScheduledCharge(
scheduledAction,
chargeDefinition,
findChargeRange(productIdentifier, chargeDefinition))))
.collect(Collectors.toList());
}
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private static class Segment {
final String identifier;
final BigDecimal lowerBound;
final Optional<BigDecimal> upperBound;
private Segment(final String segmentIdentifier,
final BigDecimal lowerBound,
final Optional<BigDecimal> upperBound) {
this.identifier = segmentIdentifier;
this.lowerBound = lowerBound;
this.upperBound = upperBound;
}
BigDecimal getLowerBound() {
return lowerBound;
}
Optional<BigDecimal> getUpperBound() {
return upperBound;
}
@Override
public String toString() {
return "Segment{" +
"identifier='" + identifier + '\'' +
", lowerBound=" + lowerBound +
", upperBound=" + upperBound +
'}';
}
}
Optional<ChargeRange> findChargeRange(final String productIdentifier, final ChargeDefinition chargeDefinition) {
if ((chargeDefinition.getForSegmentSet() == null) ||
(chargeDefinition.getFromSegment() == null) ||
(chargeDefinition.getToSegment() == null))
return Optional.empty();
final List<BalanceSegmentEntity> segmentSet = balanceSegmentRepository.findByProductIdentifierAndSegmentSetIdentifier(productIdentifier, chargeDefinition.getForSegmentSet())
.sorted(Comparator.comparing(BalanceSegmentEntity::getLowerBound))
.collect(Collectors.toList());
final Map<String, Segment> segments = Stream.iterate(0, i -> i + 1).limit(segmentSet.size())
.map(i -> new Segment(
segmentSet.get(i).getSegmentIdentifier(),
segmentSet.get(i).getLowerBound(),
Optional.ofNullable(i + 1 < segmentSet.size() ?
segmentSet.get(i + 1).getLowerBound() :
null)
))
.collect(Collectors.toMap(x -> x.identifier, x -> x));
final Optional<Segment> fromSegment = Optional.ofNullable(segments.get(chargeDefinition.getFromSegment()));
final Optional<Segment> toSegment = Optional.ofNullable(segments.get(chargeDefinition.getToSegment()));
if (!fromSegment.isPresent() || !toSegment.isPresent())
return Optional.empty();
return Optional.of(new ChargeRange(fromSegment.get().getLowerBound(), toSegment.get().getUpperBound()));
}
private static Stream<ChargeDefinition> getChargeDefinitionStream(
final Map<String, List<ChargeDefinition>> chargeDefinitionsMappedByChargeAction,
final Map<String, List<ChargeDefinition>> chargeDefinitionsMappedByAccrueAction,
final ScheduledAction scheduledAction) {
final List<ChargeDefinition> chargeMappingList = chargeDefinitionsMappedByChargeAction
.get(scheduledAction.action.name());
Stream<ChargeDefinition> chargeMapping = chargeMappingList == null ? Stream.empty() : chargeMappingList.stream();
if (chargeMapping == null)
chargeMapping = Stream.empty();
final List<ChargeDefinition> accrueMappingList = chargeDefinitionsMappedByAccrueAction
.get(scheduledAction.action.name());
Stream<ChargeDefinition> accrueMapping = accrueMappingList == null ? Stream.empty() : accrueMappingList.stream();
if (accrueMapping == null)
accrueMapping = Stream.empty();
return Stream.concat(
accrueMapping.sorted(ScheduledChargeComparator::proportionalityApplicationOrder),
chargeMapping.sorted(ScheduledChargeComparator::proportionalityApplicationOrder));
}
}