- Calculations can be started now with any validity period and property set.

- added preflight check for validity period, property set and all route sections
This commit is contained in:
Jan 2025-10-18 19:52:10 +02:00
parent dac371b481
commit 78bd0ad6d6
15 changed files with 318 additions and 131 deletions

View file

@ -54,10 +54,16 @@ public class CountryPropertyRepository {
throw new DatabaseException("Could not update property value for country " + countryId + " and property type " + mappingId); throw new DatabaseException("Could not update property value for country " + countryId + " and property type " + mappingId);
} }
@Transactional
public Optional<PropertyDTO> getByMappingIdAndCountryId(CountryPropertyMappingId mappingId, Integer countryId) { public Optional<PropertyDTO> getByMappingIdAndCountryId(CountryPropertyMappingId mappingId, Integer countryId) {
return getByMappingIdAndCountryId(mappingId.name(), countryId); return getByMappingIdAndCountryId(mappingId.name(), countryId);
} }
@Transactional
public Optional<PropertyDTO> getByMappingIdAndCountryId(CountryPropertyMappingId mappingId, Integer setId, Integer countryId) {
return getByMappingIdAndCountryId(mappingId.name(), setId, countryId);
}
public Optional<PropertyDTO> getByMappingIdAndCountryId(String mappingId, Integer countryId) { public Optional<PropertyDTO> getByMappingIdAndCountryId(String mappingId, Integer countryId) {
String query = """ String query = """
SELECT type.name as name, SELECT type.name as name,
@ -74,14 +80,14 @@ public class CountryPropertyRepository {
FROM country_property_type AS type FROM country_property_type AS type
LEFT JOIN ( LEFT JOIN (
SELECT cp.property_value, cp.country_property_type_id SELECT cp.property_value, cp.country_property_type_id
FROM country_property cp FROM country_property cp
JOIN property_set ps ON ps.id = cp.property_set_id JOIN property_set ps ON ps.id = cp.property_set_id
WHERE cp.country_id = ? AND ps.state = 'DRAFT' WHERE cp.country_id = ? AND ps.state = 'DRAFT'
) AS draft ON draft.country_property_type_id = type.id ) AS draft ON draft.country_property_type_id = type.id
LEFT JOIN ( LEFT JOIN (
SELECT cp.property_value, cp.country_property_type_id SELECT cp.property_value, cp.country_property_type_id
FROM country_property cp FROM country_property cp
JOIN property_set ps ON ps.id = cp.property_set_id JOIN property_set ps ON ps.id = cp.property_set_id
WHERE cp.country_id = ? AND ps.state = 'VALID' WHERE cp.country_id = ? AND ps.state = 'VALID'
) AS valid ON valid.country_property_type_id = type.id ) AS valid ON valid.country_property_type_id = type.id
WHERE type.external_mapping_id = ? WHERE type.external_mapping_id = ?
@ -95,6 +101,36 @@ public class CountryPropertyRepository {
return Optional.of(property.getFirst()); return Optional.of(property.getFirst());
} }
public Optional<PropertyDTO> getByMappingIdAndCountryId(String mappingId, Integer setId, Integer countryId) {
String query = """
SELECT type.name as name,
type.data_type as dataType,
type.external_mapping_id as externalMappingId,
type.validation_rule as validationRule,
type.is_required as is_required,
type.description as description,
type.property_group as propertyGroup,
type.sequence_number as sequenceNumber,
valid.property_value as validValue
FROM country_property_type AS type
LEFT JOIN (
SELECT cp.property_value, cp.country_property_type_id
FROM country_property cp
JOIN property_set ps ON ps.id = cp.property_set_id
WHERE cp.country_id = ? AND ps.id = ?
) AS valid ON valid.country_property_type_id = type.id
WHERE type.external_mapping_id = ?
""";
var property = jdbcTemplate.query(query, new PropertyMapper(), countryId, countryId, setId, mappingId);
if (property.isEmpty())
return Optional.empty();
return Optional.of(property.getFirst());
}
private Integer getTypeIdByMappingId(String mappingId) { private Integer getTypeIdByMappingId(String mappingId) {
String query = "SELECT id FROM country_property_type WHERE external_mapping_id = ?"; String query = "SELECT id FROM country_property_type WHERE external_mapping_id = ?";
return jdbcTemplate.queryForObject(query, Integer.class, mappingId); return jdbcTemplate.queryForObject(query, Integer.class, mappingId);

View file

@ -146,6 +146,25 @@ public class PropertyRepository {
} }
@Transactional
public Optional<PropertyDTO> getPropertyByMappingId(SystemPropertyMappingId mappingId, Integer setId) {
String query = """
SELECT type.name as name, type.data_type as dataType, type.external_mapping_id as externalMappingId, type.validation_rule as validationRule,
type.description as description, type.property_group as propertyGroup, type.sequence_number as sequenceNumber,
property.property_value as draftValue, property.property_value as validValue
FROM system_property_type AS type
LEFT JOIN system_property AS property ON property.system_property_type_id = type.id
LEFT JOIN property_set AS propertySet ON propertySet.id = property.property_set_id
WHERE propertySet.id = ? AND type.external_mapping_id = ?
""";
var property = jdbcTemplate.query(query, new PropertyMapper(), setId, mappingId.name());
if (property.isEmpty()) return Optional.empty();
else return Optional.of(property.getFirst());
}
/** /**
* Fills the draft property set with values from a valid property set. * Fills the draft property set with values from a valid property set.
* This method ensures that the draft set contains all properties with their latest valid values. * This method ensures that the draft set contains all properties with their latest valid values.

View file

@ -171,12 +171,39 @@ public class ContainerRateRepository {
return jdbcTemplate.query(query, new ContainerRateMapper(true), ValidityPeriodState.VALID.name(), mainRun.getToNodeId(), TransportType.POST_RUN.name()); return jdbcTemplate.query(query, new ContainerRateMapper(true), ValidityPeriodState.VALID.name(), mainRun.getToNodeId(), TransportType.POST_RUN.name());
} }
public Optional<ContainerRate> findRoute(Integer fromNodeId, Integer toNodeId, TransportType type) {
@Transactional
public Optional<ContainerRate> findRoute(Integer fromNodeId, Integer toNodeId, Integer periodId, TransportType type) {
String query = """ String query = """
SELECT * FROM container_rate WHERE from_node_id = ? AND to_node_id = ? AND container_rate_type = ? SELECT * FROM container_rate WHERE from_node_id = ? AND to_node_id = ? AND container_rate_type = ? AND validity_period_id = ?
"""; """;
var route = jdbcTemplate.query(query, new ContainerRateMapper(), fromNodeId, toNodeId, type.name()); var route = jdbcTemplate.query(query, new ContainerRateMapper(), fromNodeId, toNodeId, type.name(), periodId);
if(route.isEmpty())
return Optional.empty();
return Optional.of(route.getFirst());
}
@Transactional
public Optional<ContainerRate> findRoute(Integer fromNodeId, Integer toNodeId, TransportType type) {
String query = """
SELECT cr.id AS id,
cr.validity_period_id AS validity_period_id,
cr.container_rate_type AS container_rate_type,
cr.from_node_id AS from_node_id,
cr.to_node_id AS to_node_id,
cr.rate_feu AS rate_feu,
cr.rate_teu AS rate_teu,
cr.rate_hc AS rate_hc,
cr.lead_time AS lead_time
FROM container_rate AS cr LEFT JOIN validity_period AS vp ON cr.validity_period_id = vp.id
WHERE cr.from_node_id = ? AND cr.to_node_id = ? AND cr.container_rate_type = ? AND vp.state = ?
""";
var route = jdbcTemplate.query(query, new ContainerRateMapper(), fromNodeId, toNodeId, type.name(), ValidityPeriodState.VALID.name());
if(route.isEmpty()) if(route.isEmpty())
return Optional.empty(); return Optional.empty();

View file

@ -1,6 +1,7 @@
package de.avatic.lcc.repositories.rates; package de.avatic.lcc.repositories.rates;
import de.avatic.lcc.model.rates.MatrixRate; import de.avatic.lcc.model.rates.MatrixRate;
import de.avatic.lcc.model.rates.ValidityPeriodState;
import de.avatic.lcc.repositories.pagination.SearchQueryPagination; import de.avatic.lcc.repositories.pagination.SearchQueryPagination;
import de.avatic.lcc.repositories.pagination.SearchQueryResult; import de.avatic.lcc.repositories.pagination.SearchQueryResult;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
@ -125,8 +126,35 @@ public class MatrixRateRepository {
@Transactional @Transactional
public Optional<MatrixRate> getByCountryIds(Integer fromCountryId, Integer toCountryId) { public Optional<MatrixRate> getByCountryIds(Integer fromCountryId, Integer toCountryId) {
String query = "SELECT * FROM country_matrix_rate WHERE from_country_id = ? AND to_country_id = ?";
var rates = jdbcTemplate.query(query, new MatrixRateMapper(), fromCountryId, toCountryId); String query = """
SELECT cmr.id AS id,
cmr.rate AS rate,
cmr.from_country_id AS from_country_id,
cmr.to_country_id AS to_country_id,
cmr.validity_period_id AS validity_period_id
FROM country_matrix_rate AS cmr LEFT JOIN validity_period AS vp ON vp.id = cmr.validity_period_id
WHERE cmr.from_country_id = ? AND cmr.to_country_id = ? AND vp.state = ?
""";
var rates = jdbcTemplate.query(query, new MatrixRateMapper(), fromCountryId, toCountryId, ValidityPeriodState.VALID.name());
if(rates.isEmpty())
return Optional.empty();
else
return Optional.of(rates.getFirst());
}
@Transactional
public Optional<MatrixRate> getByCountryIds(Integer fromCountryId, Integer toCountryId, Integer periodId) {
String query = """
SELECT *
FROM country_matrix_rate
WHERE from_country_id = ? AND to_country_id = ? AND validity_period_id = ?
""";
var rates = jdbcTemplate.query(query, new MatrixRateMapper(), fromCountryId, toCountryId, periodId);
if(rates.isEmpty()) if(rates.isEmpty())
return Optional.empty(); return Optional.empty();

View file

@ -100,14 +100,13 @@ public class PremisesService {
public void startCalculation(List<Integer> premises) { public void startCalculation(List<Integer> premises) {
var userId = authorizationService.getUserId(); var userId = authorizationService.getUserId();
premiseRepository.checkOwner(premises, userId);
// todo check if user is allowed to schedule this
premises.forEach(preCalculationCheckService::doPrecheck);
var validSetId = propertySetRepository.getValidSetId(); var validSetId = propertySetRepository.getValidSetId();
var validPeriodId = validityPeriodRepository.getValidPeriodId().orElseThrow(() -> new InternalErrorException("no valid period found that is VALID")); var validPeriodId = validityPeriodRepository.getValidPeriodId().orElseThrow(() -> new InternalErrorException("no valid period found that is VALID"));
premises.forEach(premiseId -> preCalculationCheckService.doPrecheck(premiseId, validSetId, validPeriodId));
var calculationIds = new ArrayList<Integer>(); var calculationIds = new ArrayList<Integer>();
premises.forEach(p -> { premises.forEach(p -> {

View file

@ -102,7 +102,7 @@ public class CalculationExecutionService {
BigDecimal fcaFee; BigDecimal fcaFee;
if (premise.getFcaEnabled()) { if (premise.getFcaEnabled()) {
var fcaProperty = propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.FCA_FEE).orElseThrow(); var fcaProperty = propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.FCA_FEE, calculation.getPropertySetId()).orElseThrow();
var fcaShare = Double.parseDouble(fcaProperty.getCurrentValue()); var fcaShare = Double.parseDouble(fcaProperty.getCurrentValue());
fcaFee = BigDecimal.valueOf(fcaShare).multiply(materialCost); fcaFee = BigDecimal.valueOf(fcaShare).multiply(materialCost);
} else { } else {
@ -110,19 +110,19 @@ public class CalculationExecutionService {
} }
List<Destination> destinations = destinationRepository.getByPremiseId(premise.getId()); List<Destination> destinations = destinationRepository.getByPremiseId(premise.getId());
return destinations.stream().map(destination -> doDestinationCalculation(destination, premise, materialCost, fcaFee)).toList(); return destinations.stream().map(destination -> doDestinationCalculation(calculation.getPropertySetId(), calculation.getValidityPeriodId(), destination, premise, materialCost, fcaFee)).toList();
} }
throw new IllegalStateException("Calculation job is not scheduled"); throw new IllegalStateException("Calculation job is not scheduled");
} }
private DestinationInfo doDestinationCalculation(Destination destination, Premise premise, BigDecimal materialCost, BigDecimal fcaFee) { private DestinationInfo doDestinationCalculation(Integer setId, Integer periodId, Destination destination, Premise premise, BigDecimal materialCost, BigDecimal fcaFee) {
InventoryCostResult inventoryCost; InventoryCostResult inventoryCost;
HandlingResult handlingCost; HandlingResult handlingCost;
CustomResult customCost; CustomResult customCost;
List<SectionInfo> sections; List<SectionInfo> sections;
AirfreightResult airfreightCost = airfreightCalculationService.doCalculation(premise, destination); AirfreightResult airfreightCost = airfreightCalculationService.doCalculation(setId, periodId, premise, destination);
ContainerType usedContainerType = null; ContainerType usedContainerType = null;
CalculationJobDestination destinationCalculationJob = new CalculationJobDestination(); CalculationJobDestination destinationCalculationJob = new CalculationJobDestination();
@ -130,12 +130,12 @@ public class CalculationExecutionService {
BigDecimal leadTime = null; BigDecimal leadTime = null;
if (destination.getD2d()) { if (destination.getD2d()) {
var containerCalculation = containerCalculationService.doCalculation(premiseToHuService.createHuFromPremise(premise), ContainerType.FEU); var containerCalculation = containerCalculationService.doCalculation(setId, premiseToHuService.createHuFromPremise(premise), ContainerType.FEU);
sections = List.of(new SectionInfo(null, routeSectionCostCalculationService.doD2dCalculation(premise, destination, containerCalculation), containerCalculation)); sections = List.of(new SectionInfo(null, routeSectionCostCalculationService.doD2dCalculation(setId, periodId, premise, destination, containerCalculation), containerCalculation));
leadTime = BigDecimal.valueOf(destination.getLeadTimeD2d()); leadTime = BigDecimal.valueOf(destination.getLeadTimeD2d());
usedContainerType = ContainerType.FEU; usedContainerType = ContainerType.FEU;
} else { } else {
var bestContainerTypeResult = getSectionsFromBestContainerType(destination, premise); var bestContainerTypeResult = getSectionsFromBestContainerType(setId, periodId, destination, premise);
sections = bestContainerTypeResult.sections; sections = bestContainerTypeResult.sections;
usedContainerType = bestContainerTypeResult.containerType; usedContainerType = bestContainerTypeResult.containerType;
hasMainRun = sections.stream().anyMatch(s -> s.section().getMainRun()); hasMainRun = sections.stream().anyMatch(s -> s.section().getMainRun());
@ -156,9 +156,9 @@ public class CalculationExecutionService {
if(destination.getD2d()) if(destination.getD2d())
destinationCalculationJob.setRateD2D(destination.getRateD2d()); destinationCalculationJob.setRateD2D(destination.getRateD2d());
customCost = customCostCalculationService.doCalculation(premise, destination, sections); customCost = customCostCalculationService.doCalculation(setId, premise, destination, sections);
handlingCost = handlingCostCalculationService.doCalculation(premise, destination, hasMainRun); handlingCost = handlingCostCalculationService.doCalculation(setId, premise, destination, hasMainRun);
inventoryCost = inventoryCostCalculationService.doCalculation(premise, destination, leadTime); inventoryCost = inventoryCostCalculationService.doCalculation(setId, premise, destination, leadTime);
destinationCalculationJob.setContainerType(usedContainerType); destinationCalculationJob.setContainerType(usedContainerType);
@ -197,7 +197,7 @@ public class CalculationExecutionService {
destinationCalculationJob.setHuCount(sections.getFirst().containerResult().getHuUnitCount()); destinationCalculationJob.setHuCount(sections.getFirst().containerResult().getHuUnitCount());
destinationCalculationJob.setAnnualAmount(BigDecimal.valueOf(destination.getAnnualAmount())); destinationCalculationJob.setAnnualAmount(BigDecimal.valueOf(destination.getAnnualAmount()));
destinationCalculationJob.setShippingFrequency(shippingFrequencyCalculationService.doCalculation(destination.getAnnualAmount())); destinationCalculationJob.setShippingFrequency(shippingFrequencyCalculationService.doCalculation(setId, destination.getAnnualAmount()));
var commonCost = destinationCalculationJob.getAnnualHandlingCost() var commonCost = destinationCalculationJob.getAnnualHandlingCost()
.add(destinationCalculationJob.getAnnualDisposalCost()) .add(destinationCalculationJob.getAnnualDisposalCost())
@ -223,7 +223,7 @@ public class CalculationExecutionService {
return new DestinationInfo(destination, destinationCalculationJob, sections); return new DestinationInfo(destination, destinationCalculationJob, sections);
} }
private BestContainerTypeResult getSectionsFromBestContainerType(Destination destination, Premise premise) { private BestContainerTypeResult getSectionsFromBestContainerType(Integer setId, Integer periodId, Destination destination, Premise premise) {
PackagingDimension hu = premiseToHuService.createHuFromPremise(premise); PackagingDimension hu = premiseToHuService.createHuFromPremise(premise);
var route = routeRepository.getSelectedByDestinationId(destination.getId()).orElseThrow(); var route = routeRepository.getSelectedByDestinationId(destination.getId()).orElseThrow();
@ -234,7 +234,7 @@ public class CalculationExecutionService {
// Get container calculation // Get container calculation
for (var containerType : ContainerType.values()) { for (var containerType : ContainerType.values()) {
containerCalculation.put(containerType, containerCalculationService.doCalculation(hu, containerType)); containerCalculation.put(containerType, containerCalculationService.doCalculation(setId, hu, containerType));
} }
for (var containerType : ContainerType.values()) { for (var containerType : ContainerType.values()) {
@ -244,7 +244,7 @@ public class CalculationExecutionService {
for (var section : routeSections) { for (var section : routeSections) {
var container = RateType.MATRIX == section.getRateType() ? containerCalculation.get(ContainerType.TRUCK) : containerCalculation.get(containerType); var container = RateType.MATRIX == section.getRateType() ? containerCalculation.get(ContainerType.TRUCK) : containerCalculation.get(containerType);
sectionInfo.add(new SectionInfo(section, routeSectionCostCalculationService.doCalculation(premise, destination, section, container), containerCalculation.get(containerType))); sectionInfo.add(new SectionInfo(section, routeSectionCostCalculationService.doCalculation(setId, periodId, premise, destination, section, container), containerCalculation.get(containerType)));
} }
sectionInfos.put(containerType, sectionInfo); sectionInfos.put(containerType, sectionInfo);

View file

@ -28,21 +28,21 @@ public class AirfreightCalculationService {
this.countryPropertyRepository = countryPropertyRepository; this.countryPropertyRepository = countryPropertyRepository;
} }
public AirfreightResult doCalculation(Premise premise, Destination destination) { public AirfreightResult doCalculation(Integer setId, Integer periodId, Premise premise, Destination destination) {
var maxAirfreightShare = Double.parseDouble(countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.AIR_SHARE, premise.getCountryId()).orElseThrow().getCurrentValue()); var maxAirfreightShare = Double.parseDouble(countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.AIR_SHARE, setId, premise.getCountryId()).orElseThrow().getCurrentValue());
var overseaShare = premise.getOverseaShare().doubleValue(); var overseaShare = premise.getOverseaShare().doubleValue();
var airfreightShare = getAirfreightShare(maxAirfreightShare, overseaShare); var airfreightShare = getAirfreightShare(maxAirfreightShare, overseaShare);
var hu = premiseToHuService.createHuFromPremise(premise); var hu = premiseToHuService.createHuFromPremise(premise);
var preCarriage = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.AIR_PRECARRIAGE).orElseThrow().getCurrentValue())); var preCarriage = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.AIR_PRECARRIAGE, setId).orElseThrow().getCurrentValue()));
var mainCarriage = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.AIR_MAINCARRIAGE).orElseThrow().getCurrentValue())); var mainCarriage = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.AIR_MAINCARRIAGE, setId).orElseThrow().getCurrentValue()));
var postCarriage = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.AIR_ONCARRIAGE).orElseThrow().getCurrentValue())); var postCarriage = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.AIR_ONCARRIAGE, setId).orElseThrow().getCurrentValue()));
var terminalFee = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.AIR_TERMINAL_FEE).orElseThrow().getCurrentValue())); var terminalFee = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.AIR_TERMINAL_FEE, setId).orElseThrow().getCurrentValue()));
var preCarriageFee = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.AIR_HANDLING).orElseThrow().getCurrentValue())); var preCarriageFee = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.AIR_HANDLING, setId).orElseThrow().getCurrentValue()));
var customsClearanceFee = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.AIR_CUSTOM_FEE).orElseThrow().getCurrentValue())); var customsClearanceFee = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.AIR_CUSTOM_FEE, setId).orElseThrow().getCurrentValue()));
var handOverFee = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.AIR_HANDOVER_FEE).orElseThrow().getCurrentValue())); var handOverFee = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.AIR_HANDOVER_FEE, setId).orElseThrow().getCurrentValue()));
var result = new AirfreightResult(); var result = new AirfreightResult();
@ -69,11 +69,11 @@ public class AirfreightCalculationService {
} }
private double getDimensionInCm(Number dimension, DimensionUnit unit) { private double getDimensionInCm(Number dimension, DimensionUnit unit) {
return DimensionUnit.CM.convertFromMM(dimension).doubleValue(); return DimensionUnit.CM.convertFromMM(dimension);
} }
private double getWeightInKg(PackagingDimension hu) { private double getWeightInKg(PackagingDimension hu) {
return WeightUnit.KG.convertFromG(hu.getWeight()).doubleValue(); return WeightUnit.KG.convertFromG(hu.getWeight());
} }
private double getAirfreightShare(double maxAirfreightShare, double overseaShare) { private double getAirfreightShare(double maxAirfreightShare, double overseaShare) {

View file

@ -25,10 +25,10 @@ public class ChangeRiskFactorCalculationService {
this.nodeRepository = nodeRepository; this.nodeRepository = nodeRepository;
} }
public ChangeRiskFactorCalculationResult getChanceRiskFactors() { public ChangeRiskFactorCalculationResult getChanceRiskFactors(Integer setId, Integer periodId) {
var rate = findRate(); var rate = findRate(setId, periodId);
var riskValue = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.RISK_REF).orElseThrow().getCurrentValue())); var riskValue = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.RISK_REF, setId).orElseThrow().getCurrentValue()));
var chanceValue = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.CHANCE_REF).orElseThrow().getCurrentValue())); var chanceValue = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.CHANCE_REF, setId).orElseThrow().getCurrentValue()));
var result = new ChangeRiskFactorCalculationResult(); var result = new ChangeRiskFactorCalculationResult();
result.setChanceFactor(chanceValue.divide(rate.getRateFeu(), 2, RoundingMode.HALF_UP)); result.setChanceFactor(chanceValue.divide(rate.getRateFeu(), 2, RoundingMode.HALF_UP));
@ -36,14 +36,14 @@ public class ChangeRiskFactorCalculationService {
return result; return result;
} }
private ContainerRate findRate() { private ContainerRate findRate(Integer setId, Integer periodId) {
var startReference = propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.START_REF).orElseThrow().getCurrentValue(); var startReference = propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.START_REF, setId).orElseThrow().getCurrentValue();
var endReference = propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.END_REF).orElseThrow().getCurrentValue(); var endReference = propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.END_REF, setId).orElseThrow().getCurrentValue();
var startNode = nodeRepository.getByExternalMappingId(startReference).orElseThrow(); var startNode = nodeRepository.getByExternalMappingId(startReference).orElseThrow();
var endNode = nodeRepository.getByExternalMappingId(endReference).orElseThrow(); var endNode = nodeRepository.getByExternalMappingId(endReference).orElseThrow();
return containerRateRepository.findRoute(startNode.getId(), endNode.getId(), TransportType.SEA).orElseThrow(); return containerRateRepository.findRoute(startNode.getId(), endNode.getId(), periodId, TransportType.SEA).orElseThrow();
} }
} }

View file

@ -49,10 +49,10 @@ public class ContainerCalculationService {
* @param containerType The type of container to be loaded * @param containerType The type of container to be loaded
* @return ContainerCalculationResult containing loading pattern and capacity information * @return ContainerCalculationResult containing loading pattern and capacity information
*/ */
public ContainerCalculationResult doCalculation(PackagingDimension hu, ContainerType containerType) { public ContainerCalculationResult doCalculation(Integer setId, PackagingDimension hu, ContainerType containerType) {
var weightInKg = BigDecimal.valueOf(WeightUnit.KG.convertFromG(hu.getWeight())); var weightInKg = BigDecimal.valueOf(WeightUnit.KG.convertFromG(hu.getWeight()));
var maxContainerLoad = BigDecimal.valueOf(getMaxContainerLoad(containerType)); var maxContainerLoad = BigDecimal.valueOf(getMaxContainerLoad(containerType, setId));
var maxUnitByWeight = maxContainerLoad.divide(weightInKg, 0, RoundingMode.HALF_UP).intValueExact(); var maxUnitByWeight = maxContainerLoad.divide(weightInKg, 0, RoundingMode.HALF_UP).intValueExact();
var dimensions = hu.withTolerance(DIMENSION_TOLERANCE); var dimensions = hu.withTolerance(DIMENSION_TOLERANCE);
@ -144,7 +144,7 @@ public class ContainerCalculationService {
* @throws IllegalArgumentException if container type is not supported * @throws IllegalArgumentException if container type is not supported
* @throws IllegalStateException if required property is missing * @throws IllegalStateException if required property is missing
*/ */
private int getMaxContainerLoad(ContainerType containerType) { private int getMaxContainerLoad(ContainerType containerType, Integer setId) {
Map<ContainerType, SystemPropertyMappingId> mappings = Map.of( Map<ContainerType, SystemPropertyMappingId> mappings = Map.of(
ContainerType.FEU, SystemPropertyMappingId.FEU_LOAD, ContainerType.FEU, SystemPropertyMappingId.FEU_LOAD,
ContainerType.TRUCK, SystemPropertyMappingId.TRUCK_LOAD, ContainerType.TRUCK, SystemPropertyMappingId.TRUCK_LOAD,
@ -157,7 +157,7 @@ public class ContainerCalculationService {
throw new IllegalArgumentException("Unsupported container type: " + containerType); throw new IllegalArgumentException("Unsupported container type: " + containerType);
} }
var value = propertyRepository.getPropertyByMappingId(mappingId) var value = propertyRepository.getPropertyByMappingId(mappingId, setId)
.orElseThrow(() -> new IllegalStateException("Missing property: " + mappingId)) .orElseThrow(() -> new IllegalStateException("Missing property: " + mappingId))
.getCurrentValue(); .getCurrentValue();

View file

@ -48,14 +48,14 @@ public class CustomCostCalculationService {
} }
} }
public CustomResult doCalculation(Premise premise, Destination destination, List<SectionInfo> sections) { public CustomResult doCalculation(Integer setId, Premise premise, Destination destination, List<SectionInfo> sections) {
var destUnion = countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.UNION, destination.getCountryId()).orElseThrow(); var destUnion = countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.UNION, setId, destination.getCountryId()).orElseThrow();
var sourceUnion = countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.UNION, premise.getCountryId()).orElseThrow(); var sourceUnion = countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.UNION, setId, premise.getCountryId()).orElseThrow();
if (CustomUnionType.EU.name().equals(destUnion.getCurrentValue()) && (sourceUnion.getCurrentValue() == null || CustomUnionType.NONE.name().equals(sourceUnion.getCurrentValue()))) { if (CustomUnionType.EU.name().equals(destUnion.getCurrentValue()) && (sourceUnion.getCurrentValue() == null || CustomUnionType.NONE.name().equals(sourceUnion.getCurrentValue()))) {
var relevantSections = getCustomRelevantRouteSections(sections); var relevantSections = getCustomRelevantRouteSections(setId, sections);
var transportationCost = relevantSections.stream().map(s -> s.result().getAnnualCost()).reduce(BigDecimal.ZERO, BigDecimal::add); var transportationCost = relevantSections.stream().map(s -> s.result().getAnnualCost()).reduce(BigDecimal.ZERO, BigDecimal::add);
var transportationChanceCost = relevantSections.stream().map(s -> s.result().getAnnualChanceCost()).reduce(BigDecimal.ZERO, BigDecimal::add); var transportationChanceCost = relevantSections.stream().map(s -> s.result().getAnnualChanceCost()).reduce(BigDecimal.ZERO, BigDecimal::add);
@ -64,15 +64,15 @@ public class CustomCostCalculationService {
double huAnnualAmount = BigDecimal.valueOf(destination.getAnnualAmount()).divide(BigDecimal.valueOf(relevantSections.getFirst().containerResult().getHuUnitCount()),2, RoundingMode.HALF_UP).doubleValue(); double huAnnualAmount = BigDecimal.valueOf(destination.getAnnualAmount()).divide(BigDecimal.valueOf(relevantSections.getFirst().containerResult().getHuUnitCount()),2, RoundingMode.HALF_UP).doubleValue();
return getCustomCalculationResult(premise, destination, getContainerShare(premise, relevantSections.getFirst().containerResult()), huAnnualAmount, transportationCost, transportationChanceCost, transportationRiskCost); return getCustomCalculationResult(setId, premise, destination, getContainerShare(premise, relevantSections.getFirst().containerResult()), huAnnualAmount, transportationCost, transportationChanceCost, transportationRiskCost);
} }
return CustomResult.EMPTY; return CustomResult.EMPTY;
} }
private CustomResult getCustomCalculationResult(Premise premise, Destination destination, BigDecimal containerShare, double huAnnualAmount, BigDecimal transportationCost, BigDecimal transportationChanceCost, BigDecimal transportationRiskCost) { private CustomResult getCustomCalculationResult(Integer setId, Premise premise, Destination destination, BigDecimal containerShare, double huAnnualAmount, BigDecimal transportationCost, BigDecimal transportationChanceCost, BigDecimal transportationRiskCost) {
var shippingFrequency = shippingFrequencyCalculationService.doCalculation(huAnnualAmount); var shippingFrequency = shippingFrequencyCalculationService.doCalculation(setId, huAnnualAmount);
var customFee = Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.CUSTOM_FEE).orElseThrow().getCurrentValue()); var customFee = Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.CUSTOM_FEE, setId).orElseThrow().getCurrentValue());
var tariffRate = premise.getTariffRate() == null ? customApiService.getTariffRate(premise.getHsCode(), premise.getCountryId()) : premise.getTariffRate(); var tariffRate = premise.getTariffRate() == null ? customApiService.getTariffRate(premise.getHsCode(), premise.getCountryId()) : premise.getTariffRate();
@ -80,7 +80,7 @@ public class CustomCostCalculationService {
var fcaFee = BigDecimal.ZERO; var fcaFee = BigDecimal.ZERO;
if (premise.getFcaEnabled()) { if (premise.getFcaEnabled()) {
var fcaProperty = propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.FCA_FEE).orElseThrow(); var fcaProperty = propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.FCA_FEE, setId).orElseThrow();
var fcaShare = Double.parseDouble(fcaProperty.getCurrentValue()); var fcaShare = Double.parseDouble(fcaProperty.getCurrentValue());
fcaFee = BigDecimal.valueOf(fcaShare).multiply(materialCost); fcaFee = BigDecimal.valueOf(fcaShare).multiply(materialCost);
} }
@ -101,7 +101,7 @@ public class CustomCostCalculationService {
return new CustomResult(customValue, customRiskValue, customChanceValue, customDuties, tariffRate, annualCost, annualRiskCost, annualChanceCost); return new CustomResult(customValue, customRiskValue, customChanceValue, customDuties, tariffRate, annualCost, annualRiskCost, annualChanceCost);
} }
private List<SectionInfo> getCustomRelevantRouteSections(List<SectionInfo> sections) { private List<SectionInfo> getCustomRelevantRouteSections(Integer setId, List<SectionInfo> sections) {
List<SectionInfo> customSections = new ArrayList<>(); List<SectionInfo> customSections = new ArrayList<>();
@ -111,8 +111,8 @@ public class CustomCostCalculationService {
} }
for (SectionInfo section : sections) { for (SectionInfo section : sections) {
if (!(CustomUnionType.EU == getCustomUnionByRouteNodeId(section.section().getFromRouteNodeId()) && if (!(CustomUnionType.EU == getCustomUnionByRouteNodeId(setId, section.section().getFromRouteNodeId()) &&
CustomUnionType.EU == getCustomUnionByRouteNodeId(section.section().getToRouteNodeId()))) { CustomUnionType.EU == getCustomUnionByRouteNodeId(setId, section.section().getToRouteNodeId()))) {
customSections.add(section); customSections.add(section);
} }
} }
@ -120,13 +120,13 @@ public class CustomCostCalculationService {
return customSections; return customSections;
} }
private CustomUnionType getCustomUnionByRouteNodeId(Integer routeNodeId) { private CustomUnionType getCustomUnionByRouteNodeId(Integer setId, Integer routeNodeId) {
var node = routeNodeRepository.getById(routeNodeId).orElseThrow(); var node = routeNodeRepository.getById(routeNodeId).orElseThrow();
return getCustomUnionByCountryId(node.getCountryId()); return getCustomUnionByCountryId(setId, node.getCountryId());
} }
private CustomUnionType getCustomUnionByCountryId(Integer countryId) { private CustomUnionType getCustomUnionByCountryId(Integer setId, Integer countryId) {
var property = countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.UNION, countryId).orElseThrow(); var property = countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.UNION, setId, countryId).orElseThrow();
if (property.getCurrentValue() == null) if (property.getCurrentValue() == null)
return CustomUnionType.NONE; return CustomUnionType.NONE;

