Refined distance calculations and enhanced reporting layout:

- **Backend**: Adjusted `getDistance` implementation to retrieve distances via `DistanceApiService`, with fallback to `fast` algorithm. Updated `DistanceService` to utilize API responses for more accurate calculations. Enhanced `ExcelReportingService` handling for main run containers and mixed premises logic.
- **Frontend**: Improved `Report.vue` structure for better readability and modularity. Added logic to conditionally display container details based on the main run's existence.
This commit is contained in:
Jan 2025-11-01 13:27:12 +01:00
parent f7efc9eb81
commit be1ef5091b
14 changed files with 297 additions and 254 deletions

View file

@ -1,7 +1,8 @@
<template> <template>
<div class="report-container"> <div class="report-container">
<div class="box-gap"> <div class="box-gap">
<div class="report-header">{{ shorten(report.supplier.name, 35) }}</div></div> <div class="report-header">{{ shorten(report.supplier.name, 35) }}</div>
</div>
<div class="report-chart"> <div class="report-chart">
<report-chart <report-chart
title="" title=""
@ -14,7 +15,7 @@
</div> </div>
<div class="box-gap"> <div class="box-gap">
<collapsible-box :is-collapsable="false" variant="border" title="Overview" size="m" :stretch-content="true" > <collapsible-box :is-collapsable="false" variant="border" title="Overview" size="m" :stretch-content="true">
<div class="report-content-container--2-col"> <div class="report-content-container--2-col">
<div class="report-content-row"> <div class="report-content-row">
@ -92,7 +93,10 @@
<div class="report-content-row" v-if="((report.costs.air_freight_cost ?? null) !== null)"> <div class="report-content-row" v-if="((report.costs.air_freight_cost ?? null) !== null)">
<div>Air freight costs</div> <div>Air freight costs</div>
<div class="report-content-data-cell">{{ report.costs.air_freight_cost.total.toFixed(2) }}</div> <div class="report-content-data-cell">{{ report.costs.air_freight_cost.total.toFixed(2) }}</div>
<div class="report-content-data-cell">{{ (report.costs.air_freight_cost.percentage * 100).toFixed(2) }}</div> <div class="report-content-data-cell">{{
(report.costs.air_freight_cost.percentage * 100).toFixed(2)
}}
</div>
</div> </div>
@ -143,7 +147,8 @@
<collapsible-box class="report-content-container" variant="border" :title="premise.destination.name" <collapsible-box class="report-content-container" variant="border" :title="premise.destination.name"
:stretch-content="true" :initially-collapsed="true"> :stretch-content="true" :initially-collapsed="true">
<div> <div>
<report-route :sections="premise.sections" :destination="premise.destination" :route-section-scale="routeSectionScale[idx]" ></report-route> <report-route :sections="premise.sections" :destination="premise.destination"
:route-section-scale="routeSectionScale[idx]"></report-route>
<div class="report-sub-header">Premisses</div> <div class="report-sub-header">Premisses</div>
@ -192,42 +197,45 @@
<div class="report-content-row"> <div class="report-content-row">
<div>HU dimensions [{{ premise.dimension_unit }}]</div> <div>HU dimensions [{{ premise.dimension_unit }}]</div>
<div class="report-content-data-cell">{{ toFixedDimension(premise.length, premise.dimension_unit) }} x {{ toFixedDimension(premise.width, premise.dimension_unit) }} x {{ toFixedDimension(premise.height, premise.dimension_unit) }} </div> <div class="report-content-data-cell">{{ toFixedDimension(premise.length, premise.dimension_unit) }} x
{{ toFixedDimension(premise.width, premise.dimension_unit) }} x
{{ toFixedDimension(premise.height, premise.dimension_unit) }}
</div>
</div> </div>
<div class="report-content-row"> <div class="report-content-row">
<div>HU weight [{{ premise.weight_unit }}]</div> <div>HU weight [{{ premise.weight_unit }}]</div>
<div class="report-content-data-cell">{{ toFixedWeight(premise.weight, premise.weight_unit) }} </div> <div class="report-content-data-cell">{{ toFixedWeight(premise.weight, premise.weight_unit) }}</div>
</div> </div>
<div class="report-content-row"> <div class="report-content-row">
<div>HU unit count</div> <div>HU unit count</div>
<div class="report-content-data-cell">{{ premise.hu_unit_count }} </div> <div class="report-content-data-cell">{{ premise.hu_unit_count }}</div>
</div> </div>
<div class="report-content-row"> <div class="report-content-row">
<div>Mixed container</div> <div>Mixed container</div>
<div class="report-content-data-cell">{{ premise.mixed ? 'Yes' : 'No' }} </div> <div class="report-content-data-cell">{{ premise.mixed ? 'Yes' : 'No' }}</div>
</div> </div>
<div class="report-content-row"> <div class="report-content-row">
<div>Stacked layers</div> <div>Stacked layers</div>
<div class="report-content-data-cell">{{ premise.layer }} </div> <div class="report-content-data-cell">{{ hasMainRun(premise.sections) ? premise.layer : '-' }}</div>
</div> </div>
<div class="report-content-row"> <div class="report-content-row">
<div>Container unit count</div> <div>Container unit count</div>
<div class="report-content-data-cell">{{ premise.unit_count * premise.hu_unit_count }} </div> <div class="report-content-data-cell">{{hasMainRun(premise.sections) ? (premise.unit_count * premise.hu_unit_count) : '-' }}</div>
</div> </div>
<div class="report-content-row"> <div class="report-content-row">
<div>Container type</div> <div>Container type</div>
<div class="report-content-data-cell">{{ getContainerTypeName(premise.container_type) }} </div> <div class="report-content-data-cell">{{hasMainRun(premise.sections) ? getContainerTypeName(premise.container_type) : '-' }}</div>
</div> </div>
<div class="report-content-row"> <div class="report-content-row">
<div>Limiting factor</div> <div>Limiting factor</div>
<div class="report-content-data-cell">{{ premise.weight_exceeded ? 'Weight' : 'Volume' }} </div> <div class="report-content-data-cell">{{hasMainRun(premise.sections) ? premise.weight_exceeded ? 'Weight' : 'Volume' : '-'}}</div>
</div> </div>
</div> </div>
@ -265,9 +273,12 @@ export default {
} }
}, },
methods: { methods: {
hasMainRun(sections) {
return sections.some(section => section.transport_type === 'SEA' || section.transport_type === 'RAIL');
},
shorten(text, length) { shorten(text, length) {
if(text !== null && text !== undefined && text.length > length) { if (text !== null && text !== undefined && text.length > length) {
return `${text.substring(0, length - 3)}` ; return `${text.substring(0, length - 3)}`;
} }
return text; return text;
@ -284,11 +295,11 @@ export default {
return '' return ''
}, },
toFixedDimension(value, unit) { toFixedDimension(value, unit) {
if(unit === 'm') { if (unit === 'm') {
return value.toFixed(2); return value.toFixed(2);
} else if(unit === 'cm') { } else if (unit === 'cm') {
return value.toFixed(2); return value.toFixed(2);
} else if(unit === 'mm') { } else if (unit === 'mm') {
return value.toFixed(); return value.toFixed();
} }
}, },

View file

@ -190,7 +190,7 @@ export default {
return this.modalType ? this.componentsData[this.modalType] : null; return this.modalType ? this.componentsData[this.modalType] : null;
}, },
showProcessingModal() { showProcessingModal() {
return this.premiseEditStore.showProcessingModal; return this.premiseEditStore.showProcessingModal || this.showCalculationModal;
} }
}, },
created() { created() {
@ -224,7 +224,8 @@ export default {
}, },
editIds: null, editIds: null,
dataSourceId: null, dataSourceId: null,
processingMessage: "Please wait. Calculating routes ...", processingMessage: "Please wait. Calculating ...",
showCalculationModal: false
} }
}, },
methods: { methods: {
@ -244,6 +245,7 @@ export default {
} }
}, },
async startCalculation() { async startCalculation() {
this.showCalculationModal = true;
const error = await this.premiseEditStore.startCalculation(); const error = await this.premiseEditStore.startCalculation();
if (error !== null) { if (error !== null) {
@ -258,6 +260,7 @@ export default {
} else { } else {
this.closeMassEdit() this.closeMassEdit()
} }
this.showCalculationModal = false;
}, },
closeMassEdit() { closeMassEdit() {
this.$router.push({name: "calculation-list"}); this.$router.push({name: "calculation-list"});

View file

@ -86,6 +86,13 @@
<h3 class="sub-header">Destinations & routes</h3> <h3 class="sub-header">Destinations & routes</h3>
<destination-list-view></destination-list-view> <destination-list-view></destination-list-view>
<modal :z-index="3000" :state="showProcessingModal">
<div class="edit-calculation-spinner-container space-around">
<spinner></spinner>
<span>{{ processingMessage }}</span>
</div>
</modal>
</div> </div>
</div> </div>
</template> </template>
@ -131,6 +138,8 @@ export default {
traceModal: false, traceModal: false,
bulkEditQuery: null, bulkEditQuery: null,
id: null, id: null,
processingMessage: "Please wait. Calculating ...",
showCalculationModal: false,
} }
}, },
computed: { computed: {
@ -140,15 +149,18 @@ export default {
}, },
fromMassEdit() { fromMassEdit() {
return this.bulkEditQuery !== null; return this.bulkEditQuery !== null;
} },
showProcessingModal() {
return this.premiseEditStore.showProcessingModal || this.showCalculationModal;
},
}, },
methods: { methods: {
async startCalculation() { async startCalculation() {
this.showCalculationModal = true;
const error = await this.premiseEditStore.startCalculation(); const error = await this.premiseEditStore.startCalculation();
if (error !== null) { if (error !== null) {
this.$refs.toast.addToast({ this.$refs.toast.addToast({
icon: 'warning', icon: 'warning',
message: error.message, message: error.message,
@ -159,6 +171,8 @@ export default {
} else { } else {
this.close(); this.close();
} }
this.showCalculationModal = false;
}, },
close() { close() {
if (this.bulkEditQuery) { if (this.bulkEditQuery) {
@ -181,17 +195,6 @@ export default {
success = await this.premiseEditStore.savePackaging(); success = await this.premiseEditStore.savePackaging();
} }
// if(success) {
// this.$refs.toast.addToast({
// icon: 'floppy-disk',
// message: `Changes on ${type} saved.`,
//
// variant: 'primary',
// duration: 3000
// })
// }
}, },
updateMaterial(id, action) { updateMaterial(id, action) {
console.log(id, action); console.log(id, action);
@ -287,11 +290,18 @@ export default {
text-decoration: underline; text-decoration: underline;
} }
.space-around {
margin: 3rem;
}
.edit-calculation-spinner-container { .edit-calculation-spinner-container {
display: flex; display: flex;
flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
flex: 1 1 30rem; gap: 3.6rem;
flex: 1 1 auto;
font-size: 1.6rem;
} }
.edit-calculation-spinner { .edit-calculation-spinner {

View file

@ -599,6 +599,8 @@ export const usePremiseEditStore = defineStore('premiseEdit', {
} else { } else {
const id = node.id; const id = node.id;
this.processDestinationMassEdit = true;
const toBeUpdated = this.destinations.fromMassEditView ? this.destinations.premise_ids : this.premisses?.filter(p => p.selected).map(p => p.id); const toBeUpdated = this.destinations.fromMassEditView ? this.destinations.premise_ids : this.premisses?.filter(p => p.selected).map(p => p.id);
@ -611,6 +613,7 @@ export const usePremiseEditStore = defineStore('premiseEdit', {
const {data: destinations} = await performRequest(this, 'POST', url, body).catch(e => { const {data: destinations} = await performRequest(this, 'POST', url, body).catch(e => {
this.loading = false; this.loading = false;
this.selectedLoading = false; this.selectedLoading = false;
this.processDestinationMassEdit = false;
throw e; throw e;
}); });
@ -624,6 +627,8 @@ export const usePremiseEditStore = defineStore('premiseEdit', {
this.destinations.destinations.push(mappedDestination); this.destinations.destinations.push(mappedDestination);
} }
this.processDestinationMassEdit = false;
return mappedIds; return mappedIds;
} }
}, },

View file

@ -39,9 +39,10 @@ export const useReportsStore = defineStore('reports', {
const params = new URLSearchParams(); const params = new URLSearchParams();
params.append('material', this.materialId); params.append('material', this.materialId);
params.append('sources', this.supplierIds); params.append('sources', this.supplierIds);
params.append('userSources', this.userSupplierIds);
const url = `${config.backendUrl}/reports/download/${params.size === 0 ? '' : '?'}${params.toString()}`; const url = `${config.backendUrl}/reports/download/${params.size === 0 ? '' : '?'}${params.toString()}`;
const fileName = `report_${this.materialId}_${this.supplierIds.join('_')}.xlsx`; const fileName = `report_${this.materialId}_${this.supplierIds.join('_')}_u${this.userSupplierIds.join('_')}.xlsx`;
await performDownload(url,fileName); await performDownload(url,fileName);
}, },
reset() { reset() {

View file

@ -71,7 +71,7 @@ public class SecurityConfig {
.authorizeHttpRequests(auth -> auth .authorizeHttpRequests(auth -> auth
.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.requestMatchers("/actuator/health").permitAll() .requestMatchers("/actuator/health").permitAll()
.requestMatchers("/actuator/**").authenticated() .requestMatchers("/actuator/**").hasRole("SERVICE")
.requestMatchers("/oauth2/token").permitAll() .requestMatchers("/oauth2/token").permitAll()
.requestMatchers("/api/**").authenticated() .requestMatchers("/api/**").authenticated()
.requestMatchers("/api/dev/**").denyAll() .requestMatchers("/api/dev/**").denyAll()

View file

@ -13,6 +13,7 @@ import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriComponentsBuilder;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.net.URI;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Optional; import java.util.Optional;
@ -35,6 +36,7 @@ public class DistanceApiService {
} }
public Optional<Distance> getDistance(Node from, Node to) { public Optional<Distance> getDistance(Node from, Node to) {
if (from == null || to == null) { if (from == null || to == null) {
logger.warn("Source or destination node is null"); logger.warn("Source or destination node is null");
return Optional.empty(); return Optional.empty();
@ -46,7 +48,6 @@ public class DistanceApiService {
return Optional.empty(); return Optional.empty();
} }
// Check if distance exists in database and is valid
Optional<Distance> cachedDistance = distanceMatrixRepository.getDistance(from, to); Optional<Distance> cachedDistance = distanceMatrixRepository.getDistance(from, to);
if (cachedDistance.isPresent()) { if (cachedDistance.isPresent()) {
@ -54,12 +55,10 @@ public class DistanceApiService {
return cachedDistance; return cachedDistance;
} }
// Distance not found or stale, fetch from Azure Maps logger.debug("Fetching distance from Azure Maps for nodes {} to {}", from.getId(), to.getId());
logger.info("Fetching distance from Azure Maps for nodes {} to {}", from.getId(), to.getId());
Optional<Distance> fetchedDistance = fetchDistanceFromAzureMaps(from, to); Optional<Distance> fetchedDistance = fetchDistanceFromAzureMaps(from, to);
if (fetchedDistance.isPresent()) { if (fetchedDistance.isPresent()) {
// Store in database
distanceMatrixRepository.saveDistance(fetchedDistance.get()); distanceMatrixRepository.saveDistance(fetchedDistance.get());
return fetchedDistance; return fetchedDistance;
} }
@ -69,18 +68,19 @@ public class DistanceApiService {
private Optional<Distance> fetchDistanceFromAzureMaps(Node from, Node to) { private Optional<Distance> fetchDistanceFromAzureMaps(Node from, Node to) {
try { try {
String url = UriComponentsBuilder.fromHttpUrl(AZURE_MAPS_ROUTE_API) String url = UriComponentsBuilder.fromUriString(AZURE_MAPS_ROUTE_API)
.queryParam("api-version", "1.0") .queryParam("api-version", "1.0")
.queryParam("subscription-key", subscriptionKey) .queryParam("subscription-key", subscriptionKey)
.queryParam("query", String.format("%s,%s:%s,%s", .queryParam("query", String.format("%s,%s:%s,%s",
from.getGeoLat(), from.getGeoLng(), from.getGeoLat(), from.getGeoLng(),
to.getGeoLat(), to.getGeoLng())) to.getGeoLat(), to.getGeoLng()))
.encode()
.toUriString(); .toUriString();
RouteDirectionsResponse response = restTemplate.getForObject(url, RouteDirectionsResponse.class); RouteDirectionsResponse response = restTemplate.getForObject(url, RouteDirectionsResponse.class);
if (response != null && response.getRoutes() != null && !response.getRoutes().isEmpty()) { if (response != null && response.getRoutes() != null && !response.getRoutes().isEmpty()) {
Integer distanceInMeters = response.getRoutes().get(0).getSummary().getLengthInMeters(); Integer distanceInMeters = response.getRoutes().getFirst().getSummary().getLengthInMeters();
Distance distance = new Distance(); Distance distance = new Distance();
distance.setFromNodeId(from.getId()); distance.setFromNodeId(from.getId());

View file

@ -6,6 +6,7 @@ import de.avatic.lcc.model.db.nodes.Location;
import de.avatic.lcc.model.db.nodes.Node; import de.avatic.lcc.model.db.nodes.Node;
import de.avatic.lcc.repositories.DistanceMatrixRepository; import de.avatic.lcc.repositories.DistanceMatrixRepository;
import de.avatic.lcc.repositories.country.CountryRepository; import de.avatic.lcc.repositories.country.CountryRepository;
import de.avatic.lcc.service.api.DistanceApiService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service
@ -14,20 +15,21 @@ public class DistanceService {
private static final double EARTH_RADIUS = 6371.0; private static final double EARTH_RADIUS = 6371.0;
private final DistanceMatrixRepository distanceMatrixRepository; private final DistanceMatrixRepository distanceMatrixRepository;
private final CountryRepository countryRepository; private final CountryRepository countryRepository;
private final DistanceApiService distanceApiService;
public DistanceService(DistanceMatrixRepository distanceMatrixRepository, CountryRepository countryRepository) { public DistanceService(DistanceMatrixRepository distanceMatrixRepository, CountryRepository countryRepository, DistanceApiService distanceApiService) {
this.distanceMatrixRepository = distanceMatrixRepository; this.distanceMatrixRepository = distanceMatrixRepository;
this.countryRepository = countryRepository; this.countryRepository = countryRepository;
this.distanceApiService = distanceApiService;
} }
public double getDistance(Node src, Node dest, boolean fast) { public double getDistance(Node src, Node dest, boolean fast) {
if (fast) return getDistanceFast(src, dest); if (fast) return getDistanceFast(src, dest);
var distance = distanceMatrixRepository.getDistance(src, dest); var distance = distanceApiService.getDistance(src, dest);
if (distance.isEmpty()) return getDistanceFast(src, dest);
// TODO do a api call if empty!.
return distance.map(value -> value.getDistance().intValue()).orElse(0);
return distance.map(value -> value.getDistance().intValue()/1000).orElse(0);
} }
public double getDistanceFast(Integer srcCountryId, Location src, Integer destCountryId, Location dest ) { public double getDistanceFast(Integer srcCountryId, Location src, Integer destCountryId, Location dest ) {

View file

@ -334,7 +334,7 @@ public class RoutingService {
} }
finalSection.setRate(matrixRate); finalSection.setRate(matrixRate);
finalSection.setApproxDistance(distanceService.getDistance(container.getSourceNode(), toNode, true)); finalSection.setApproxDistance(distanceService.getDistance(container.getSourceNode(), toNode, false));
rates.add(finalSection); rates.add(finalSection);
} }
@ -699,7 +699,7 @@ public class RoutingService {
if (matrixRate.isPresent()) { if (matrixRate.isPresent()) {
matrixRateObj.setRate(matrixRate.get()); matrixRateObj.setRate(matrixRate.get());
matrixRateObj.setApproxDistance(distanceService.getDistance(startNode, endNode, true)); matrixRateObj.setApproxDistance(distanceService.getDistance(startNode, endNode, false));
container.getRates().add(matrixRateObj); container.getRates().add(matrixRateObj);
return matrixRateObj; return matrixRateObj;
} else { } else {

View file

@ -67,7 +67,7 @@ public class RouteSectionCostCalculationService {
Node fromNode = nodeRepository.getById(premise.getSupplierNodeId()).orElseThrow(); Node fromNode = nodeRepository.getById(premise.getSupplierNodeId()).orElseThrow();
Node toNode = nodeRepository.getById(destination.getDestinationNodeId()).orElseThrow(); Node toNode = nodeRepository.getById(destination.getDestinationNodeId()).orElseThrow();
double distance = distanceService.getDistance(fromNode, toNode, true); double distance = distanceService.getDistance(fromNode, toNode, false);
result.setDistance(BigDecimal.valueOf(distance)); result.setDistance(BigDecimal.valueOf(distance));
// Get rate and transit time // Get rate and transit time

View file

@ -153,7 +153,7 @@ public class PreCalculationCheckService {
var validDaysInt = Integer.parseInt(validDays.get().getCurrentValue()); var validDaysInt = Integer.parseInt(validDays.get().getCurrentValue());
if(!period.getStartDate().plusDays((long) validDaysInt * renewals).isAfter(LocalDateTime.now())) 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("There are no valid rates for the given date. Please contact your administrator.");
} }

View file

@ -1,6 +1,7 @@
package de.avatic.lcc.service.report; package de.avatic.lcc.service.report;
import de.avatic.lcc.dto.generic.NodeDTO; import de.avatic.lcc.dto.generic.NodeDTO;
import de.avatic.lcc.dto.generic.TransportType;
import de.avatic.lcc.dto.report.ReportDTO; import de.avatic.lcc.dto.report.ReportDTO;
import de.avatic.lcc.dto.report.ReportDestinationDTO; import de.avatic.lcc.dto.report.ReportDestinationDTO;
import de.avatic.lcc.dto.report.ReportEntryDTO; import de.avatic.lcc.dto.report.ReportEntryDTO;
@ -145,6 +146,9 @@ public class ExcelReportingService {
} }
private void flattenDestination(ReportDestinationDTO destination) { private void flattenDestination(ReportDestinationDTO destination) {
var hasMainRun = destination.getSections().stream().anyMatch(s -> s.getTransportType().equals(TransportType.RAIL) || s.getTransportType().equals(TransportType.SEA));
addData(DESTINATION_NAME, destination.getDestination().getName()); addData(DESTINATION_NAME, destination.getDestination().getName());
addData(DESTINATION_ADDRESS, destination.getDestination().getAddress()); addData(DESTINATION_ADDRESS, destination.getDestination().getAddress());
@ -152,6 +156,7 @@ public class ExcelReportingService {
addData(DESTINATION_HS_CODE, destination.getHsCode()); addData(DESTINATION_HS_CODE, destination.getHsCode());
addData(DESTINATION_TARIFF_RATE, destination.getTariffRate().toString()); addData(DESTINATION_TARIFF_RATE, destination.getTariffRate().toString());
addData(DESTINATION_OVERSHARE, destination.getOverseaShare().toString()); addData(DESTINATION_OVERSHARE, destination.getOverseaShare().toString());
if(destination.getAirFreightShare() != null) if(destination.getAirFreightShare() != null)
addData(DESTINATION_AIR_FREIGHT_SHARE, destination.getAirFreightShare().toString()); addData(DESTINATION_AIR_FREIGHT_SHARE, destination.getAirFreightShare().toString());
addData(DESTINATION_TRANSPORT_TIME, destination.getTransportTime().toString()); addData(DESTINATION_TRANSPORT_TIME, destination.getTransportTime().toString());
@ -164,14 +169,14 @@ public class ExcelReportingService {
addData(DESTINATION_WEIGHT, destination.getWeight().toString()); addData(DESTINATION_WEIGHT, destination.getWeight().toString());
addData(DESTINATION_WEIGHT_UNIT, destination.getWeightUnit().toString()); addData(DESTINATION_WEIGHT_UNIT, destination.getWeightUnit().toString());
addData(DESTINATION_HU_UNIT_COUNT, destination.getHuUnitCount().toString()); addData(DESTINATION_HU_UNIT_COUNT, destination.getHuUnitCount().toString());
addData(DESTINATION_CONTAINER_LAYER, destination.getLayer().toString()); addData(DESTINATION_CONTAINER_LAYER, !hasMainRun ? "-" : destination.getLayer().toString());
addData(DESTINATION_CONTAINER_UNIT_COUNT, destination.getUnitCount().toString()); addData(DESTINATION_CONTAINER_UNIT_COUNT, !hasMainRun ? "-" : destination.getUnitCount().toString());
addData(DESTINATION_CONTAINER_UTILIZATION, destination.getUtilization().toString()); addData(DESTINATION_CONTAINER_UTILIZATION, !hasMainRun ? "-" : destination.getUtilization().toString());
addData(DESTINATION_CONTAINER_TYPE, destination.getType().toString()); addData(DESTINATION_CONTAINER_TYPE, !hasMainRun ? "-" : destination.getType().toString());
addData(DESTINATION_CONTAINER_WEIGHT_EXCEEDED, destination.getWeightExceeded().toString()); addData(DESTINATION_CONTAINER_WEIGHT_EXCEEDED, !hasMainRun ? "-" : destination.getWeightExceeded().toString());
addData(DESTINATION_CONTAINER_RATE, destination.getRate().toString()); addData(DESTINATION_CONTAINER_RATE, !hasMainRun ? "-" : destination.getRate().toString());
addData(DESTINATION_MIXED, destination.getMixed().toString()); addData(DESTINATION_MIXED, !hasMainRun ? "-" : destination.getMixed().toString());
} }

View file

@ -2,6 +2,7 @@ package de.avatic.lcc.service.report;
import de.avatic.lcc.dto.generic.NodeDTO; import de.avatic.lcc.dto.generic.NodeDTO;
import de.avatic.lcc.dto.report.ReportDTO; import de.avatic.lcc.dto.report.ReportDTO;
import de.avatic.lcc.model.db.calculations.CalculationJob;
import de.avatic.lcc.repositories.NodeRepository; import de.avatic.lcc.repositories.NodeRepository;
import de.avatic.lcc.repositories.calculation.CalculationJobRepository; import de.avatic.lcc.repositories.calculation.CalculationJobRepository;
import de.avatic.lcc.repositories.rates.ValidityPeriodRepository; import de.avatic.lcc.repositories.rates.ValidityPeriodRepository;
@ -58,9 +59,13 @@ public class ReportingService {
var periodId = tuple.get().periodId(); var periodId = tuple.get().periodId();
var setId = tuple.get().propertySetId(); var setId = tuple.get().propertySetId();
//TODO check user node id and node id for null
var jobs = new ArrayList<>(nodeIds.stream().map(nodeId -> calculationJobRepository.getCalculationJobWithJobStateValid(periodId, setId, nodeId, materialId)).filter(Optional::isPresent).map(Optional::get).toList()); var jobs = new ArrayList<CalculationJob>();
if(!nodeIds.isEmpty())
jobs.addAll(nodeIds.stream().map(nodeId -> calculationJobRepository.getCalculationJobWithJobStateValid(periodId, setId, nodeId, materialId)).filter(Optional::isPresent).map(Optional::get).toList());
if(!userNodeIds.isEmpty())
jobs.addAll(userNodeIds.stream().map(nodeId -> calculationJobRepository.getCalculationJobWithJobStateValidUserNodeId(periodId, setId,nodeId ,materialId)).filter(Optional::isPresent).map(Optional::get).toList()); jobs.addAll(userNodeIds.stream().map(nodeId -> calculationJobRepository.getCalculationJobWithJobStateValidUserNodeId(periodId, setId,nodeId ,materialId)).filter(Optional::isPresent).map(Optional::get).toList());
return jobs.stream().map(reportTransformer::toReportDTO).toList(); return jobs.stream().map(reportTransformer::toReportDTO).toList();

View file

@ -190,6 +190,8 @@ public class ReportTransformer {
destinationDTO.setWeight(weightUnit.convertFromG(premise.getIndividualHuWeight())); destinationDTO.setWeight(weightUnit.convertFromG(premise.getIndividualHuWeight()));
destinationDTO.setHuUnitCount(premise.getHuUnitCount()); destinationDTO.setHuUnitCount(premise.getHuUnitCount());
CalculationJobRouteSection mainRun = sections.stream().filter(CalculationJobRouteSection::getMainRun).findFirst().orElse(null);
destinationDTO.setLayer(destination.getLayerCount()); destinationDTO.setLayer(destination.getLayerCount());
destinationDTO.setOverseaShare(premise.getOverseaShare().doubleValue()); destinationDTO.setOverseaShare(premise.getOverseaShare().doubleValue());
@ -199,7 +201,6 @@ public class ReportTransformer {
if (includeAirfreight) if (includeAirfreight)
destinationDTO.setAirFreightShare(destination.getAirFreightShare().doubleValue()); destinationDTO.setAirFreightShare(destination.getAirFreightShare().doubleValue());
CalculationJobRouteSection mainRun = sections.stream().filter(CalculationJobRouteSection::getMainRun).findFirst().orElse(null);
destinationDTO.setMixed(premise.getHuMixable()); destinationDTO.setMixed(premise.getHuMixable());
destinationDTO.setRate(mainRun == null ? 0 : mainRun.getRate()); destinationDTO.setRate(mainRun == null ? 0 : mainRun.getRate());