Refactor: Pass ContainerCalculationResult into cost calculation services and update ShippingFrequencyCalculationService logic to consider HU per container handling.

This commit is contained in:
Jan 2025-12-17 14:29:08 +01:00
parent 9ac3cb7815
commit 1788a7ef1c
8 changed files with 50 additions and 25 deletions

View file

@ -0,0 +1,4 @@
package de.avatic.lcc.dto.configuration.apps;
public class AppExchangeDTO {
}

View file

@ -215,7 +215,7 @@ public class ContainerCalculationResult {
* @return The total utilization value for the container. * @return The total utilization value for the container.
*/ */
public double getTotalUtilizationByVolume() { public double getTotalUtilizationByVolume() {
return getHuUtilizationByVolume() * huUnitCount * layer; return getHuUtilizationByVolume() * huUnitCount;
} }
/** /**
@ -254,4 +254,7 @@ public class ContainerCalculationResult {
return WeightUnit.KG.convertFromG(hu.getWeight()) / maxContainerWeight; return WeightUnit.KG.convertFromG(hu.getWeight()) / maxContainerWeight;
} }
public int getHuPerContainer() {
return this.huUnitCount;
}
} }

View file

@ -137,13 +137,15 @@ public class CalculationExecutionService {
AirfreightResult airfreightCost = airfreightCalculationService.doCalculation(setId, periodId, premise, destination); AirfreightResult airfreightCost = airfreightCalculationService.doCalculation(setId, periodId, premise, destination);
ContainerType usedContainerType = null; ContainerType usedContainerType = null;
ContainerCalculationResult selectedContainerCalculation = null;
CalculationJobDestination destinationCalculationJob = new CalculationJobDestination(); CalculationJobDestination destinationCalculationJob = new CalculationJobDestination();
boolean hasMainRun = true; boolean hasMainRun = true;
BigDecimal leadTime = null; BigDecimal leadTime = null;
if (destination.getD2d()) { if (destination.getD2d()) {
var containerCalculation = containerCalculationService.doCalculation(setId, premiseToHuService.createHuFromPremise(premise), ContainerType.FEU, premise.getHuMixable(), premise.getHuStackable()); selectedContainerCalculation = containerCalculationService.doCalculation(setId, premiseToHuService.createHuFromPremise(premise), ContainerType.FEU, premise.getHuMixable(), premise.getHuStackable());
sections = List.of(new SectionInfo(null, routeSectionCostCalculationService.doD2dCalculation(setId, periodId, premise, destination, containerCalculation), containerCalculation)); sections = List.of(new SectionInfo(null, routeSectionCostCalculationService.doD2dCalculation(setId, periodId, premise, destination, selectedContainerCalculation), selectedContainerCalculation));
leadTime = BigDecimal.valueOf(destination.getLeadTimeD2d()); leadTime = BigDecimal.valueOf(destination.getLeadTimeD2d());
usedContainerType = ContainerType.FEU; usedContainerType = ContainerType.FEU;
} else { } else {
@ -161,6 +163,8 @@ public class CalculationExecutionService {
s.result().setPostRun(false); s.result().setPostRun(false);
}); });
} }
selectedContainerCalculation = bestContainerTypeResult.selectedContainerCalculation;
} }
destinationCalculationJob.setD2D(destination.getD2d()); destinationCalculationJob.setD2D(destination.getD2d());
@ -168,9 +172,9 @@ public class CalculationExecutionService {
if(destination.getD2d()) if(destination.getD2d())
destinationCalculationJob.setRateD2D(destination.getRateD2d()); destinationCalculationJob.setRateD2D(destination.getRateD2d());
customCost = customCostCalculationService.doCalculation(setId, premise, destination, sections); customCost = customCostCalculationService.doCalculation(setId, premise, destination, sections, selectedContainerCalculation);
handlingCost = handlingCostCalculationService.doCalculation(setId, premise, destination, hasMainRun); handlingCost = handlingCostCalculationService.doCalculation(setId, premise, destination, hasMainRun, selectedContainerCalculation);
inventoryCost = inventoryCostCalculationService.doCalculation(setId, premise, destination, leadTime); inventoryCost = inventoryCostCalculationService.doCalculation(setId, premise, destination, leadTime, selectedContainerCalculation);
destinationCalculationJob.setContainerType(usedContainerType); destinationCalculationJob.setContainerType(usedContainerType);
@ -209,7 +213,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(setId, destination.getAnnualAmount())); destinationCalculationJob.setShippingFrequency(shippingFrequencyCalculationService.doCalculation(setId, destination.getAnnualAmount(), selectedContainerCalculation.getHuPerContainer(),!premise.getHuMixable()));
var commonCost = destinationCalculationJob.getAnnualHandlingCost() var commonCost = destinationCalculationJob.getAnnualHandlingCost()
.add(destinationCalculationJob.getAnnualDisposalCost()) .add(destinationCalculationJob.getAnnualDisposalCost())
@ -264,10 +268,10 @@ public class CalculationExecutionService {
} }
var bestContainerType = getBestContainerType(sectionInfos); var bestContainerType = getBestContainerType(sectionInfos);
return new BestContainerTypeResult(bestContainerType, sectionInfos.get(bestContainerType)); return new BestContainerTypeResult(bestContainerType, sectionInfos.get(bestContainerType), containerCalculation.get(bestContainerType));
} }
private record BestContainerTypeResult(ContainerType containerType, List<SectionInfo> sections) { private record BestContainerTypeResult(ContainerType containerType, List<SectionInfo> sections, ContainerCalculationResult selectedContainerCalculation) {
} }
} }

View file

@ -37,7 +37,7 @@ public class CustomCostCalculationService {
this.shippingFrequencyCalculationService = shippingFrequencyCalculationService; this.shippingFrequencyCalculationService = shippingFrequencyCalculationService;
} }
public CustomResult doCalculation(Integer setId, Premise premise, Destination destination, List<SectionInfo> sections) { public CustomResult doCalculation(Integer setId, Premise premise, Destination destination, List<SectionInfo> sections, ContainerCalculationResult containerCalculationResult) {
var destUnion = countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.UNION, setId, destination.getCountryId()).orElseThrow(); var destUnion = countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.UNION, setId, destination.getCountryId()).orElseThrow();
var sourceUnion = countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.UNION, setId, premise.getCountryId()).orElseThrow(); var sourceUnion = countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.UNION, setId, premise.getCountryId()).orElseThrow();
@ -53,14 +53,15 @@ public class CustomCostCalculationService {
double huAnnualAmount = BigDecimal.valueOf(destination.getAnnualAmount()).divide(BigDecimal.valueOf(premise.getHuUnitCount()),0, RoundingMode.CEILING).doubleValue(); double huAnnualAmount = BigDecimal.valueOf(destination.getAnnualAmount()).divide(BigDecimal.valueOf(premise.getHuUnitCount()),0, RoundingMode.CEILING).doubleValue();
return getCustomCalculationResult(setId, premise, destination, huAnnualAmount, transportationCost, transportationChanceCost, transportationRiskCost); return getCustomCalculationResult(setId, premise, destination, huAnnualAmount, transportationCost, transportationChanceCost, transportationRiskCost, containerCalculationResult);
} }
return CustomResult.EMPTY; return CustomResult.EMPTY;
} }
private CustomResult getCustomCalculationResult(Integer setId, Premise premise, Destination destination, double huAnnualAmount, BigDecimal transportationCost, BigDecimal transportationChanceCost, BigDecimal transportationRiskCost) { private CustomResult getCustomCalculationResult(Integer setId, Premise premise, Destination destination, double huAnnualAmount, BigDecimal transportationCost, BigDecimal transportationChanceCost, BigDecimal transportationRiskCost, ContainerCalculationResult containerCalculationResult) {
var shippingFrequency = shippingFrequencyCalculationService.doCalculation(setId, huAnnualAmount);
var shippingFrequency = shippingFrequencyCalculationService.doCalculation(setId, huAnnualAmount, containerCalculationResult.getHuPerContainer(), !premise.getHuMixable());
var customFee = Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.CUSTOM_FEE, setId).orElseThrow().getCurrentValue()); var customFee = Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.CUSTOM_FEE, setId).orElseThrow().getCurrentValue());
var tariffRate = premise.getTariffRate(); var tariffRate = premise.getTariffRate();

View file

@ -1,5 +1,6 @@
package de.avatic.lcc.service.calculation.execution.steps; package de.avatic.lcc.service.calculation.execution.steps;
import de.avatic.lcc.model.calculation.ContainerCalculationResult;
import de.avatic.lcc.model.calculation.HandlingResult; import de.avatic.lcc.model.calculation.HandlingResult;
import de.avatic.lcc.model.db.packaging.LoadCarrierType; import de.avatic.lcc.model.db.packaging.LoadCarrierType;
import de.avatic.lcc.model.db.packaging.PackagingDimension; import de.avatic.lcc.model.db.packaging.PackagingDimension;
@ -30,13 +31,13 @@ public class HandlingCostCalculationService {
this.shippingFrequencyCalculationService = shippingFrequencyCalculationService; this.shippingFrequencyCalculationService = shippingFrequencyCalculationService;
} }
public HandlingResult doCalculation(Integer setId, Premise premise, Destination destination, Boolean addRepackingAndDisposalCost) { public HandlingResult doCalculation(Integer setId, Premise premise, Destination destination, Boolean addRepackingAndDisposalCost, ContainerCalculationResult containerCalculationResult) {
var hu = premiseToHuService.createHuFromPremise(premise); var hu = premiseToHuService.createHuFromPremise(premise);
return (LoadCarrierType.SLC == hu.getLoadCarrierType() ? getSLCCost(setId, destination, hu, hu.getLoadCarrierType(), addRepackingAndDisposalCost) : getLLCCost(setId, destination, hu, hu.getLoadCarrierType(), addRepackingAndDisposalCost)); return (LoadCarrierType.SLC == hu.getLoadCarrierType() ? getSLCCost(setId, premise, destination, hu, hu.getLoadCarrierType(), addRepackingAndDisposalCost, containerCalculationResult) : getLLCCost(setId, premise, destination, hu, hu.getLoadCarrierType(), addRepackingAndDisposalCost, containerCalculationResult));
} }
private HandlingResult getSLCCost(Integer setId, Destination destination, PackagingDimension hu, LoadCarrierType loadCarrierType, boolean addRepackingAndDisposalCost) { private HandlingResult getSLCCost(Integer setId, Premise premise, Destination destination, PackagingDimension hu, LoadCarrierType loadCarrierType, boolean addRepackingAndDisposalCost, ContainerCalculationResult containerCalculationResult) {
var destinationHandling = destination.getHandlingCost(); var destinationHandling = destination.getHandlingCost();
var destinationDisposal = destination.getDisposalCost(); var destinationDisposal = destination.getDisposalCost();
@ -77,7 +78,7 @@ public class HandlingCostCalculationService {
} }
private HandlingResult getLLCCost(Integer setId, Destination destination, PackagingDimension hu, LoadCarrierType type, boolean addRepackingAndDisposalCost) { private HandlingResult getLLCCost(Integer setId, Premise premise, Destination destination, PackagingDimension hu, LoadCarrierType type, boolean addRepackingAndDisposalCost, ContainerCalculationResult containerCalculationResult) {
var destinationHandling = destination.getHandlingCost(); var destinationHandling = destination.getHandlingCost();
var destinationDisposal = destination.getDisposalCost(); var destinationDisposal = destination.getDisposalCost();
@ -93,7 +94,7 @@ public class HandlingCostCalculationService {
BigDecimal booking = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.BOOKING, setId).orElseThrow().getCurrentValue())); BigDecimal booking = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.BOOKING, setId).orElseThrow().getCurrentValue()));
var annualRepacking = getRepackingCost(setId, hu, type, addRepackingAndDisposalCost, destinationRepacking).multiply(wageFactor).multiply( huAnnualAmount); var annualRepacking = getRepackingCost(setId, hu, type, addRepackingAndDisposalCost, destinationRepacking).multiply(wageFactor).multiply( huAnnualAmount);
var annualHandling = ((handling.add(dispatch).add(release)).multiply(wageFactor).multiply(huAnnualAmount)).add(booking.multiply(BigDecimal.valueOf(shippingFrequencyCalculationService.doCalculation(setId, huAnnualAmount.doubleValue())))); var annualHandling = ((handling.add(dispatch).add(release)).multiply(wageFactor).multiply(huAnnualAmount)).add(booking.multiply(BigDecimal.valueOf(shippingFrequencyCalculationService.doCalculation(setId, huAnnualAmount.doubleValue(), containerCalculationResult.getHuPerContainer(), !premise.getHuMixable()))));
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

@ -1,5 +1,6 @@
package de.avatic.lcc.service.calculation.execution.steps; package de.avatic.lcc.service.calculation.execution.steps;
import de.avatic.lcc.model.calculation.ContainerCalculationResult;
import de.avatic.lcc.model.calculation.InventoryCostResult; import de.avatic.lcc.model.calculation.InventoryCostResult;
import de.avatic.lcc.model.db.packaging.PackagingDimension; import de.avatic.lcc.model.db.packaging.PackagingDimension;
import de.avatic.lcc.model.db.premises.Premise; import de.avatic.lcc.model.db.premises.Premise;
@ -30,7 +31,7 @@ public class InventoryCostCalculationService {
this.premiseToHuService = premiseToHuService; this.premiseToHuService = premiseToHuService;
} }
public InventoryCostResult doCalculation(Integer setId, Premise premise, Destination destination, BigDecimal leadTime) { public InventoryCostResult doCalculation(Integer setId, Premise premise, Destination destination, BigDecimal leadTime, ContainerCalculationResult containerCalculationResult) {
var fcaFee = BigDecimal.ZERO; var fcaFee = BigDecimal.ZERO;
@ -53,7 +54,7 @@ public class InventoryCostCalculationService {
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(setId, huAnnualAmount),1)), 10, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(.5))); var opStock = (annualAmount.divide(BigDecimal.valueOf(Math.max(shippingFrequencyCalculationService.doCalculation(setId, huAnnualAmount, containerCalculationResult.getHuPerContainer(), !premise.getHuMixable()),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);

View file

@ -97,7 +97,7 @@ public class RouteSectionCostCalculationService {
BigDecimal.valueOf(containerCalculation.getTotalUtilizationByVolume()), BigDecimal.valueOf(containerCalculation.getTotalUtilizationByVolume()),
BigDecimal.valueOf(containerCalculation.getHuUtilizationByWeight()), BigDecimal.valueOf(containerCalculation.getHuUtilizationByWeight()),
utilization, utilization,
shippingFrequencyCalculationService.doCalculation(setId, huAnnualAmount.doubleValue()), shippingFrequencyCalculationService.doCalculation(setId, huAnnualAmount.doubleValue(), containerCalculation.getHuPerContainer(), !premise.getHuMixable()),
huAnnualAmount.doubleValue(), huAnnualAmount.doubleValue(),
containerCalculation); containerCalculation);
@ -183,7 +183,7 @@ public class RouteSectionCostCalculationService {
BigDecimal.valueOf(containerCalculation.getTotalUtilizationByVolume()), BigDecimal.valueOf(containerCalculation.getTotalUtilizationByVolume()),
BigDecimal.valueOf(containerCalculation.getTotalUtilizationByWeight()), BigDecimal.valueOf(containerCalculation.getTotalUtilizationByWeight()),
utilization, utilization,
shippingFrequencyCalculationService.doCalculation(setId, huAnnualAmount.doubleValue()), shippingFrequencyCalculationService.doCalculation(setId, huAnnualAmount.doubleValue(), containerCalculation.getHuPerContainer(), !premise.getHuMixable()),
huAnnualAmount.doubleValue(), huAnnualAmount.doubleValue(),
containerCalculation); containerCalculation);
@ -243,7 +243,7 @@ public class RouteSectionCostCalculationService {
double huPerContainer = annualHuAmount / shippingFrequency; double huPerContainer = annualHuAmount / shippingFrequency;
// if the shipping frequency is bigger than the annual amount the "totalXXUtilization" cannot be used. // if the shipping frequency is bigger than the annual amount the "totalXXUtilization" cannot be used.
if(huPerContainer < (containerCalculationResult.getHuUnitCount() * containerCalculationResult.getLayer())) { if(huPerContainer < (containerCalculationResult.getHuPerContainer())) {
totalVolumeUtilization = BigDecimal.valueOf(huPerContainer * containerCalculationResult.getHu().getVolume(DimensionUnit.M)).divide(BigDecimal.valueOf(containerCalculationResult.getContainerType().getVolume()), 20, RoundingMode.HALF_UP); totalVolumeUtilization = BigDecimal.valueOf(huPerContainer * containerCalculationResult.getHu().getVolume(DimensionUnit.M)).divide(BigDecimal.valueOf(containerCalculationResult.getContainerType().getVolume()), 20, RoundingMode.HALF_UP);
totalWeightUtilization = BigDecimal.valueOf(huPerContainer * containerCalculationResult.getHu().getWeight(WeightUnit.KG)).divide(BigDecimal.valueOf(containerCalculationResult.getMaxContainerWeight()), 20, RoundingMode.HALF_UP); totalWeightUtilization = BigDecimal.valueOf(huPerContainer * containerCalculationResult.getHu().getWeight(WeightUnit.KG)).divide(BigDecimal.valueOf(containerCalculationResult.getMaxContainerWeight()), 20, RoundingMode.HALF_UP);

View file

@ -13,10 +13,16 @@ public class ShippingFrequencyCalculationService {
this.propertyRepository = propertyRepository; this.propertyRepository = propertyRepository;
} }
public int doCalculation(Integer setId, int huAnnualAmount) { public int doCalculation(Integer setId, int huAnnualAmount, int maxHuPerContainer, boolean fillContainer) {
var minAnnualFrequency = Integer.parseInt(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.FREQ_MIN, setId).orElseThrow().getCurrentValue()); var minAnnualFrequency = Integer.parseInt(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.FREQ_MIN, setId).orElseThrow().getCurrentValue());
var maxAnnualFrequency = Integer.parseInt(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.FREQ_MAX, setId).orElseThrow().getCurrentValue()); var maxAnnualFrequency = Integer.parseInt(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.FREQ_MAX, setId).orElseThrow().getCurrentValue());
var fullContainers = huAnnualAmount / maxHuPerContainer;
if(fillContainer && huAnnualAmount > maxAnnualFrequency)
return fullContainers;
if (huAnnualAmount > maxAnnualFrequency) if (huAnnualAmount > maxAnnualFrequency)
return maxAnnualFrequency; return maxAnnualFrequency;
@ -24,10 +30,15 @@ public class ShippingFrequencyCalculationService {
} }
public double doCalculation(Integer setId, double huAnnualAmount) { public double doCalculation(Integer setId, double huAnnualAmount, int maxHuPerContainer, boolean fillContainer) {
int minAnnualFrequency = Integer.parseInt(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.FREQ_MIN, setId).orElseThrow().getCurrentValue()); int minAnnualFrequency = Integer.parseInt(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.FREQ_MIN, setId).orElseThrow().getCurrentValue());
int maxAnnualFrequency = Integer.parseInt(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.FREQ_MAX, setId).orElseThrow().getCurrentValue()); int maxAnnualFrequency = Integer.parseInt(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.FREQ_MAX, setId).orElseThrow().getCurrentValue());
var fullContainers = huAnnualAmount / maxHuPerContainer;
if(fillContainer && huAnnualAmount > (double) maxAnnualFrequency)
return fullContainers;
if (huAnnualAmount > (double) maxAnnualFrequency) if (huAnnualAmount > (double) maxAnnualFrequency)
return maxAnnualFrequency; return maxAnnualFrequency;