View file

@ -30,36 +30,36 @@ public class HandlingCostCalculationService {
this.shippingFrequencyCalculationService = shippingFrequencyCalculationService; this.shippingFrequencyCalculationService = shippingFrequencyCalculationService;
} }
public HandlingResult doCalculation(Premise premise, Destination destination, Boolean addRepackingCosts) { public HandlingResult doCalculation(Integer setId, Premise premise, Destination destination, Boolean addRepackingCosts) {
var hu = premiseToHuService.createHuFromPremise(premise); var hu = premiseToHuService.createHuFromPremise(premise);
return (LoadCarrierType.SLC == hu.getLoadCarrierType() ? getSLCCost(destination, hu, hu.getLoadCarrierType(), addRepackingCosts) : getLLCCost(destination, hu, hu.getLoadCarrierType(), addRepackingCosts)); return (LoadCarrierType.SLC == hu.getLoadCarrierType() ? getSLCCost(setId, destination, hu, hu.getLoadCarrierType(), addRepackingCosts) : getLLCCost(setId, destination, hu, hu.getLoadCarrierType(), addRepackingCosts));
} }
private HandlingResult getSLCCost(Destination destination, PackagingDimension hu, LoadCarrierType loadCarrierType, boolean addRepackingCosts) { private HandlingResult getSLCCost(Integer setId, Destination destination, PackagingDimension hu, LoadCarrierType loadCarrierType, boolean addRepackingCosts) {
var destinationHandling = destination.getHandlingCost(); var destinationHandling = destination.getHandlingCost();
var destinationDisposal = destination.getDisposalCost(); var destinationDisposal = destination.getDisposalCost();
var destinationRepacking = destination.getRepackingCost(); var destinationRepacking = destination.getRepackingCost();
BigDecimal huAnnualAmount = BigDecimal.valueOf(destination.getAnnualAmount()).divide(BigDecimal.valueOf(hu.getContentUnitCount()),4, RoundingMode.UP ); BigDecimal huAnnualAmount = BigDecimal.valueOf(destination.getAnnualAmount()).divide(BigDecimal.valueOf(hu.getContentUnitCount()),4, RoundingMode.UP );
BigDecimal handling = destinationHandling != null ? destinationHandling : BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.GLT_HANDLING).orElseThrow().getCurrentValue())); BigDecimal handling = destinationHandling != null ? destinationHandling : BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.GLT_HANDLING, setId).orElseThrow().getCurrentValue()));
BigDecimal release = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.GLT_RELEASE).orElseThrow().getCurrentValue())); BigDecimal release = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.GLT_RELEASE, setId).orElseThrow().getCurrentValue()));
BigDecimal dispatch = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.GLT_DISPATCH).orElseThrow().getCurrentValue())); BigDecimal dispatch = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.GLT_DISPATCH, setId).orElseThrow().getCurrentValue()));
BigDecimal disposal = destinationDisposal != null ? destinationDisposal : BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.DISPOSAL).orElseThrow().getCurrentValue())); BigDecimal disposal = destinationDisposal != null ? destinationDisposal : BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.DISPOSAL, setId).orElseThrow().getCurrentValue()));
BigDecimal wageFactor = BigDecimal.valueOf(Double.parseDouble(countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.WAGE, destination.getCountryId()).orElseThrow().getCurrentValue())); BigDecimal wageFactor = BigDecimal.valueOf(Double.parseDouble(countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.WAGE, setId, destination.getCountryId()).orElseThrow().getCurrentValue()));
BigDecimal booking = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.BOOKING_KLT).orElseThrow().getCurrentValue())); BigDecimal booking = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.BOOKING_KLT, setId).orElseThrow().getCurrentValue()));
return new HandlingResult(LoadCarrierType.SLC, return new HandlingResult(LoadCarrierType.SLC,
getRepackingCost(hu, loadCarrierType, addRepackingCosts, destinationRepacking).multiply(huAnnualAmount), getRepackingCost(setId, hu, loadCarrierType, addRepackingCosts, destinationRepacking).multiply(huAnnualAmount),
handling.multiply(huAnnualAmount), handling.multiply(huAnnualAmount),
destinationDisposal == null ? BigDecimal.ZERO : (disposal.multiply(huAnnualAmount)), //TODO: disposal SLC, ignore? destinationDisposal == null ? BigDecimal.ZERO : (disposal.multiply(huAnnualAmount)), //TODO: disposal SLC, ignore?
huAnnualAmount.multiply((handling.add(booking).add(release).add(dispatch).add(getRepackingCost(hu, loadCarrierType, addRepackingCosts, destinationRepacking)))).multiply(wageFactor)); huAnnualAmount.multiply((handling.add(booking).add(release).add(dispatch).add(getRepackingCost(setId, hu, loadCarrierType, addRepackingCosts, destinationRepacking)))).multiply(wageFactor));
} }
private BigDecimal getRepackingCost(PackagingDimension hu, LoadCarrierType type, boolean addRepackingCosts, BigDecimal userInput) { private BigDecimal getRepackingCost(Integer setId, PackagingDimension hu, LoadCarrierType type, boolean addRepackingCosts, BigDecimal userInput) {
if(userInput != null) if(userInput != null)
return userInput; return userInput;
@ -70,30 +70,30 @@ public class HandlingCostCalculationService {
return switch (type) { return switch (type) {
case SLC -> case SLC ->
BigDecimal.valueOf(Double.parseDouble((hu.getWeight() < 15_000) ? propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.KLT_REPACK_S).orElseThrow().getCurrentValue() : propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.KLT_REPACK_M).orElseThrow().getCurrentValue())); BigDecimal.valueOf(Double.parseDouble((hu.getWeight() < 15_000) ? propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.KLT_REPACK_S, setId).orElseThrow().getCurrentValue() : propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.KLT_REPACK_M, setId).orElseThrow().getCurrentValue()));
case LLC -> case LLC ->
BigDecimal.valueOf(Double.parseDouble(((hu.getWeight() < 15_000) ? propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.GLT_REPACK_S) : (hu.getWeight() < 2_000_000) ? propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.GLT_REPACK_M) : propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.GLT_REPACK_L)).orElseThrow().getCurrentValue())); BigDecimal.valueOf(Double.parseDouble(((hu.getWeight() < 15_000) ? propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.GLT_REPACK_S, setId) : (hu.getWeight() < 2_000_000) ? propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.GLT_REPACK_M, setId) : propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.GLT_REPACK_L, setId)).orElseThrow().getCurrentValue()));
}; };
} }
private HandlingResult getLLCCost(Destination destination, PackagingDimension hu, LoadCarrierType type, boolean addRepackingCosts) { private HandlingResult getLLCCost(Integer setId, Destination destination, PackagingDimension hu, LoadCarrierType type, boolean addRepackingCosts) {
var destinationHandling = destination.getHandlingCost(); var destinationHandling = destination.getHandlingCost();
var destinationDisposal = destination.getDisposalCost(); var destinationDisposal = destination.getDisposalCost();
var destinationRepacking = destination.getRepackingCost(); var destinationRepacking = destination.getRepackingCost();
BigDecimal huAnnualAmount = BigDecimal.valueOf(destination.getAnnualAmount()).divide(BigDecimal.valueOf(hu.getContentUnitCount()),4, RoundingMode.UP ); BigDecimal huAnnualAmount = BigDecimal.valueOf(destination.getAnnualAmount()).divide(BigDecimal.valueOf(hu.getContentUnitCount()),4, RoundingMode.UP );
BigDecimal handling = destinationHandling != null ? destinationHandling : BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.GLT_HANDLING).orElseThrow().getCurrentValue())); BigDecimal handling = destinationHandling != null ? destinationHandling : BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.GLT_HANDLING, setId).orElseThrow().getCurrentValue()));
BigDecimal release = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.GLT_RELEASE).orElseThrow().getCurrentValue())); BigDecimal release = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.GLT_RELEASE, setId).orElseThrow().getCurrentValue()));
BigDecimal dispatch = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.GLT_DISPATCH).orElseThrow().getCurrentValue())); BigDecimal dispatch = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.GLT_DISPATCH, setId).orElseThrow().getCurrentValue()));
BigDecimal disposal = destinationDisposal != null ? destinationDisposal : BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.DISPOSAL).orElseThrow().getCurrentValue())); BigDecimal disposal = destinationDisposal != null ? destinationDisposal : BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.DISPOSAL, setId).orElseThrow().getCurrentValue()));
BigDecimal wageFactor = BigDecimal.valueOf(Double.parseDouble(countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.WAGE, destination.getCountryId()).orElseThrow().getCurrentValue())); BigDecimal wageFactor = BigDecimal.valueOf(Double.parseDouble(countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.WAGE, setId, destination.getCountryId()).orElseThrow().getCurrentValue()));
BigDecimal booking = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.BOOKING).orElseThrow().getCurrentValue())); BigDecimal booking = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.BOOKING, setId).orElseThrow().getCurrentValue()));
var annualRepacking = getRepackingCost(hu, type, addRepackingCosts, destinationRepacking).multiply(wageFactor).multiply( huAnnualAmount); var annualRepacking = getRepackingCost(setId, hu, type, addRepackingCosts, destinationRepacking).multiply(wageFactor).multiply( huAnnualAmount);
var annualHandling = ((handling.add(dispatch).add(release)).multiply(wageFactor).multiply(huAnnualAmount)).add(booking.multiply(BigDecimal.valueOf(shippingFrequencyCalculationService.doCalculation(huAnnualAmount.doubleValue())))); var annualHandling = ((handling.add(dispatch).add(release)).multiply(wageFactor).multiply(huAnnualAmount)).add(booking.multiply(BigDecimal.valueOf(shippingFrequencyCalculationService.doCalculation(setId, huAnnualAmount.doubleValue()))));
var annualDisposal = (disposal.multiply(huAnnualAmount)); var annualDisposal = (disposal.multiply(huAnnualAmount));
return new HandlingResult(LoadCarrierType.LLC, annualRepacking, annualHandling, annualDisposal, annualRepacking.add(annualHandling).add(annualDisposal)); return new HandlingResult(LoadCarrierType.LLC, annualRepacking, annualHandling, annualDisposal, annualRepacking.add(annualHandling).add(annualDisposal));

