- 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:
parent
dac371b481
commit
78bd0ad6d6
15 changed files with 318 additions and 131 deletions
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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 -> {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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].");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue