From 4f0eeff16b4d15c9bfd6dccb4c68224896450458 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 8 Dec 2025 20:01:05 +0100 Subject: [PATCH 01/46] Refine exception message handling for missing transport rates to support nullable end dates. --- .../precalculation/PreCalculationCheckService.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/avatic/lcc/service/precalculation/PreCalculationCheckService.java b/src/main/java/de/avatic/lcc/service/precalculation/PreCalculationCheckService.java index f0d3a9f..4099ab2 100644 --- a/src/main/java/de/avatic/lcc/service/precalculation/PreCalculationCheckService.java +++ b/src/main/java/de/avatic/lcc/service/precalculation/PreCalculationCheckService.java @@ -175,16 +175,20 @@ public class PreCalculationCheckService { 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 (rate.isEmpty()) { + var toText = period.getEndDate() == null ? "" : " to " + period.getEndDate().format(DateTimeFormatter.ISO_DATE); + throw new PremiseValidationError("The transport rates for the period " + period.getStartDate().format(DateTimeFormatter.ISO_DATE) + toText + " 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()); + if (rate.isEmpty()) { + var toText = period.getEndDate() == null ? "" : " to " + period.getEndDate().format(DateTimeFormatter.ISO_DATE); + throw new PremiseValidationError("The transport rates for the period " + period.getStartDate().format(DateTimeFormatter.ISO_DATE) + toText + " are insufficient to perform the calculation for route segment" + fromRouteNode.get().getExternalMappingId() + " to " + toRouteNode.get().getExternalMappingId()); + } } From 0edcfb5258b0e45c1292733c5f4aae419aabd228 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 9 Dec 2025 10:55:01 +0100 Subject: [PATCH 02/46] Refactor `doPrecheck` method to improve parameter handling and enhance error messages with calculation date support. --- .../PreCalculationCheckService.java | 68 +++++++++---------- 1 file changed, 31 insertions(+), 37 deletions(-) diff --git a/src/main/java/de/avatic/lcc/service/precalculation/PreCalculationCheckService.java b/src/main/java/de/avatic/lcc/service/precalculation/PreCalculationCheckService.java index 4099ab2..972762f 100644 --- a/src/main/java/de/avatic/lcc/service/precalculation/PreCalculationCheckService.java +++ b/src/main/java/de/avatic/lcc/service/precalculation/PreCalculationCheckService.java @@ -6,6 +6,7 @@ import de.avatic.lcc.model.db.nodes.Node; import de.avatic.lcc.model.db.premises.Premise; import de.avatic.lcc.model.db.premises.route.Destination; import de.avatic.lcc.model.db.premises.route.Route; +import de.avatic.lcc.model.db.premises.route.RouteNode; import de.avatic.lcc.model.db.premises.route.RouteSection; import de.avatic.lcc.model.db.properties.PropertySet; import de.avatic.lcc.model.db.properties.SystemPropertyMappingId; @@ -28,6 +29,7 @@ import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.math.BigDecimal; +import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.List; @@ -75,8 +77,11 @@ public class PreCalculationCheckService { this.eUTaxationResolverService = eUTaxationResolverService; } - @Async("calculationExecutor") - public CompletableFuture doPrecheck(Integer premiseId, Integer setId, Integer periodId) { + public void doPrecheck(Integer premiseId, Optional set, Optional period) { + doPrecheck(premiseId, set, period, LocalDate.now()); + } + + public void doPrecheck(Integer premiseId, Optional set, Optional period, LocalDate date) { var premise = premiseRepository.getPremiseById(premiseId).orElseThrow(); supplierCheck(premise); @@ -93,7 +98,6 @@ public class PreCalculationCheckService { throw new PremiseValidationError("No destination defined yet, please add at least one destination."); } - for (Destination destination : destinations) { var node = nodeRepository.getByDestinationId(destination.getId()).orElseThrow(); @@ -117,24 +121,16 @@ public class PreCalculationCheckService { 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); + periodCheck(period.orElse(null), set.orElse(null), date); routes.stream().filter(Route::getSelected).findAny().ifPresent(r -> { var sections = routeSectionRepository.getByRouteId(r.getId()); - routeCheck(sections, period); + routeCheck(sections, period.orElseThrow(), date); }); - - } - - return CompletableFuture.completedFuture(null); } - private void periodCheck(ValidityPeriod period, PropertySet set) { - + private void periodCheck(ValidityPeriod period, PropertySet set, LocalDate calculationDate) { if (set == null) throw new PremiseValidationError("There are no system properties for the given date. Please contact your administrator."); @@ -148,21 +144,24 @@ public class PreCalculationCheckService { if (ValidityPeriodState.VALID != set.getState() && ValidityPeriodState.EXPIRED != period.getState()) throw new PremiseValidationError("There are no valid system properties for the given date. Please contact your administrator."); - //TODO: sicherstellen, dass die valid days für den zeitpunkt galten zu dem die valid period galt (wenn rückwirkend gerechnet wird) - var validDays = propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.VALID_DAYS, set.getId()); - var renewals = period.getRenewals(); - if (validDays.isEmpty()) - throw new PremiseValidationError("There are no valid days property. Please contact your administrator"); + if (calculationDate == null) { - var validDaysInt = Integer.parseInt(validDays.get().getCurrentValue()); + var validDays = propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.VALID_DAYS, set.getId()); + var renewals = period.getRenewals(); - if (!period.getStartDate().plusDays((((long) validDaysInt * renewals) + validDaysInt)).isAfter(LocalDateTime.now())) - throw new PremiseValidationError("There are no valid rates for the given date. Please contact your administrator."); + if (validDays.isEmpty()) + throw new PremiseValidationError("There are no valid days property. Please contact your administrator"); + + var validDaysInt = Integer.parseInt(validDays.get().getCurrentValue()); + + if (!period.getStartDate().plusDays((((long) validDaysInt * renewals) + validDaysInt)).isAfter(LocalDateTime.now())) + throw new PremiseValidationError("There are no valid rates for the given date. Please contact your administrator."); + } } - private void routeCheck(List sections, ValidityPeriod period) { + private void routeCheck(List sections, ValidityPeriod period, LocalDate calculationDate) { sections.forEach(section -> { var fromRouteNode = routeNodeRepository.getFromNodeBySectionId(section.getId()); @@ -173,27 +172,22 @@ public class PreCalculationCheckService { if (RateType.MATRIX == section.getRateType()) { var rate = matrixRateRepository.getByCountryIds(fromRouteNode.get().getCountryId(), toRouteNode.get().getCountryId(), period.getId()); - - - if (rate.isEmpty()) { - var toText = period.getEndDate() == null ? "" : " to " + period.getEndDate().format(DateTimeFormatter.ISO_DATE); - throw new PremiseValidationError("The transport rates for the period " + period.getStartDate().format(DateTimeFormatter.ISO_DATE) + toText + " are insufficient to perform the calculation for route segment" + fromRouteNode.get().getExternalMappingId() + " to " + toRouteNode.get().getExternalMappingId()); - } - + constructRouteSectionError(calculationDate, fromRouteNode.get(), toRouteNode.get(), rate.isEmpty()); } if (RateType.CONTAINER == section.getRateType()) { var rate = containerRateRepository.findRoute(fromRouteNode.get().getNodeId(), toRouteNode.get().getNodeId(), period.getId(), section.getTransportType()); - - if (rate.isEmpty()) { - var toText = period.getEndDate() == null ? "" : " to " + period.getEndDate().format(DateTimeFormatter.ISO_DATE); - throw new PremiseValidationError("The transport rates for the period " + period.getStartDate().format(DateTimeFormatter.ISO_DATE) + toText + " are insufficient to perform the calculation for route segment" + fromRouteNode.get().getExternalMappingId() + " to " + toRouteNode.get().getExternalMappingId()); - } - + constructRouteSectionError(calculationDate, fromRouteNode.get(), toRouteNode.get(), rate.isEmpty()); } - }); + } + private void constructRouteSectionError(LocalDate calculationDate, RouteNode fromRouteNode, RouteNode toRouteNode, boolean empty) { + if (empty) { + var dateStr = calculationDate == null ? "" : String.format("on given date %s", calculationDate.format(DateTimeFormatter.ofPattern("dd.MM.yyyy"))); + var errStr = String.format("Missing transport rate for route section %s to %s %s. Please contact your admin.", fromRouteNode.getExternalMappingId(), toRouteNode.getExternalMappingId(), dateStr); + throw new PremiseValidationError(errStr); + } } private void destinationCheck(Destination destination, Node node) { From 27166e4b00f5a3f0ae8ca913f189279d53212b63 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 9 Dec 2025 10:59:35 +0100 Subject: [PATCH 03/46] Added user friendly error messages --- .../PreCalculationCheckService.java | 90 ++++++++++--------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/src/main/java/de/avatic/lcc/service/precalculation/PreCalculationCheckService.java b/src/main/java/de/avatic/lcc/service/precalculation/PreCalculationCheckService.java index 972762f..5cc51b7 100644 --- a/src/main/java/de/avatic/lcc/service/precalculation/PreCalculationCheckService.java +++ b/src/main/java/de/avatic/lcc/service/precalculation/PreCalculationCheckService.java @@ -81,6 +81,7 @@ public class PreCalculationCheckService { doPrecheck(premiseId, set, period, LocalDate.now()); } + public void doPrecheck(Integer premiseId, Optional set, Optional period, LocalDate date) { var premise = premiseRepository.getPremiseById(premiseId).orElseThrow(); @@ -95,7 +96,7 @@ public class PreCalculationCheckService { var destinations = destinationRepository.getByPremiseId(premiseId); if (destinations == null || destinations.isEmpty()) { - throw new PremiseValidationError("No destination defined yet, please add at least one destination."); + throw new PremiseValidationError("Please add at least one destination to continue"); } for (Destination destination : destinations) { @@ -108,17 +109,17 @@ public class PreCalculationCheckService { if (routes.isEmpty() && destination.getD2d() == false) - throw new PremiseValidationError("No standard route available for destination " + node.getName() + ". Please use individual rate or contact your administrator."); + throw new PremiseValidationError(String.format("No standard route found for %s - try using an individual rate instead", node.getName())); if (routes.stream().noneMatch(Route::getSelected) && destination.getD2d() == false) - throw new PremiseValidationError("No route selected for destination " + node.getName()); + throw new PremiseValidationError(String.format("Please select a route for %s", node.getName())); if (destination.getD2d() && (destination.getRateD2d() == null || destination.getRateD2d().compareTo(BigDecimal.ZERO) == 0)) { - throw new PremiseValidationError("Door-2-door rate not entered or zero."); + throw new PremiseValidationError("Please enter a door-to-door rate greater than zero"); } if (destination.getD2d() && (destination.getLeadTimeD2d() == null || destination.getLeadTimeD2d() == 0)) { - throw new PremiseValidationError("Door-2-door lead time not entered or zero."); + throw new PremiseValidationError("Please enter a door-to-door lead time"); } periodCheck(period.orElse(null), set.orElse(null), date); @@ -133,16 +134,16 @@ public class PreCalculationCheckService { private void periodCheck(ValidityPeriod period, PropertySet set, LocalDate calculationDate) { if (set == null) - throw new PremiseValidationError("There are no system properties for the given date. Please contact your administrator."); + throw new PremiseValidationError("No system data available for this date - please contact your administrator"); if (period == null) - throw new PremiseValidationError("There are no rates for the given date. Please contact your administrator."); + throw new PremiseValidationError("No rates available for this date - please contact your administrator"); if (ValidityPeriodState.VALID != period.getState() && ValidityPeriodState.EXPIRED != period.getState()) - throw new PremiseValidationError("There are no valid rates for the given date. Please contact your administrator."); + throw new PremiseValidationError("Rates for this date aren't valid yet - please contact your administrator"); if (ValidityPeriodState.VALID != set.getState() && ValidityPeriodState.EXPIRED != period.getState()) - throw new PremiseValidationError("There are no valid system properties for the given date. Please contact your administrator."); + throw new PremiseValidationError("System properties for this date aren't valid yet - please contact your administrator"); if (calculationDate == null) { @@ -151,12 +152,12 @@ public class PreCalculationCheckService { var renewals = period.getRenewals(); if (validDays.isEmpty()) - throw new PremiseValidationError("There are no valid days property. Please contact your administrator"); + throw new PremiseValidationError("Missing configuration - please contact your administrator"); var validDaysInt = Integer.parseInt(validDays.get().getCurrentValue()); if (!period.getStartDate().plusDays((((long) validDaysInt * renewals) + validDaysInt)).isAfter(LocalDateTime.now())) - throw new PremiseValidationError("There are no valid rates for the given date. Please contact your administrator."); + throw new PremiseValidationError("Rates for this date aren't valid yet - please contact your administrator"); } } @@ -168,7 +169,7 @@ public class PreCalculationCheckService { var toRouteNode = routeNodeRepository.getToNodeBySectionId(section.getId()); if (fromRouteNode.isEmpty() || toRouteNode.isEmpty()) - throw new PremiseValidationError("Error in route. Please contact your administrator."); + throw new PremiseValidationError("Route configuration issue - please contact your administrator"); if (RateType.MATRIX == section.getRateType()) { var rate = matrixRateRepository.getByCountryIds(fromRouteNode.get().getCountryId(), toRouteNode.get().getCountryId(), period.getId()); @@ -184,8 +185,11 @@ public class PreCalculationCheckService { private void constructRouteSectionError(LocalDate calculationDate, RouteNode fromRouteNode, RouteNode toRouteNode, boolean empty) { if (empty) { - var dateStr = calculationDate == null ? "" : String.format("on given date %s", calculationDate.format(DateTimeFormatter.ofPattern("dd.MM.yyyy"))); - var errStr = String.format("Missing transport rate for route section %s to %s %s. Please contact your admin.", fromRouteNode.getExternalMappingId(), toRouteNode.getExternalMappingId(), dateStr); + var dateStr = calculationDate == null ? "" : String.format("on %s", calculationDate.format(DateTimeFormatter.ofPattern("dd.MM.yyyy"))); + var errStr = String.format("Transport rate missing for %s to %s %s - please contact your administrator", + fromRouteNode.getExternalMappingId(), + toRouteNode.getExternalMappingId(), + dateStr); throw new PremiseValidationError(errStr); } } @@ -193,39 +197,39 @@ public class PreCalculationCheckService { private void destinationCheck(Destination destination, Node node) { if (destination.getAnnualAmount() == null || destination.getAnnualAmount() == 0) - throw new PremiseValidationError("In destination " + node.getName() + ": annual quantity must be greater than zero."); + throw new PremiseValidationError(String.format("Annual quantity for %s must be greater than zero", node.getName())); if (destination.getD2d() == null) - throw new PremiseValidationError("In destination " + node.getName() + ": Door-2-Door flag is missing. Please contact administrator."); + throw new PremiseValidationError(String.format("Something's missing for %s - please contact your administrator", node.getName())); if (destination.getD2d() == true) { if (destination.getRateD2d() == null || destination.getRateD2d().compareTo(BigDecimal.ZERO) == 0) { - throw new PremiseValidationError("In destination " + node.getName() + ": Door-2-door rate not entered or zero."); + throw new PremiseValidationError(String.format("Door-to-door rate for %s needs to be greater than zero", node.getName())); } if (destination.getLeadTimeD2d() == null || destination.getLeadTimeD2d() == 0) { - throw new PremiseValidationError("In destination " + node.getName() + ": Door-2-Door lead time not entered or zero."); + throw new PremiseValidationError(String.format("Please set a lead time for door-to-door delivery to %s", node.getName())); } } if (destination.getCountryId() == null || destination.getCountryId() == 0) { - throw new PremiseValidationError("In destination " + node.getName() + ": destination country ID not set. Please contact your administrator."); + throw new PremiseValidationError(String.format("Configuration issue with %s - please contact your administrator", node.getName())); } if (destination.getGeoLat() == null || destination.getGeoLng() == null) { - throw new PremiseValidationError("In destination " + node.getName() + ": destination geo location not set. Please contact your administrator."); + throw new PremiseValidationError(String.format("Location data missing for %s - please contact your administrator", node.getName())); } if (destination.getDisposalCost() != null && destination.getDisposalCost().compareTo(BigDecimal.ZERO) < 0) { - throw new PremiseValidationError("In destination " + node.getName() + ": disposal costs are not set or entered value is less than zero."); + throw new PremiseValidationError(String.format("Disposal costs for %s can't be negative", node.getName())); } if (destination.getHandlingCost() != null && destination.getHandlingCost().compareTo(BigDecimal.ZERO) < 0) { - throw new PremiseValidationError("In destination " + node.getName() + ": handling costs are not set or entered value is less than zero."); + throw new PremiseValidationError(String.format("Handling costs for %s can't be negative", node.getName())); } if (destination.getRepackingCost() != null && destination.getRepackingCost().compareTo(BigDecimal.ZERO) < 0) { - throw new PremiseValidationError("In destination " + node.getName() + ": repackaging costs are not set or entered value is less than zero."); + throw new PremiseValidationError(String.format("Repackaging costs for %s can't be negative", node.getName())); } } @@ -233,22 +237,22 @@ public class PreCalculationCheckService { private void supplierCheck(Premise premise) { if (premise.getSupplierNodeId() == null && premise.getUserSupplierNodeId() == null) - throw new PremiseValidationError("Supplier node not set. Please contact administrator"); + throw new PremiseValidationError("Supplier information is missing - please contact your administrator"); } private void priceCheck(Premise premise) { if (premise.getMaterialCost() == null || premise.getMaterialCost().compareTo(BigDecimal.ZERO) == 0) { - throw new PremiseValidationError("MEK_A not entered or zero."); + throw new PremiseValidationError("Please enter a material cost (MEK_A) greater than zero"); } if (premise.getOverseaShare() == null) { - throw new PremiseValidationError("Oversea share not entered."); + throw new PremiseValidationError("Please enter the overseas share"); } if (premise.getFcaEnabled() == null) { - throw new PremiseValidationError("FCA fee not set. Please contact administrator"); + throw new PremiseValidationError("FCA configuration missing - please contact your administrator"); } } @@ -256,43 +260,43 @@ public class PreCalculationCheckService { private void packagingCheck(Premise premise) { if (premise.getHuMixable() == null) { - throw new PremiseValidationError("Mixable not set. Please contact administrator."); + throw new PremiseValidationError("Packaging configuration incomplete - please contact your administrator"); } if (premise.getHuStackable() == null) { - throw new PremiseValidationError("Stackable not set. Please contact administrator."); + throw new PremiseValidationError("Packaging configuration incomplete - please contact your administrator"); } if (premise.getHuStackable() == false && premise.getHuMixable() == true) { - throw new PremiseValidationError("Stackable cannot be false, when mixable is true."); + throw new PremiseValidationError("If packaging is mixable, it must also be stackable"); } if (premise.getIndividualHuLength() == null || premise.getIndividualHuLength() == 0) { - throw new PremiseValidationError("Packaging length not entered or zero."); + throw new PremiseValidationError("Please enter packaging length"); } if (premise.getIndividualHuWidth() == null || premise.getIndividualHuWidth() == 0) { - throw new PremiseValidationError("Packaging width not entered or zero."); + throw new PremiseValidationError("Please enter packaging width"); } if (premise.getIndividualHuHeight() == null || premise.getIndividualHuHeight() == 0) { - throw new PremiseValidationError("Packaging height not entered or zero."); + throw new PremiseValidationError("Please enter packaging height"); } if (premise.getIndividualHuWeight() == null || premise.getIndividualHuWeight() == 0) { - throw new PremiseValidationError("Packaging weight not entered or zero"); + throw new PremiseValidationError("Please enter packaging weight"); } if (premise.getHuUnitCount() == null || premise.getHuUnitCount() == 0) { - throw new PremiseValidationError("Packaging unit count not entered or zero."); + throw new PremiseValidationError("Please enter the number of units per package"); } if (premise.getHuDisplayedWeightUnit() == null) { - throw new PremiseValidationError("Packaging weight unit not set. Please contact administrator."); + throw new PremiseValidationError("Weight unit configuration missing - please contact your administrator"); } if (premise.getHuDisplayedDimensionUnit() == null) { - throw new PremiseValidationError("Packaging dimension unit not set. Please contact administrator."); + throw new PremiseValidationError("Dimension unit configuration missing - please contact your administrator"); } var hu = dimensionTransformer.toDimensionEntity(premise).withTolerance(DIMENSION_TOLERANCE); @@ -301,21 +305,21 @@ public class PreCalculationCheckService { Optional feuLoad = propertyService.getProperty(SystemPropertyMappingId.TEU_LOAD); if (teuLoad.isEmpty() || feuLoad.isEmpty()) - throw new PremiseValidationError("System properties not properly configured. Please contact your administrator."); + throw new PremiseValidationError("System configuration incomplete - please contact your administrator"); if (WeightUnit.KG.convertFromG(hu.getWeight()) > teuLoad.get() && hu.getWeight() > feuLoad.get()) - throw new PremiseValidationError("HU weight exceeds maximum container weight load (" + Math.max(teuLoad.get(), feuLoad.get()) + " kg). Review entered weight and selected weight unit [g, kg, t]."); + throw new PremiseValidationError(String.format("Package weight exceeds %d kg - please check your weight and unit", Math.max(teuLoad.get(), feuLoad.get()))); var teuFitsXY = (hu.getLength() < ContainerType.TEU.getLength() && hu.getWidth() < ContainerType.TEU.getWidth()); var teuFitsYX = (hu.getWidth() < ContainerType.TEU.getLength() && hu.getLength() < ContainerType.TEU.getWidth()); if (!teuFitsYX && !teuFitsXY) { - throw new PremiseValidationError("HU dimensions too large. Review entered length, width, height and selected dimension unit [mm, cm, m]."); + throw new PremiseValidationError("Package dimensions are too large - please check your measurements and unit"); } 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("Package dimensions are too small - please check your measurements and unit"); } } @@ -332,8 +336,8 @@ public class PreCalculationCheckService { // } if (premise.getTariffRate() == null) { - throw new PremiseValidationError("Tariff rate not entered."); + throw new PremiseValidationError("Please enter a tariff rate"); } } -} +} \ No newline at end of file From 8763efd8fce511626a297e15a6cae4bc939ba91e Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 9 Dec 2025 11:38:32 +0100 Subject: [PATCH 04/46] added supplier and part number info to error message --- .../PreCalculationCheckService.java | 137 +++++++++--------- .../internalerror/PremiseValidationError.java | 4 + 2 files changed, 73 insertions(+), 68 deletions(-) diff --git a/src/main/java/de/avatic/lcc/service/precalculation/PreCalculationCheckService.java b/src/main/java/de/avatic/lcc/service/precalculation/PreCalculationCheckService.java index 5cc51b7..85039ce 100644 --- a/src/main/java/de/avatic/lcc/service/precalculation/PreCalculationCheckService.java +++ b/src/main/java/de/avatic/lcc/service/precalculation/PreCalculationCheckService.java @@ -13,19 +13,16 @@ import de.avatic.lcc.model.db.properties.SystemPropertyMappingId; import de.avatic.lcc.model.db.rates.ValidityPeriod; import de.avatic.lcc.model.db.rates.ValidityPeriodState; import de.avatic.lcc.model.db.utils.WeightUnit; +import de.avatic.lcc.repositories.MaterialRepository; import de.avatic.lcc.repositories.NodeRepository; import de.avatic.lcc.repositories.premise.*; import de.avatic.lcc.repositories.properties.PropertyRepository; -import de.avatic.lcc.repositories.properties.PropertySetRepository; import de.avatic.lcc.repositories.rates.ContainerRateRepository; import de.avatic.lcc.repositories.rates.MatrixRateRepository; -import de.avatic.lcc.repositories.rates.ValidityPeriodRepository; +import de.avatic.lcc.repositories.users.UserNodeRepository; import de.avatic.lcc.service.access.PropertyService; -import de.avatic.lcc.service.api.CustomApiService; -import de.avatic.lcc.service.api.TaxationResolverService; import de.avatic.lcc.service.transformer.generic.DimensionTransformer; import de.avatic.lcc.util.exception.internalerror.PremiseValidationError; -import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.math.BigDecimal; @@ -34,7 +31,6 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Optional; -import java.util.concurrent.CompletableFuture; @Service public class PreCalculationCheckService { @@ -42,7 +38,6 @@ public class PreCalculationCheckService { private static final double DIMENSION_TOLERANCE = 0.02; private final PremiseRepository premiseRepository; - private final CustomApiService customApiService; private final DestinationRepository destinationRepository; private final RouteRepository routeRepository; private final NodeRepository nodeRepository; @@ -53,14 +48,12 @@ public class PreCalculationCheckService { private final RouteNodeRepository routeNodeRepository; private final MatrixRateRepository matrixRateRepository; private final ContainerRateRepository containerRateRepository; - private final ValidityPeriodRepository validityPeriodRepository; - private final PropertySetRepository propertySetRepository; private final PropertyRepository propertyRepository; - private final TaxationResolverService eUTaxationResolverService; + private final MaterialRepository materialRepository; + private final UserNodeRepository userNodeRepository; - 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, PropertyRepository propertyRepository, TaxationResolverService eUTaxationResolverService) { + public PreCalculationCheckService(PremiseRepository premiseRepository, DestinationRepository destinationRepository, RouteRepository routeRepository, NodeRepository nodeRepository, DimensionTransformer dimensionTransformer, PropertyService propertyService, RouteSectionRepository routeSectionRepository, RouteNodeRepository routeNodeRepository, MatrixRateRepository matrixRateRepository, ContainerRateRepository containerRateRepository, PropertyRepository propertyRepository, MaterialRepository materialRepository, UserNodeRepository userNodeRepository) { this.premiseRepository = premiseRepository; - this.customApiService = customApiService; this.destinationRepository = destinationRepository; this.routeRepository = routeRepository; this.nodeRepository = nodeRepository; @@ -71,10 +64,9 @@ public class PreCalculationCheckService { this.routeNodeRepository = routeNodeRepository; this.matrixRateRepository = matrixRateRepository; this.containerRateRepository = containerRateRepository; - this.validityPeriodRepository = validityPeriodRepository; - this.propertySetRepository = propertySetRepository; this.propertyRepository = propertyRepository; - this.eUTaxationResolverService = eUTaxationResolverService; + this.materialRepository = materialRepository; + this.userNodeRepository = userNodeRepository; } public void doPrecheck(Integer premiseId, Optional set, Optional period) { @@ -87,54 +79,63 @@ public class PreCalculationCheckService { supplierCheck(premise); - materialCheck(premise); + var material = materialRepository.getById(premise.getMaterialId()); + var supplier = premise.getSupplierNodeId() == null ? userNodeRepository.getById(premise.getUserSupplierNodeId()) : nodeRepository.getById(premise.getSupplierNodeId()); - packagingCheck(premise); + if(material.isEmpty() || supplier.isEmpty()) + throw new PremiseValidationError("No material or supplier - please contact your administrator"); - priceCheck(premise); + var partNumber = material.get().getPartNumber(); + var supplierName = supplier.get().getName(); + + materialCheck(premise, supplierName, partNumber); + + packagingCheck(premise, supplierName, partNumber); + + priceCheck(premise, supplierName, partNumber); var destinations = destinationRepository.getByPremiseId(premiseId); if (destinations == null || destinations.isEmpty()) { - throw new PremiseValidationError("Please add at least one destination to continue"); + throw new PremiseValidationError("Please add at least one destination to continue", supplierName, partNumber); } for (Destination destination : destinations) { var node = nodeRepository.getByDestinationId(destination.getId()).orElseThrow(); - destinationCheck(destination, node); + destinationCheck(destination, node, supplierName, partNumber); var routes = routeRepository.getByDestinationId(destination.getId()); if (routes.isEmpty() && destination.getD2d() == false) - throw new PremiseValidationError(String.format("No standard route found for %s - try using an individual rate instead", node.getName())); + throw new PremiseValidationError(String.format("No standard route found for %s - try using an individual rate instead", node.getName()), supplierName, partNumber); if (routes.stream().noneMatch(Route::getSelected) && destination.getD2d() == false) - throw new PremiseValidationError(String.format("Please select a route for %s", node.getName())); + throw new PremiseValidationError(String.format("Please select a route for %s", node.getName()), supplierName, partNumber); if (destination.getD2d() && (destination.getRateD2d() == null || destination.getRateD2d().compareTo(BigDecimal.ZERO) == 0)) { - throw new PremiseValidationError("Please enter a door-to-door rate greater than zero"); + throw new PremiseValidationError("Please enter a door-to-door rate greater than zero", supplierName, partNumber); } if (destination.getD2d() && (destination.getLeadTimeD2d() == null || destination.getLeadTimeD2d() == 0)) { - throw new PremiseValidationError("Please enter a door-to-door lead time"); + throw new PremiseValidationError("Please enter a door-to-door lead time", supplierName, partNumber); } - periodCheck(period.orElse(null), set.orElse(null), date); + periodCheck(period.orElse(null), set.orElse(null), date, supplierName, partNumber); routes.stream().filter(Route::getSelected).findAny().ifPresent(r -> { var sections = routeSectionRepository.getByRouteId(r.getId()); - routeCheck(sections, period.orElseThrow(), date); + routeCheck(sections, period.orElseThrow(), date, supplierName, partNumber); }); } } - private void periodCheck(ValidityPeriod period, PropertySet set, LocalDate calculationDate) { + private void periodCheck(ValidityPeriod period, PropertySet set, LocalDate calculationDate, String supplierName, String partNumber) { if (set == null) - throw new PremiseValidationError("No system data available for this date - please contact your administrator"); + throw new PremiseValidationError("No system configuration available for this date - please contact your administrator"); if (period == null) throw new PremiseValidationError("No rates available for this date - please contact your administrator"); @@ -152,7 +153,7 @@ public class PreCalculationCheckService { var renewals = period.getRenewals(); if (validDays.isEmpty()) - throw new PremiseValidationError("Missing configuration - please contact your administrator"); + throw new PremiseValidationError("Missing system configuration (VALID_DAYS) - please contact your administrator"); var validDaysInt = Integer.parseInt(validDays.get().getCurrentValue()); @@ -162,74 +163,74 @@ public class PreCalculationCheckService { } - private void routeCheck(List sections, ValidityPeriod period, LocalDate calculationDate) { + private void routeCheck(List sections, ValidityPeriod period, LocalDate calculationDate, String supplierName, String partNumber) { sections.forEach(section -> { var fromRouteNode = routeNodeRepository.getFromNodeBySectionId(section.getId()); var toRouteNode = routeNodeRepository.getToNodeBySectionId(section.getId()); if (fromRouteNode.isEmpty() || toRouteNode.isEmpty()) - throw new PremiseValidationError("Route configuration issue - please contact your administrator"); + throw new PremiseValidationError("Route configuration issue - please contact your administrator", supplierName, partNumber); if (RateType.MATRIX == section.getRateType()) { var rate = matrixRateRepository.getByCountryIds(fromRouteNode.get().getCountryId(), toRouteNode.get().getCountryId(), period.getId()); - constructRouteSectionError(calculationDate, fromRouteNode.get(), toRouteNode.get(), rate.isEmpty()); + constructRouteSectionError(calculationDate, fromRouteNode.get(), toRouteNode.get(), rate.isEmpty(), supplierName, partNumber); } if (RateType.CONTAINER == section.getRateType()) { var rate = containerRateRepository.findRoute(fromRouteNode.get().getNodeId(), toRouteNode.get().getNodeId(), period.getId(), section.getTransportType()); - constructRouteSectionError(calculationDate, fromRouteNode.get(), toRouteNode.get(), rate.isEmpty()); + constructRouteSectionError(calculationDate, fromRouteNode.get(), toRouteNode.get(), rate.isEmpty(), supplierName, partNumber); } }); } - private void constructRouteSectionError(LocalDate calculationDate, RouteNode fromRouteNode, RouteNode toRouteNode, boolean empty) { + private void constructRouteSectionError(LocalDate calculationDate, RouteNode fromRouteNode, RouteNode toRouteNode, boolean empty, String supplierName, String partNumber) { if (empty) { var dateStr = calculationDate == null ? "" : String.format("on %s", calculationDate.format(DateTimeFormatter.ofPattern("dd.MM.yyyy"))); var errStr = String.format("Transport rate missing for %s to %s %s - please contact your administrator", fromRouteNode.getExternalMappingId(), toRouteNode.getExternalMappingId(), dateStr); - throw new PremiseValidationError(errStr); + throw new PremiseValidationError(errStr, supplierName, partNumber); } } - private void destinationCheck(Destination destination, Node node) { + private void destinationCheck(Destination destination, Node node, String supplierName, String partNumber) { if (destination.getAnnualAmount() == null || destination.getAnnualAmount() == 0) - throw new PremiseValidationError(String.format("Annual quantity for %s must be greater than zero", node.getName())); + throw new PremiseValidationError(String.format("Annual quantity for %s must be greater than zero", node.getName()), supplierName, partNumber); if (destination.getD2d() == null) - throw new PremiseValidationError(String.format("Something's missing for %s - please contact your administrator", node.getName())); + throw new PremiseValidationError(String.format("Something's missing for %s - please contact your administrator", node.getName()), supplierName, partNumber); if (destination.getD2d() == true) { if (destination.getRateD2d() == null || destination.getRateD2d().compareTo(BigDecimal.ZERO) == 0) { - throw new PremiseValidationError(String.format("Door-to-door rate for %s needs to be greater than zero", node.getName())); + throw new PremiseValidationError(String.format("Door-to-door rate for %s needs to be greater than zero", node.getName()), supplierName, partNumber); } if (destination.getLeadTimeD2d() == null || destination.getLeadTimeD2d() == 0) { - throw new PremiseValidationError(String.format("Please set a lead time for door-to-door delivery to %s", node.getName())); + throw new PremiseValidationError(String.format("Please set a lead time for door-to-door delivery to %s", node.getName()), supplierName, partNumber); } } if (destination.getCountryId() == null || destination.getCountryId() == 0) { - throw new PremiseValidationError(String.format("Configuration issue with %s - please contact your administrator", node.getName())); + throw new PremiseValidationError(String.format("Configuration issue with %s - please contact your administrator", node.getName()), supplierName, partNumber); } if (destination.getGeoLat() == null || destination.getGeoLng() == null) { - throw new PremiseValidationError(String.format("Location data missing for %s - please contact your administrator", node.getName())); + throw new PremiseValidationError(String.format("Location data missing for %s - please contact your administrator", node.getName()), supplierName, partNumber); } if (destination.getDisposalCost() != null && destination.getDisposalCost().compareTo(BigDecimal.ZERO) < 0) { - throw new PremiseValidationError(String.format("Disposal costs for %s can't be negative", node.getName())); + throw new PremiseValidationError(String.format("Disposal costs for %s can't be negative", node.getName()), supplierName, partNumber); } if (destination.getHandlingCost() != null && destination.getHandlingCost().compareTo(BigDecimal.ZERO) < 0) { - throw new PremiseValidationError(String.format("Handling costs for %s can't be negative", node.getName())); + throw new PremiseValidationError(String.format("Handling costs for %s can't be negative", node.getName()), supplierName, partNumber); } if (destination.getRepackingCost() != null && destination.getRepackingCost().compareTo(BigDecimal.ZERO) < 0) { - throw new PremiseValidationError(String.format("Repackaging costs for %s can't be negative", node.getName())); + throw new PremiseValidationError(String.format("Repackaging costs for %s can't be negative", node.getName()), supplierName, partNumber); } } @@ -241,62 +242,62 @@ public class PreCalculationCheckService { } - private void priceCheck(Premise premise) { + private void priceCheck(Premise premise, String supplierName, String partNumber) { if (premise.getMaterialCost() == null || premise.getMaterialCost().compareTo(BigDecimal.ZERO) == 0) { - throw new PremiseValidationError("Please enter a material cost (MEK_A) greater than zero"); + throw new PremiseValidationError("Please enter a material cost (MEK_A) greater than zero", supplierName, partNumber); } if (premise.getOverseaShare() == null) { - throw new PremiseValidationError("Please enter the overseas share"); + throw new PremiseValidationError("Please enter the overseas share", supplierName, partNumber); } if (premise.getFcaEnabled() == null) { - throw new PremiseValidationError("FCA configuration missing - please contact your administrator"); + throw new PremiseValidationError("FCA configuration missing - please contact your administrator", supplierName, partNumber); } } - private void packagingCheck(Premise premise) { + private void packagingCheck(Premise premise, String supplierName, String partNumber) { if (premise.getHuMixable() == null) { - throw new PremiseValidationError("Packaging configuration incomplete - please contact your administrator"); + throw new PremiseValidationError("Packaging configuration incomplete - please contact your administrator", supplierName, partNumber); } if (premise.getHuStackable() == null) { - throw new PremiseValidationError("Packaging configuration incomplete - please contact your administrator"); + throw new PremiseValidationError("Packaging configuration incomplete - please contact your administrator", supplierName, partNumber); } if (premise.getHuStackable() == false && premise.getHuMixable() == true) { - throw new PremiseValidationError("If packaging is mixable, it must also be stackable"); + throw new PremiseValidationError("If packaging is mixable, it must also be stackable", supplierName, partNumber); } if (premise.getIndividualHuLength() == null || premise.getIndividualHuLength() == 0) { - throw new PremiseValidationError("Please enter packaging length"); + throw new PremiseValidationError("Please enter packaging length", supplierName, partNumber); } if (premise.getIndividualHuWidth() == null || premise.getIndividualHuWidth() == 0) { - throw new PremiseValidationError("Please enter packaging width"); + throw new PremiseValidationError("Please enter packaging width", supplierName, partNumber); } if (premise.getIndividualHuHeight() == null || premise.getIndividualHuHeight() == 0) { - throw new PremiseValidationError("Please enter packaging height"); + throw new PremiseValidationError("Please enter packaging height", supplierName, partNumber); } if (premise.getIndividualHuWeight() == null || premise.getIndividualHuWeight() == 0) { - throw new PremiseValidationError("Please enter packaging weight"); + throw new PremiseValidationError("Please enter packaging weight", supplierName, partNumber); } if (premise.getHuUnitCount() == null || premise.getHuUnitCount() == 0) { - throw new PremiseValidationError("Please enter the number of units per package"); + throw new PremiseValidationError("Please enter the number of units per package", supplierName, partNumber); } if (premise.getHuDisplayedWeightUnit() == null) { - throw new PremiseValidationError("Weight unit configuration missing - please contact your administrator"); + throw new PremiseValidationError("Weight unit configuration missing - please contact your administrator", supplierName, partNumber); } if (premise.getHuDisplayedDimensionUnit() == null) { - throw new PremiseValidationError("Dimension unit configuration missing - please contact your administrator"); + throw new PremiseValidationError("Dimension unit configuration missing - please contact your administrator", supplierName, partNumber); } var hu = dimensionTransformer.toDimensionEntity(premise).withTolerance(DIMENSION_TOLERANCE); @@ -305,38 +306,38 @@ public class PreCalculationCheckService { Optional feuLoad = propertyService.getProperty(SystemPropertyMappingId.TEU_LOAD); if (teuLoad.isEmpty() || feuLoad.isEmpty()) - throw new PremiseValidationError("System configuration incomplete - please contact your administrator"); + throw new PremiseValidationError("System configuration incomplete - please contact your administrator", supplierName, partNumber); if (WeightUnit.KG.convertFromG(hu.getWeight()) > teuLoad.get() && hu.getWeight() > feuLoad.get()) - throw new PremiseValidationError(String.format("Package weight exceeds %d kg - please check your weight and unit", Math.max(teuLoad.get(), feuLoad.get()))); + throw new PremiseValidationError(String.format("Package weight exceeds %d kg - please check your weight and unit", Math.max(teuLoad.get(), feuLoad.get())), supplierName, partNumber); var teuFitsXY = (hu.getLength() < ContainerType.TEU.getLength() && hu.getWidth() < ContainerType.TEU.getWidth()); var teuFitsYX = (hu.getWidth() < ContainerType.TEU.getLength() && hu.getLength() < ContainerType.TEU.getWidth()); if (!teuFitsYX && !teuFitsXY) { - throw new PremiseValidationError("Package dimensions are too large - please check your measurements and unit"); + throw new PremiseValidationError("Package dimensions are too large - please check your measurements and unit", supplierName, partNumber); } if ((hu.getLength() * hu.getWidth()) < 20000) { - throw new PremiseValidationError("Package dimensions are too small - please check your measurements and unit"); + throw new PremiseValidationError("Package dimensions are too small - please check your measurements and unit", supplierName, partNumber); } } - private void materialCheck(Premise premise) { + private void materialCheck(Premise premise, String supplierName, String partNumber) { // if (premise.getTariffUnlocked()) { // if (premise.getHsCode() == null || premise.getHsCode().length() < 10) -// throw new PremiseValidationError("Invalid HS code (10 digits expected)."); +// throw new PremiseValidationError("Invalid HS code (10 digits expected).", supplierName, partNumber); // // var isDeclarable = eUTaxationResolverService.validate(premise.getHsCode()); // -// if (!isDeclarable) throw new PremiseValidationError("Invalid HS code (not declarable)."); +// if (!isDeclarable) throw new PremiseValidationError("Invalid HS code (not declarable).", supplierName, partNumber); // } if (premise.getTariffRate() == null) { - throw new PremiseValidationError("Please enter a tariff rate"); + throw new PremiseValidationError("Please enter a tariff rate", supplierName, partNumber); } } diff --git a/src/main/java/de/avatic/lcc/util/exception/internalerror/PremiseValidationError.java b/src/main/java/de/avatic/lcc/util/exception/internalerror/PremiseValidationError.java index b8ff029..d74592d 100644 --- a/src/main/java/de/avatic/lcc/util/exception/internalerror/PremiseValidationError.java +++ b/src/main/java/de/avatic/lcc/util/exception/internalerror/PremiseValidationError.java @@ -4,6 +4,10 @@ import de.avatic.lcc.util.exception.base.InternalErrorException; public class PremiseValidationError extends InternalErrorException { + public PremiseValidationError(String message, String supplierName, String partNumber) { + super("Calculation data validation failed.", String.format("%s (Part number:%s - %s)",message, partNumber, supplierName)); + } + public PremiseValidationError(String message) { super("Calculation data validation failed.", message); } From 691d447d1693f06f9999ccd1ae877e584f10b09e Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 10 Dec 2025 14:49:54 +0100 Subject: [PATCH 05/46] Refactored: dedicated calculation thread. Calculationstatus Dashboard. --- src/frontend/src/App.vue | 2 + .../calculation/CalculationListItem.vue | 18 +- .../layout/calculation/TheDashboard.vue | 212 ++++++++++++++++++ .../src/pages/CalculationMassEdit.vue | 5 +- .../src/pages/CalculationSingleEdit.vue | 2 +- src/frontend/src/pages/Calculations.vue | 93 +++++++- src/frontend/src/store/activeuser.js | 5 + src/frontend/src/store/dashboard.js | 63 ++++++ src/frontend/src/store/premiseEdit.js | 12 +- src/frontend/src/store/premiseSingleEdit.js | 2 +- .../de/avatic/lcc/config/AsyncConfig.java | 28 ++- .../controller/GlobalExceptionHandler.java | 2 +- .../calculation/DashboardController.java | 24 ++ .../calculation/PremiseController.java | 32 +-- .../report/ReportingController.java | 3 + .../dto/calculation/CalculationStatus.java | 14 -- .../lcc/dto/calculation/PremiseDTO.java | 27 ++- .../CalculationProcessingOverviewDTO.java | 45 ++++ .../CalculationProcessingStateRequestDTO.java | 19 ++ ...CalculationProcessingStateResponseDTO.java | 16 ++ .../execution/CalculationStartRequestDTO.java | 33 +++ .../CalculationStartResponseDTO.java | 16 ++ .../model/db/calculations/CalculationJob.java | 29 +++ .../calculations/CalculationJobPriority.java | 5 + .../model/db/nodes/DistanceMatrixState.java | 2 +- .../calculation/CalculationJobRepository.java | 170 +++++++++++--- .../premise/PremiseRepository.java | 13 +- .../properties/PropertySetRepository.java | 27 ++- .../rates/ValidityPeriodRepository.java | 15 ++ .../lcc/service/access/PremisesService.java | 129 +---------- .../lcc/service/api/DistanceApiService.java | 45 +++- .../service/calculation/DistanceService.java | 5 +- .../CalculationExecutionService.java | 64 +++--- .../execution/CalculationJobProcessor.java | 135 +++++++++++ ...culationJobProcessorManagementService.java | 148 ++++++++++++ .../execution/CalculationStatusService.java | 39 ---- .../PostCalculationCheckService.java | 5 +- .../premise/PremiseTransformer.java | 8 +- src/main/resources/application.properties | 8 +- .../db/migration/V11__Schedule_Priority.sql | 11 + src/main/resources/schema.sql | 9 +- 41 files changed, 1236 insertions(+), 304 deletions(-) create mode 100644 src/frontend/src/components/layout/calculation/TheDashboard.vue create mode 100644 src/frontend/src/store/dashboard.js create mode 100644 src/main/java/de/avatic/lcc/controller/calculation/DashboardController.java delete mode 100644 src/main/java/de/avatic/lcc/dto/calculation/CalculationStatus.java create mode 100644 src/main/java/de/avatic/lcc/dto/calculation/execution/CalculationProcessingOverviewDTO.java create mode 100644 src/main/java/de/avatic/lcc/dto/calculation/execution/CalculationProcessingStateRequestDTO.java create mode 100644 src/main/java/de/avatic/lcc/dto/calculation/execution/CalculationProcessingStateResponseDTO.java create mode 100644 src/main/java/de/avatic/lcc/dto/calculation/execution/CalculationStartRequestDTO.java create mode 100644 src/main/java/de/avatic/lcc/dto/calculation/execution/CalculationStartResponseDTO.java create mode 100644 src/main/java/de/avatic/lcc/model/db/calculations/CalculationJobPriority.java create mode 100644 src/main/java/de/avatic/lcc/service/calculation/execution/CalculationJobProcessor.java create mode 100644 src/main/java/de/avatic/lcc/service/calculation/execution/CalculationJobProcessorManagementService.java delete mode 100644 src/main/java/de/avatic/lcc/service/calculation/execution/CalculationStatusService.java create mode 100644 src/main/resources/db/migration/V11__Schedule_Priority.sql diff --git a/src/frontend/src/App.vue b/src/frontend/src/App.vue index 66c8e16..0c997b1 100644 --- a/src/frontend/src/App.vue +++ b/src/frontend/src/App.vue @@ -44,10 +44,12 @@ html.modal-open { color: #002F54; } + .sub-header { font-weight: normal; font-size: 1.4rem; color: #6B869C; + margin: 1.6rem 0; } html { diff --git a/src/frontend/src/components/layout/calculation/CalculationListItem.vue b/src/frontend/src/components/layout/calculation/CalculationListItem.vue index 87a0c0a..ee8ec54 100644 --- a/src/frontend/src/components/layout/calculation/CalculationListItem.vue +++ b/src/frontend/src/components/layout/calculation/CalculationListItem.vue @@ -20,6 +20,9 @@
{{ premise.state }}
+
+ {{ buildDate(this.premise.created_at, true)}} +
@@ -39,7 +42,7 @@ import Checkbox from "@/components/UI/Checkbox.vue"; import {mapStores} from "pinia"; import {usePremiseStore} from "@/store/premise.js"; import Flag from "@/components/UI/Flag.vue"; -import {UrlSafeBase64} from "@/common.js"; +import {buildDate, UrlSafeBase64} from "@/common.js"; export default { name: "CalculationListItem", @@ -68,7 +71,7 @@ export default { return 'grey'; } else if (this.premise.state === 'COMPLETED') { return 'primary'; - } else if (this.premise.state === 'EXCEPTION') { + } else if (this.premise.state === 'COMPLETED' && this.premise.calculation_state === 'EXCEPTION') { return 'exception'; } else { return 'grey'; @@ -95,6 +98,7 @@ export default { } }, methods: { + buildDate, updateCheckBox(checked) { this.$emit('updateCheckbox', {checked: checked, id: this.id}); }, @@ -124,7 +128,7 @@ export default { .calculation-list-row { display: grid; - grid-template-columns: 6rem 1fr 2fr 14rem 10rem; + grid-template-columns: 6rem 1fr 2fr 14rem 20rem 10rem; gap: 1.6rem; padding: 1.6rem; border-bottom: 0.16rem solid #f3f4f6; @@ -203,6 +207,14 @@ export default { justify-content: start; } +.calculation-list-date-cell { + display: flex; + justify-content: start; + color: #6b7280; + font-size: 1.4rem; + line-height: 1.4; +} + .calculation-list-actions-cell { display: flex; gap: 0.8rem; diff --git a/src/frontend/src/components/layout/calculation/TheDashboard.vue b/src/frontend/src/components/layout/calculation/TheDashboard.vue new file mode 100644 index 0000000..9415703 --- /dev/null +++ b/src/frontend/src/components/layout/calculation/TheDashboard.vue @@ -0,0 +1,212 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/src/pages/CalculationMassEdit.vue b/src/frontend/src/pages/CalculationMassEdit.vue index 2952b0e..6b2e345 100644 --- a/src/frontend/src/pages/CalculationMassEdit.vue +++ b/src/frontend/src/pages/CalculationMassEdit.vue @@ -210,7 +210,7 @@ export default { modalType: null, modalProps: null, editIds: null, - processingMessage: "Please wait. Calculating ...", + processingMessage: "Please wait. Processing ...", showCalculationModal: false, isInitialLoad: true, modalDialogShow: false, @@ -267,6 +267,9 @@ export default { return this.premiseEditStore.showProcessingModal || this.destinationEditStore.showProcessingModal; }, shownProcessingMessage() { + if(this.premiseEditStore.showProcessingModal) + return "Please wait. Prepare calculation ..." + return this.processingMessage; } }, diff --git a/src/frontend/src/pages/CalculationSingleEdit.vue b/src/frontend/src/pages/CalculationSingleEdit.vue index f13a3f8..908a8ab 100644 --- a/src/frontend/src/pages/CalculationSingleEdit.vue +++ b/src/frontend/src/pages/CalculationSingleEdit.vue @@ -147,7 +147,7 @@ export default { if (this.premiseSingleEditStore.routing) return "Please wait. Routing ..." - return "Please wait. Calculating ..."; + return "Please wait. Prepare calculation ..."; } }, watch: { diff --git a/src/frontend/src/pages/Calculations.vue b/src/frontend/src/pages/Calculations.vue index f54cccc..a34e67b 100644 --- a/src/frontend/src/pages/Calculations.vue +++ b/src/frontend/src/pages/Calculations.vue @@ -1,9 +1,17 @@