View file

@ -30,7 +30,7 @@ public class InventoryCostCalculationService {
this.premiseToHuService = premiseToHuService; this.premiseToHuService = premiseToHuService;
} }
public InventoryCostResult doCalculation(Premise premise, Destination destination, BigDecimal leadTime) { public InventoryCostResult doCalculation(Integer setId, Premise premise, Destination destination, BigDecimal leadTime) {
var fcaFee = BigDecimal.ZERO; var fcaFee = BigDecimal.ZERO;
@ -44,16 +44,16 @@ public class InventoryCostCalculationService {
var hu = premiseToHuService.createHuFromPremise(premise); var hu = premiseToHuService.createHuFromPremise(premise);
double huAnnualAmount = BigDecimal.valueOf(destination.getAnnualAmount()).divide(BigDecimal.valueOf(hu.getContentUnitCount()),0, RoundingMode.UP ).doubleValue(); double huAnnualAmount = BigDecimal.valueOf(destination.getAnnualAmount()).divide(BigDecimal.valueOf(hu.getContentUnitCount()),0, RoundingMode.UP ).doubleValue();
var safetyDays = BigDecimal.valueOf(Integer.parseInt(countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.SAFETY_STOCK, premise.getCountryId()).orElseThrow().getCurrentValue())); var safetyDays = BigDecimal.valueOf(Integer.parseInt(countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.SAFETY_STOCK, setId, premise.getCountryId()).orElseThrow().getCurrentValue()));
var workdays = BigDecimal.valueOf(Integer.parseInt(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.WORKDAYS).orElseThrow().getCurrentValue())); var workdays = BigDecimal.valueOf(Integer.parseInt(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.WORKDAYS, setId).orElseThrow().getCurrentValue()));
var paymentTerms = BigDecimal.valueOf(Integer.parseInt(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.PAYMENT_TERMS).orElseThrow().getCurrentValue())); var paymentTerms = BigDecimal.valueOf(Integer.parseInt(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.PAYMENT_TERMS, setId).orElseThrow().getCurrentValue()));
var interestRate = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.INTEREST_RATE).orElseThrow().getCurrentValue())); var interestRate = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.INTEREST_RATE, setId).orElseThrow().getCurrentValue()));
var annualAmount = BigDecimal.valueOf(destination.getAnnualAmount().doubleValue()); var annualAmount = BigDecimal.valueOf(destination.getAnnualAmount().doubleValue());
var dailyAmount = annualAmount.divide(BigDecimal.valueOf(365), 10, RoundingMode.HALF_UP); var dailyAmount = annualAmount.divide(BigDecimal.valueOf(365), 10, RoundingMode.HALF_UP);
var workdayAmount = annualAmount.divide(workdays, 10, RoundingMode.HALF_UP); var workdayAmount = annualAmount.divide(workdays, 10, RoundingMode.HALF_UP);
var opStock = (annualAmount.divide(BigDecimal.valueOf(Math.max(shippingFrequencyCalculationService.doCalculation(huAnnualAmount),1)), 10, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(.5))); var opStock = (annualAmount.divide(BigDecimal.valueOf(Math.max(shippingFrequencyCalculationService.doCalculation(setId, huAnnualAmount),1)), 10, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(.5)));
var safetyStock = safetyDays.multiply(workdayAmount); var safetyStock = safetyDays.multiply(workdayAmount);
var stockedInventory = opStock.add(safetyStock); var stockedInventory = opStock.add(safetyStock);
var inTransportStock = dailyAmount.multiply(leadTime); var inTransportStock = dailyAmount.multiply(leadTime);
@ -63,15 +63,15 @@ public class InventoryCostCalculationService {
var storageCostStock = roundToHu(hu, safetyStock.add(opStock)); var storageCostStock = roundToHu(hu, safetyStock.add(opStock));
var capitalCost = capitalCostStock.multiply(interestRate).multiply(premise.getMaterialCost().add(fcaFee)); var capitalCost = capitalCostStock.multiply(interestRate).multiply(premise.getMaterialCost().add(fcaFee));
var storageCost = storageCostStock.multiply(getSpaceCostPerHu(hu)).multiply(BigDecimal.valueOf(365)); var storageCost = storageCostStock.multiply(getSpaceCostPerHu(setId, hu)).multiply(BigDecimal.valueOf(365));
return new InventoryCostResult(opStock, safetyStock, stockedInventory, inTransportStock, stockBeforePayment, capitalCost, storageCost, safetyDays ); return new InventoryCostResult(opStock, safetyStock, stockedInventory, inTransportStock, stockBeforePayment, capitalCost, storageCost, safetyDays );
} }
private BigDecimal getSpaceCostPerHu(PackagingDimension hu) { private BigDecimal getSpaceCostPerHu(Integer setId, PackagingDimension hu) {
var spaceCost = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.SPACE_COST).orElseThrow().getCurrentValue())); var spaceCost = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.SPACE_COST, setId).orElseThrow().getCurrentValue()));
var spaceCostPerHu = BigDecimal.valueOf(hu.getFloorArea(DimensionUnit.M)*hu.getRoundedHeight(DimensionUnit.M)).multiply(spaceCost); var spaceCostPerHu = BigDecimal.valueOf(hu.getFloorArea(DimensionUnit.M)*hu.getRoundedHeight(DimensionUnit.M)).multiply(spaceCost);
return spaceCostPerHu; return spaceCostPerHu;
} }

View file

@ -49,7 +49,7 @@ public class RouteSectionCostCalculationService {
this.nodeRepository = nodeRepository; this.nodeRepository = nodeRepository;
} }
public CalculationJobRouteSection doD2dCalculation(Premise premise, Destination destination, ContainerCalculationResult containerCalculation) { public CalculationJobRouteSection doD2dCalculation(Integer setId, Integer periodId, Premise premise, Destination destination, ContainerCalculationResult containerCalculation) {
CalculationJobRouteSection result = new CalculationJobRouteSection(); CalculationJobRouteSection result = new CalculationJobRouteSection();
// Set route metadata // Set route metadata
@ -78,7 +78,7 @@ public class RouteSectionCostCalculationService {
result.setTransitTime(transitTime); result.setTransitTime(transitTime);
// Calculate price and annual cost // Calculate price and annual cost
BigDecimal utilization = getUtilization(RateType.CONTAINER); /* D2D is always 40ft container */ BigDecimal utilization = getUtilization(setId, RateType.CONTAINER); /* D2D is always 40ft container */
double annualVolume = destination.getAnnualAmount() * containerCalculation.getHu().getVolume(DimensionUnit.M); double annualVolume = destination.getAnnualAmount() * containerCalculation.getHu().getVolume(DimensionUnit.M);
PriceCalculationResult prices = calculatePrices( PriceCalculationResult prices = calculatePrices(
@ -97,7 +97,7 @@ public class RouteSectionCostCalculationService {
result.setWeightPrice(prices.weightPrice); result.setWeightPrice(prices.weightPrice);
result.setUtilization(prices.utilization); result.setUtilization(prices.utilization);
var chanceRiskFactors = changeRiskFactorCalculationService.getChanceRiskFactors(); var chanceRiskFactors = changeRiskFactorCalculationService.getChanceRiskFactors(setId, periodId);
BigDecimal annualCost = (containerCalculation.isWeightExceeded() ? prices.weightPrice : prices.volumePrice).multiply(BigDecimal.valueOf(annualVolume)); BigDecimal annualCost = (containerCalculation.isWeightExceeded() ? prices.weightPrice : prices.volumePrice).multiply(BigDecimal.valueOf(annualVolume));
BigDecimal annualRiskCost = annualCost.multiply(chanceRiskFactors.getRiskFactor()); BigDecimal annualRiskCost = annualCost.multiply(chanceRiskFactors.getRiskFactor());
@ -110,7 +110,7 @@ public class RouteSectionCostCalculationService {
return result; return result;
} }
public CalculationJobRouteSection doCalculation(Premise premise, Destination destination, RouteSection section, ContainerCalculationResult containerCalculation) { public CalculationJobRouteSection doCalculation(Integer setId, Integer periodId, Premise premise, Destination destination, RouteSection section, ContainerCalculationResult containerCalculation) {
CalculationJobRouteSection result = new CalculationJobRouteSection(); CalculationJobRouteSection result = new CalculationJobRouteSection();
// Set route metadata // Set route metadata
@ -135,11 +135,11 @@ public class RouteSectionCostCalculationService {
int transitTime; int transitTime;
if (RateType.CONTAINER == section.getRateType()) { if (RateType.CONTAINER == section.getRateType()) {
ContainerRate containerRate = findContainerRate(section, fromNode, toNode); ContainerRate containerRate = findContainerRate(section, fromNode, toNode, periodId);
rate = getContainerRate(containerRate, containerCalculation.getContainerType()); rate = getContainerRate(containerRate, containerCalculation.getContainerType());
transitTime = containerRate.getLeadTime(); transitTime = containerRate.getLeadTime();
} else if (RateType.MATRIX == section.getRateType()) { } else if (RateType.MATRIX == section.getRateType()) {
MatrixRate matrixRate = findMatrixRate(fromNode, toNode); MatrixRate matrixRate = findMatrixRate(fromNode, toNode, periodId);
rate = matrixRate.getRate().multiply(BigDecimal.valueOf(distance)); rate = matrixRate.getRate().multiply(BigDecimal.valueOf(distance));
transitTime = 3; // Default transit time for matrix rate transitTime = 3; // Default transit time for matrix rate
} else if (RateType.NEAR_BY == section.getRateType()) { } else if (RateType.NEAR_BY == section.getRateType()) {
@ -154,7 +154,7 @@ public class RouteSectionCostCalculationService {
// Calculate price and annual cost // Calculate price and annual cost
BigDecimal huAnnualAmount = BigDecimal.valueOf(destination.getAnnualAmount()).divide(BigDecimal.valueOf(containerCalculation.getHu().getContentUnitCount()), 2, RoundingMode.HALF_UP); BigDecimal huAnnualAmount = BigDecimal.valueOf(destination.getAnnualAmount()).divide(BigDecimal.valueOf(containerCalculation.getHu().getContentUnitCount()), 2, RoundingMode.HALF_UP);
BigDecimal utilization = getUtilization(section.getRateType()); BigDecimal utilization = getUtilization(setId, section.getRateType());
BigDecimal annualVolume = huAnnualAmount.multiply(BigDecimal.valueOf(containerCalculation.getHu().getVolume(DimensionUnit.M))); BigDecimal annualVolume = huAnnualAmount.multiply(BigDecimal.valueOf(containerCalculation.getHu().getVolume(DimensionUnit.M)));
BigDecimal annualWeight = huAnnualAmount.multiply(BigDecimal.valueOf(containerCalculation.getHu().getWeight(WeightUnit.KG))); BigDecimal annualWeight = huAnnualAmount.multiply(BigDecimal.valueOf(containerCalculation.getHu().getWeight(WeightUnit.KG)));
@ -174,7 +174,7 @@ public class RouteSectionCostCalculationService {
result.setWeightPrice(prices.weightPrice); result.setWeightPrice(prices.weightPrice);
result.setUtilization(!containerCalculation.isWeightExceeded() || !premise.getHuMixable() ? prices.utilization : BigDecimal.valueOf(1.0)); result.setUtilization(!containerCalculation.isWeightExceeded() || !premise.getHuMixable() ? prices.utilization : BigDecimal.valueOf(1.0));
var chanceRiskFactors = changeRiskFactorCalculationService.getChanceRiskFactors(); var chanceRiskFactors = changeRiskFactorCalculationService.getChanceRiskFactors(setId, periodId);
BigDecimal annualCost = (containerCalculation.isWeightExceeded() ? prices.weightPrice.multiply(annualWeight) : prices.volumePrice.multiply(annualVolume)); BigDecimal annualCost = (containerCalculation.isWeightExceeded() ? prices.weightPrice.multiply(annualWeight) : prices.volumePrice.multiply(annualVolume));
BigDecimal annualRiskCost = annualCost.multiply(chanceRiskFactors.getRiskFactor()); BigDecimal annualRiskCost = annualCost.multiply(chanceRiskFactors.getRiskFactor());
@ -220,31 +220,32 @@ public class RouteSectionCostCalculationService {
return new PriceCalculationResult(volumePrice, weightPrice, utilization); return new PriceCalculationResult(volumePrice, weightPrice, utilization);
} }
private ContainerRate findContainerRate(RouteSection section, RouteNode fromNode, RouteNode toNode) { private ContainerRate findContainerRate(RouteSection section, RouteNode fromNode, RouteNode toNode, Integer periodId) {
return containerRateRepository.findRoute( return containerRateRepository.findRoute(
fromNode.getNodeId(), fromNode.getNodeId(),
toNode.getNodeId(), toNode.getNodeId(),
periodId,
TransportType.valueOf(section.getTransportType().name())) TransportType.valueOf(section.getTransportType().name()))
.orElseThrow(() -> new NoSuchElementException( .orElseThrow(() -> new NoSuchElementException(
"ContainerRate not found for route: " + fromNode.getName() + "(" + fromNode.getNodeId() + ")" + "ContainerRate not found for route: " + fromNode.getName() + "(" + fromNode.getNodeId() + ")" +
" to " + toNode.getName() + "(" + toNode.getNodeId() + ")")); " to " + toNode.getName() + "(" + toNode.getNodeId() + ")"));
} }
private MatrixRate findMatrixRate(RouteNode fromNode, RouteNode toNode) { private MatrixRate findMatrixRate(RouteNode fromNode, RouteNode toNode, Integer periodId) {
return matrixRateRepository.getByCountryIds(fromNode.getCountryId(), toNode.getCountryId()) return matrixRateRepository.getByCountryIds(fromNode.getCountryId(), toNode.getCountryId(), periodId)
.orElseThrow(() -> new NoSuchElementException( .orElseThrow(() -> new NoSuchElementException(
"MatrixRate not found for countries: " + fromNode.getCountryId() + "MatrixRate not found for countries: " + fromNode.getCountryId() +
" to " + toNode.getCountryId())); " to " + toNode.getCountryId()));
} }
private BigDecimal getUtilization(RateType rateType) { private BigDecimal getUtilization(Integer setId, RateType rateType) {
BigDecimal utilization; BigDecimal utilization;
if (rateType == RateType.NEAR_BY) { if (rateType == RateType.NEAR_BY) {
utilization = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.CONTAINER_UTIL).orElseThrow().getCurrentValue())); utilization = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.CONTAINER_UTIL, setId).orElseThrow().getCurrentValue()));
} else if (rateType == RateType.CONTAINER) { } else if (rateType == RateType.CONTAINER) {
utilization = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.CONTAINER_UTIL).orElseThrow().getCurrentValue())); utilization = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.CONTAINER_UTIL, setId).orElseThrow().getCurrentValue()));
} else if (rateType == RateType.MATRIX) { } else if (rateType == RateType.MATRIX) {
utilization = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.TRUCK_UTIL).orElseThrow().getCurrentValue())); utilization = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.TRUCK_UTIL, setId).orElseThrow().getCurrentValue()));
} else } else
throw new IllegalArgumentException("Unknown rate type"); throw new IllegalArgumentException("Unknown rate type");

View file

@ -13,9 +13,9 @@ public class ShippingFrequencyCalculationService {
this.propertyRepository = propertyRepository; this.propertyRepository = propertyRepository;
} }
public int doCalculation(int huAnnualAmount) { public int doCalculation(Integer setId, int huAnnualAmount) {
var minAnnualFrequency = Integer.parseInt(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.FREQ_MIN).orElseThrow().getCurrentValue()); var minAnnualFrequency = Integer.parseInt(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.FREQ_MIN, setId).orElseThrow().getCurrentValue());
var maxAnnualFrequency = Integer.parseInt(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.FREQ_MAX).orElseThrow().getCurrentValue()); var maxAnnualFrequency = Integer.parseInt(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.FREQ_MAX, setId).orElseThrow().getCurrentValue());
if (huAnnualAmount > maxAnnualFrequency) if (huAnnualAmount > maxAnnualFrequency)
return maxAnnualFrequency; return maxAnnualFrequency;
@ -24,9 +24,9 @@ public class ShippingFrequencyCalculationService {
} }
public double doCalculation(double huAnnualAmount) { public double doCalculation(Integer setId, double huAnnualAmount) {
Integer minAnnualFrequency = Integer.parseInt(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.FREQ_MIN).orElseThrow().getCurrentValue()); Integer minAnnualFrequency = Integer.parseInt(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.FREQ_MIN, setId).orElseThrow().getCurrentValue());
Integer maxAnnualFrequency = Integer.parseInt(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.FREQ_MAX).orElseThrow().getCurrentValue()); Integer maxAnnualFrequency = Integer.parseInt(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.FREQ_MAX, setId).orElseThrow().getCurrentValue());
if (huAnnualAmount > maxAnnualFrequency.doubleValue()) if (huAnnualAmount > maxAnnualFrequency.doubleValue())
return maxAnnualFrequency; return maxAnnualFrequency;

View file

@ -1,24 +1,32 @@
package de.avatic.lcc.service.precalculation; package de.avatic.lcc.service.precalculation;
import de.avatic.lcc.dto.generic.ContainerType; import de.avatic.lcc.dto.generic.ContainerType;
import de.avatic.lcc.dto.generic.RateType;
import de.avatic.lcc.model.nodes.Node; import de.avatic.lcc.model.nodes.Node;
import de.avatic.lcc.model.premises.Premise; import de.avatic.lcc.model.premises.Premise;
import de.avatic.lcc.model.premises.route.Destination; import de.avatic.lcc.model.premises.route.Destination;
import de.avatic.lcc.model.premises.route.Route; import de.avatic.lcc.model.premises.route.Route;
import de.avatic.lcc.model.premises.route.RouteSection;
import de.avatic.lcc.model.properties.PropertySet;
import de.avatic.lcc.model.properties.SystemPropertyMappingId; import de.avatic.lcc.model.properties.SystemPropertyMappingId;
import de.avatic.lcc.model.rates.ValidityPeriod;
import de.avatic.lcc.model.rates.ValidityPeriodState;
import de.avatic.lcc.model.utils.WeightUnit; import de.avatic.lcc.model.utils.WeightUnit;
import de.avatic.lcc.repositories.NodeRepository; import de.avatic.lcc.repositories.NodeRepository;
import de.avatic.lcc.repositories.premise.DestinationRepository; import de.avatic.lcc.repositories.premise.*;
import de.avatic.lcc.repositories.premise.PremiseRepository; import de.avatic.lcc.repositories.properties.PropertySetRepository;
import de.avatic.lcc.repositories.premise.RouteRepository; import de.avatic.lcc.repositories.rates.ContainerRateRepository;
import de.avatic.lcc.repositories.properties.PropertyRepository; import de.avatic.lcc.repositories.rates.MatrixRateRepository;
import de.avatic.lcc.service.api.CustomApiService; import de.avatic.lcc.repositories.rates.ValidityPeriodRepository;
import de.avatic.lcc.service.access.PropertyService; import de.avatic.lcc.service.access.PropertyService;
import de.avatic.lcc.service.api.CustomApiService;
import de.avatic.lcc.service.transformer.generic.DimensionTransformer; import de.avatic.lcc.service.transformer.generic.DimensionTransformer;
import de.avatic.lcc.util.exception.internalerror.PremiseValidationError; import de.avatic.lcc.util.exception.internalerror.PremiseValidationError;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Optional; import java.util.Optional;
@Service @Service
@ -32,28 +40,39 @@ public class PreCalculationCheckService {
private final RouteRepository routeRepository; private final RouteRepository routeRepository;
private final NodeRepository nodeRepository; private final NodeRepository nodeRepository;
private final DimensionTransformer dimensionTransformer; private final DimensionTransformer dimensionTransformer;
private final PropertyRepository propertyRepository;
private final PropertyService propertyService;
public PreCalculationCheckService(PremiseRepository premiseRepository, CustomApiService customApiService, DestinationRepository destinationRepository, RouteRepository routeRepository, NodeRepository nodeRepository, DimensionTransformer dimensionTransformer, PropertyRepository propertyRepository, PropertyService propertyService) { private final PropertyService propertyService;
private final RouteSectionRepository routeSectionRepository;
private final RouteNodeRepository routeNodeRepository;
private final MatrixRateRepository matrixRateRepository;
private final ContainerRateRepository containerRateRepository;
private final ValidityPeriodRepository validityPeriodRepository;
private final PropertySetRepository propertySetRepository;
public PreCalculationCheckService(PremiseRepository premiseRepository, CustomApiService customApiService, DestinationRepository destinationRepository, RouteRepository routeRepository, NodeRepository nodeRepository, DimensionTransformer dimensionTransformer, PropertyService propertyService, RouteSectionRepository routeSectionRepository, RouteNodeRepository routeNodeRepository, MatrixRateRepository matrixRateRepository, ContainerRateRepository containerRateRepository, ValidityPeriodRepository validityPeriodRepository, PropertySetRepository propertySetRepository) {
this.premiseRepository = premiseRepository; this.premiseRepository = premiseRepository;
this.customApiService = customApiService; this.customApiService = customApiService;
this.destinationRepository = destinationRepository; this.destinationRepository = destinationRepository;
this.routeRepository = routeRepository; this.routeRepository = routeRepository;
this.nodeRepository = nodeRepository; this.nodeRepository = nodeRepository;
this.dimensionTransformer = dimensionTransformer; this.dimensionTransformer = dimensionTransformer;
this.propertyRepository = propertyRepository;
this.propertyService = propertyService; this.propertyService = propertyService;
this.routeSectionRepository = routeSectionRepository;
this.routeNodeRepository = routeNodeRepository;
this.matrixRateRepository = matrixRateRepository;
this.containerRateRepository = containerRateRepository;
this.validityPeriodRepository = validityPeriodRepository;
this.propertySetRepository = propertySetRepository;
} }
public void doPrecheck(Integer premiseId) { public void doPrecheck(Integer premiseId, Integer setId, Integer periodId) {
var premise = premiseRepository.getPremiseById(premiseId).orElseThrow(); var premise = premiseRepository.getPremiseById(premiseId).orElseThrow();
supplierCheck(premise); supplierCheck(premise);
materialCheck(premise); materialCheck(premise);
packagingCheck(premise); packagingCheck(premise);
priceCheck(premise); priceCheck(premise);
@ -88,10 +107,68 @@ public class PreCalculationCheckService {
throw new PremiseValidationError("Door-2-door lead time not entered or zero."); throw new PremiseValidationError("Door-2-door lead time not entered or zero.");
} }
var period = validityPeriodRepository.getById(periodId);
var set = propertySetRepository.getById(setId);
periodCheck(period, set);
routes.stream().filter(Route::getSelected).findAny().ifPresent(r -> {
var sections = routeSectionRepository.getByRouteId(r.getId());
routeCheck(sections, period);
});
} }
} }
private void periodCheck(ValidityPeriod period, PropertySet set) {
if(set == null)
throw new PremiseValidationError("There are no system properties for the given date.");
if(period == null)
throw new PremiseValidationError("There are no rates for the given date.");
if(ValidityPeriodState.VALID != period.getState() && ValidityPeriodState.EXPIRED != period.getState())
throw new PremiseValidationError("There are no valid rates for the given date.");
if(ValidityPeriodState.VALID != set.getState() && ValidityPeriodState.EXPIRED != period.getState())
throw new PremiseValidationError("There are no valid system properties for the given date.");
}
private void routeCheck(List<RouteSection> sections, ValidityPeriod period) {
sections.forEach(section -> {
var fromRouteNode = routeNodeRepository.getFromNodeBySectionId(section.getId());
var toRouteNode = routeNodeRepository.getToNodeBySectionId(section.getId());
if (fromRouteNode.isEmpty() || toRouteNode.isEmpty())
throw new PremiseValidationError("Error in route. Please contact your administrator.");
if (RateType.MATRIX == section.getRateType()) {
var rate = matrixRateRepository.getByCountryIds(fromRouteNode.get().getCountryId(), toRouteNode.get().getCountryId(), period.getId());
if (rate.isEmpty())
throw new PremiseValidationError("The transport rates for the period " + period.getStartDate().format(DateTimeFormatter.ISO_DATE) + " to " + period.getEndDate().format(DateTimeFormatter.ISO_DATE) + " are insufficient to perform the calculation for route segment" + fromRouteNode.get().getExternalMappingId() + " to " + toRouteNode.get().getExternalMappingId());
}
if (RateType.CONTAINER == section.getRateType()) {
var rate = containerRateRepository.findRoute(fromRouteNode.get().getNodeId(), toRouteNode.get().getNodeId(), period.getId(), section.getTransportType());
if (rate.isEmpty())
throw new PremiseValidationError("The transport rates for the period " + period.getStartDate().format(DateTimeFormatter.ISO_DATE) + " to " + period.getEndDate().format(DateTimeFormatter.ISO_DATE) + " are insufficient to perform the calculation for route segment" + fromRouteNode.get().getExternalMappingId() + " to " + toRouteNode.get().getExternalMappingId());
}
});
}
private void destinationCheck(Destination destination, Node node) { private void destinationCheck(Destination destination, Node node) {
if (destination.getAnnualAmount() == null || destination.getAnnualAmount() == 0) if (destination.getAnnualAmount() == null || destination.getAnnualAmount() == 0)
@ -216,7 +293,7 @@ public class PreCalculationCheckService {
} }
if((hu.getLength() * hu.getWidth()) < 20000) { if ((hu.getLength() * hu.getWidth()) < 20000) {
throw new PremiseValidationError("HU dimensions too small. Review entered length, width, height and selected dimension unit [mm, cm, m]."); throw new PremiseValidationError("HU dimensions too small. Review entered length, width, height and selected dimension unit [mm, cm, m].");
} }