From c7eded8da20fc22176e29b59e45e1ceffad3c78b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Schr=C3=B6der?= <131770181+ReneSchroederLJ@users.noreply.github.com> Date: Tue, 14 May 2024 08:08:53 +0200 Subject: [PATCH] feat: implemented delivery information edc flow (#355) * feat: implemented delivery information edc flow * chore: updated frontend dependencies * feat: implemented logic for delivery creation based on incoterm * fix: CodeQl findings --- .../logic/util/DtrRequestBodyBuilder.java | 1 + .../common/security/SecurityConfig.java | 2 +- .../controller/DeliveryController.java | 81 +++++++-- .../DeliveryRequestApiController.java | 84 +++++++++ .../DeliveryResponsibilityEnumeration.java | 24 +++ .../domain/model/IncotermEnumeration.java | 29 +++ .../DeliveryInformationSammMapper.java | 168 ++++++++++++++++++ .../delivery/logic/dto/DeliveryDto.java | 2 + .../logic/dto/deliverysamm/Delivery.java | 102 +++++++++++ .../dto/deliverysamm/DeliveryInformation.java | 76 ++++++++ .../logic/dto/deliverysamm/Location.java | 73 ++++++++ .../deliverysamm/OrderPositionReference.java | 73 ++++++++ .../logic/dto/deliverysamm/Position.java | 70 ++++++++ .../logic/dto/deliverysamm/TransitEvent.java | 72 ++++++++ .../dto/deliverysamm/TransitLocations.java | 75 ++++++++ .../service/DeliveryRequestApiService.java | 112 ++++++++++++ .../logic/service/OwnDeliveryService.java | 43 ++++- .../service/ReportedDeliveryService.java | 47 ++++- frontend/DEPENDENCIES | 2 +- 19 files changed, 1109 insertions(+), 27 deletions(-) create mode 100644 backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/controller/DeliveryRequestApiController.java create mode 100644 backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/domain/model/DeliveryResponsibilityEnumeration.java create mode 100644 backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/adapter/DeliveryInformationSammMapper.java create mode 100644 backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/Delivery.java create mode 100644 backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/DeliveryInformation.java create mode 100644 backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/Location.java create mode 100644 backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/OrderPositionReference.java create mode 100644 backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/Position.java create mode 100644 backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/TransitEvent.java create mode 100644 backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/TransitLocations.java create mode 100644 backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/service/DeliveryRequestApiService.java diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/ddtr/logic/util/DtrRequestBodyBuilder.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/ddtr/logic/util/DtrRequestBodyBuilder.java index 584c7d7c..1e9e3b63 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/ddtr/logic/util/DtrRequestBodyBuilder.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/ddtr/logic/util/DtrRequestBodyBuilder.java @@ -97,6 +97,7 @@ public JsonNode createMaterialRegistrationRequestBody(MaterialPartnerRelation ma submodelDescriptorsArray.add(createSubmodelObject(SubmodelType.ITEM_STOCK.URN_SEMANTIC_ID, href + DirectionCharacteristic.INBOUND + "/", variablesService.getItemStockSubmodelApiAssetId())); submodelDescriptorsArray.add(createSubmodelObject(SubmodelType.DEMAND.URN_SEMANTIC_ID, href, variablesService.getDemandSubmodelApiAssetId())); + submodelDescriptorsArray.add(createSubmodelObject(SubmodelType.DELIVERY.URN_SEMANTIC_ID, href, variablesService.getDeliverySubmodelApiAssetId())); log.debug("Created body for material " + material.getOwnMaterialNumber() + "\n" + body.toPrettyString()); return body; diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/security/SecurityConfig.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/security/SecurityConfig.java index 4390b2e9..6cf564b6 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/security/SecurityConfig.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/common/security/SecurityConfig.java @@ -77,7 +77,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .authorizeHttpRequests( // any request in spring context (authorizeHttpRequests) -> authorizeHttpRequests - .requestMatchers("/stockView/**", "/partners/**", "/materials/**", "/materialpartnerrelations/**", "/item-stock/**", "/production/**", "/delivery/**", "/demand/**", "/planned-production/**", "/material-demand/**", "/edrendpoint/**", "/edc/**", "/parttypeinformation/**") + .requestMatchers("/stockView/**", "/partners/**", "/materials/**", "/materialpartnerrelations/**", "/item-stock/**", "/production/**", "/delivery/**", "/demand/**", "/planned-production/**", "/material-demand/**", "/delivery-information/**", "/edrendpoint/**", "/edc/**", "/parttypeinformation/**") .authenticated() .requestMatchers("/swagger-ui/**", "/v3/api-docs/**", "/health/**").permitAll() .dispatcherTypeMatchers(DispatcherType.ERROR).permitAll() diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/controller/DeliveryController.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/controller/DeliveryController.java index 3444c8ec..df82500e 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/controller/DeliveryController.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/controller/DeliveryController.java @@ -23,22 +23,30 @@ import java.util.List; import java.util.Optional; import java.util.UUID; +import java.util.concurrent.ExecutorService; +import java.util.regex.Pattern; import java.util.stream.Collectors; import javax.management.openmbean.KeyAlreadyExistsException; -import org.eclipse.tractusx.puris.backend.delivery.domain.model.Delivery; +import org.eclipse.tractusx.puris.backend.common.util.PatternStore; import org.eclipse.tractusx.puris.backend.delivery.domain.model.OwnDelivery; +import org.eclipse.tractusx.puris.backend.delivery.domain.model.ReportedDelivery; import org.eclipse.tractusx.puris.backend.delivery.logic.dto.DeliveryDto; +import org.eclipse.tractusx.puris.backend.delivery.logic.service.DeliveryRequestApiService; import org.eclipse.tractusx.puris.backend.delivery.logic.service.OwnDeliveryService; import org.eclipse.tractusx.puris.backend.delivery.logic.service.ReportedDeliveryService; import org.eclipse.tractusx.puris.backend.masterdata.domain.model.Material; import org.eclipse.tractusx.puris.backend.masterdata.domain.model.Partner; +import org.eclipse.tractusx.puris.backend.masterdata.logic.dto.PartnerDto; +import org.eclipse.tractusx.puris.backend.masterdata.logic.service.MaterialPartnerRelationService; import org.eclipse.tractusx.puris.backend.masterdata.logic.service.MaterialService; import org.eclipse.tractusx.puris.backend.masterdata.logic.service.PartnerService; import org.modelmapper.ModelMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -46,6 +54,7 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; @@ -67,25 +76,43 @@ public class DeliveryController { @Autowired private ReportedDeliveryService reportedDeliveryService; + @Autowired + private DeliveryRequestApiService deliveryRequestApiService; + @Autowired private MaterialService materialService; @Autowired private PartnerService partnerService; + @Autowired + private MaterialPartnerRelationService mprService; + @Autowired private ModelMapper modelMapper; @Autowired private Validator validator; + private final Pattern materialPattern = PatternStore.NON_EMPTY_NON_VERTICAL_WHITESPACE_PATTERN; + + @Autowired + private ExecutorService executorService; + @GetMapping() @ResponseBody @Operation(summary = "Get all planned deliveries for the given Material", - description = "Get all planned deliveries for the given material number. Optionally the delivery can be filtered by its partner bpnl.") - public List getAllDeliveries(String materialNumber, Optional bpnl) { - return ownDeliveryService.findAllByFilters(Optional.of(materialNumber), bpnl) + description = "Get all planned deliveries for the given material number. Optionally a bpns and partner bpnl can be provided to filter the deliveries further.") + public List getAllDeliveries(String ownMaterialNumber, Optional bpns, Optional bpnl) { + Material material = materialService.findByOwnMaterialNumber(ownMaterialNumber); + if (material == null) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Material does not exist."); + } + var reportedDeliveries = reportedDeliveryService.findAllByFilters(Optional.of(ownMaterialNumber), bpns, bpnl) + .stream().map(this::convertToDto).collect(Collectors.toList()); + var ownDeliveries = ownDeliveryService.findAllByFilters(Optional.of(ownMaterialNumber), bpns, bpnl) .stream().map(this::convertToDto).collect(Collectors.toList()); + return List.of(reportedDeliveries, ownDeliveries).stream().flatMap(List::stream).toList(); } @PostMapping() @@ -157,13 +184,35 @@ public void deleteDelivery(@PathVariable UUID id) { ownDeliveryService.delete(id); } - @GetMapping("reported") + @GetMapping("reported/refresh") @ResponseBody - @Operation(summary = "Get all deliveries of partners for a material", - description = "Get all deliveries of partners for a material number. Optionally the partners can be filtered by their bpnl.") - public List getAllDeliveriesForPartner(String materialNumber, Optional bpnl) { - return reportedDeliveryService.findAllByFilters(Optional.of(materialNumber), bpnl) - .stream().map(this::convertToDto).collect(Collectors.toList()); + @Operation( + summary = "Refreshes all reported deliveries", + description = "Refreshes all reported deliveries from the delivery request API." + ) + public ResponseEntity> refreshReportedDeliveries(@RequestParam String ownMaterialNumber) { + if (!materialPattern.matcher(ownMaterialNumber).matches()) { + return new ResponseEntity<>(HttpStatusCode.valueOf(400)); + } + Material materialEntity = materialService.findByOwnMaterialNumber(ownMaterialNumber); + if (materialEntity == null) { + return new ResponseEntity<>(HttpStatusCode.valueOf(404)); + } + + List partners; + if (materialEntity.isMaterialFlag()) { + partners = mprService.findAllSuppliersForOwnMaterialNumber(ownMaterialNumber); + } else { + partners = mprService.findAllCustomersForOwnMaterialNumber(ownMaterialNumber); + } + for (Partner partner : partners) { + executorService.submit(() -> + deliveryRequestApiService.doReportedDeliveryRequest(partner, materialEntity)); + } + + return ResponseEntity.ok(partners.stream() + .map(partner -> modelMapper.map(partner, PartnerDto.class)) + .toList()); } private OwnDelivery convertToEntity(DeliveryDto dto) { @@ -183,13 +232,19 @@ private OwnDelivery convertToEntity(DeliveryDto dto) { return entity; } - private DeliveryDto convertToDto(Delivery entity) { + private DeliveryDto convertToDto(OwnDelivery entity) { DeliveryDto dto = modelMapper.map(entity, DeliveryDto.class); - dto.setOwnMaterialNumber(entity.getMaterial().getOwnMaterialNumber()); + dto.setPartnerBpnl(entity.getPartner().getBpnl()); + dto.setReported(false); + return dto; + } + private DeliveryDto convertToDto(ReportedDelivery entity) { + DeliveryDto dto = modelMapper.map(entity, DeliveryDto.class); + dto.setOwnMaterialNumber(entity.getMaterial().getOwnMaterialNumber()); dto.setPartnerBpnl(entity.getPartner().getBpnl()); - + dto.setReported(true); return dto; } } diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/controller/DeliveryRequestApiController.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/controller/DeliveryRequestApiController.java new file mode 100644 index 00000000..55f7e4fe --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/controller/DeliveryRequestApiController.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2024 Volkswagen AG + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.eclipse.tractusx.puris.backend.delivery.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.tractusx.puris.backend.common.util.PatternStore; +import org.eclipse.tractusx.puris.backend.delivery.logic.dto.deliverysamm.DeliveryInformation; +import org.eclipse.tractusx.puris.backend.delivery.logic.service.DeliveryRequestApiService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.regex.Pattern; + +@RestController +@RequestMapping("delivery-information") +@Slf4j +/** + * This class offers the endpoint for requesting the PlannedProduction Submodel 2.0.0 + */ +public class DeliveryRequestApiController { + + @Autowired + private DeliveryRequestApiService deliveryRequestApiSrvice; + + private final Pattern bpnlPattern = PatternStore.BPNL_PATTERN; + + private final Pattern urnPattern = PatternStore.URN_OR_UUID_PATTERN; + + + @Operation(summary = "This endpoint receives the Delivery Information Submodel 2.0.0 requests") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Ok"), + @ApiResponse(responseCode = "400", description = "Bad Request"), + @ApiResponse(responseCode = "500", description = "Internal Server Error"), + @ApiResponse(responseCode = "501", description = "Unsupported representation") + }) + @GetMapping("request/{materialNumberCx}/{representation}") + public ResponseEntity getDeliveryMapping( + @RequestHeader("edc-bpn") String bpnl, + @PathVariable String materialNumberCx, + @PathVariable String representation + ) { + if (!bpnlPattern.matcher(bpnl).matches() || !urnPattern.matcher(materialNumberCx).matches()) { + log.warn("Rejecting request at Delivery Information Submodel request 2.0.0 endpoint"); + return ResponseEntity.badRequest().build(); + } + + if (!"$value".equals(representation)) { + log.warn("Rejecting request at Delivery Information Submodel request 2.0.0 endpoint, missing '$value' in request"); + if (!PatternStore.NON_EMPTY_NON_VERTICAL_WHITESPACE_PATTERN.matcher(representation).matches()) { + representation = ""; + } + log.warn("Received " + representation + " from " + bpnl); + return ResponseEntity.status(501).build(); + } + var samm = deliveryRequestApiSrvice.handleDeliverySubmodelRequest(bpnl, materialNumberCx); + if (samm == null) { + return ResponseEntity.status(500).build(); + } + return ResponseEntity.ok(samm); + } +} diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/domain/model/DeliveryResponsibilityEnumeration.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/domain/model/DeliveryResponsibilityEnumeration.java new file mode 100644 index 00000000..0bdc8a87 --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/domain/model/DeliveryResponsibilityEnumeration.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 Volkswagen AG + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.eclipse.tractusx.puris.backend.delivery.domain.model; + +public enum DeliveryResponsibilityEnumeration { + CUSTOMER, SUPPLIER, PARTIAL +} diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/domain/model/IncotermEnumeration.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/domain/model/IncotermEnumeration.java index 3d79adda..995b0bc9 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/domain/model/IncotermEnumeration.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/domain/model/IncotermEnumeration.java @@ -45,4 +45,33 @@ public enum IncotermEnumeration { public String getValue() { return value; } + + public DeliveryResponsibilityEnumeration getResponsibility() { + switch (this) { + case EXW: + return DeliveryResponsibilityEnumeration.CUSTOMER; + case FCA: + return DeliveryResponsibilityEnumeration.PARTIAL; + case FAS: + return DeliveryResponsibilityEnumeration.PARTIAL; + case FOB: + return DeliveryResponsibilityEnumeration.PARTIAL; + case CFR: + return DeliveryResponsibilityEnumeration.PARTIAL; + case CIF: + return DeliveryResponsibilityEnumeration.PARTIAL; + case DAP: + return DeliveryResponsibilityEnumeration.SUPPLIER; + case DPU: + return DeliveryResponsibilityEnumeration.SUPPLIER; + case CPT: + return DeliveryResponsibilityEnumeration.SUPPLIER; + case CIP: + return DeliveryResponsibilityEnumeration.SUPPLIER; + case DDP: + return DeliveryResponsibilityEnumeration.SUPPLIER; + default: + throw new IllegalArgumentException("Unknown Incoterm"); + } + } } diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/adapter/DeliveryInformationSammMapper.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/adapter/DeliveryInformationSammMapper.java new file mode 100644 index 00000000..46629942 --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/adapter/DeliveryInformationSammMapper.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2024 Volkswagen AG + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.eclipse.tractusx.puris.backend.delivery.logic.adapter; + +import org.eclipse.tractusx.puris.backend.common.domain.model.measurement.ItemQuantityEntity; +import org.eclipse.tractusx.puris.backend.delivery.domain.model.EventTypeEnumeration; +import org.eclipse.tractusx.puris.backend.delivery.domain.model.OwnDelivery; +import org.eclipse.tractusx.puris.backend.delivery.domain.model.ReportedDelivery; +import org.eclipse.tractusx.puris.backend.delivery.logic.dto.deliverysamm.Delivery; +import org.eclipse.tractusx.puris.backend.delivery.logic.dto.deliverysamm.DeliveryInformation; +import org.eclipse.tractusx.puris.backend.delivery.logic.dto.deliverysamm.Location; +import org.eclipse.tractusx.puris.backend.delivery.logic.dto.deliverysamm.OrderPositionReference; +import org.eclipse.tractusx.puris.backend.delivery.logic.dto.deliverysamm.Position; +import org.eclipse.tractusx.puris.backend.delivery.logic.dto.deliverysamm.TransitEvent; +import org.eclipse.tractusx.puris.backend.delivery.logic.dto.deliverysamm.TransitLocations; +import org.eclipse.tractusx.puris.backend.masterdata.domain.model.Material; +import org.eclipse.tractusx.puris.backend.masterdata.domain.model.Partner; +import org.eclipse.tractusx.puris.backend.masterdata.logic.service.MaterialPartnerRelationService; +import org.eclipse.tractusx.puris.backend.masterdata.logic.service.MaterialService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import lombok.extern.slf4j.Slf4j; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class DeliveryInformationSammMapper { + @Autowired + private MaterialPartnerRelationService mprService; + + @Autowired + private MaterialService materialService; + + public DeliveryInformation ownDeliveryToSamm(List deliveryList) { + if (deliveryList == null || deliveryList.isEmpty()) { + log.warn("Can't map empty list"); + return null; + } + Partner partner = deliveryList.get(0).getPartner(); + if (deliveryList.stream().anyMatch(deli -> !deli.getPartner().equals(partner))) { + log.warn("Can't map delivery list with different partners"); + return null; + } + Material material = deliveryList.get(0).getMaterial(); + if (deliveryList.stream().anyMatch(deli -> !deli.getMaterial().equals(material))) { + log.warn("Can't map delivery list with different materials"); + return null; + } + var groupedByPositionAttributes = deliveryList + .stream() + .collect(Collectors.groupingBy(prod -> new PositionsMappingHelper( + prod.getCustomerOrderNumber(), + prod.getSupplierOrderNumber(), + prod.getCustomerOrderPositionNumber() + ))); + DeliveryInformation samm = new DeliveryInformation(); + var matNumberCx = material.isProductFlag() ? material.getMaterialNumberCx() : mprService.find(material, partner).getPartnerCXNumber(); + samm.setMaterialGlobalAssetId(matNumberCx); + + var posList = new HashSet(); + samm.setPositions(posList); + for (var mappingHelperListEntry : groupedByPositionAttributes.entrySet()) { + var key = mappingHelperListEntry.getKey(); + var delivery = mappingHelperListEntry.getValue().get(0); + Position position = new Position(); + + posList.add(position); + if (key.customerOrderId != null || key.customerOrderPositionId != null) { + OrderPositionReference opr = new OrderPositionReference( + delivery.getSupplierOrderNumber(), + delivery.getCustomerOrderNumber(), + delivery.getCustomerOrderPositionNumber() + ); + position.setOrderPositionReference(opr); + } + var deliveries = new HashSet(); + position.setDeliveries(deliveries); + for (var v : mappingHelperListEntry.getValue()) { + ItemQuantityEntity itemQuantityEntity = new ItemQuantityEntity(v.getQuantity(), v.getMeasurementUnit()); + Set events = new HashSet(); + events.add(new TransitEvent(v.getDateOfDeparture(), v.getDepartureType())); + events.add(new TransitEvent(v.getDateOfArrival(), v.getArrivalType())); + TransitLocations locations = new TransitLocations(new Location(v.getOriginBpna(), v.getOriginBpns()), new Location(v.getDestinationBpna(), v.getDestinationBpns())); + Delivery newDelivery = new Delivery( + itemQuantityEntity, new Date(), events, locations, v.getTrackingNumber(), v.getIncoterm()); + deliveries.add(newDelivery); + } + } + return samm; + } + + public List sammToReportedDeliveries(DeliveryInformation samm, Partner partner) { + String matNbrCatenaX = samm.getMaterialGlobalAssetId(); + ArrayList outputList = new ArrayList<>(); + var mpr = mprService.findByPartnerAndPartnerCXNumber(partner, matNbrCatenaX); + Material material = materialService.findByMaterialNumberCx(matNbrCatenaX); + if (material == null && mpr == null) { + log.warn("Could not identify material with CatenaXNbr " + matNbrCatenaX); + return outputList; + } + if (material == null) { + material = mpr.getMaterial(); + } + + for (var position : samm.getPositions()) { + String supplierOrderNumber = null, customerOrderPositionNumber = null, customerOrderNumber = null; + if (position.getOrderPositionReference() != null) { + supplierOrderNumber = position.getOrderPositionReference().getSupplierOrderId(); + customerOrderNumber = position.getOrderPositionReference().getCustomerOrderId(); + customerOrderPositionNumber = position.getOrderPositionReference().getCustomerOrderPositionId(); + } + for (var delivery : position.getDeliveries()) { + var builder = ReportedDelivery.builder(); + var arrivalEvent = delivery.getTransitEvents().stream() + .filter(e -> e.getEventType().equals(EventTypeEnumeration.ACTUAL_ARRIVAL) || e.getEventType().equals(EventTypeEnumeration.ESTIMATED_ARRIVAL)) + .findFirst().get(); + var departureEvent = delivery.getTransitEvents().stream() + .filter(e -> e.getEventType().equals(EventTypeEnumeration.ACTUAL_DEPARTURE) || e.getEventType().equals(EventTypeEnumeration.ESTIMATED_DEPARTURE)) + .findFirst().get(); + var newDelivery = builder + .material(material) + .partner(partner) + .customerOrderNumber(customerOrderNumber) + .customerOrderPositionNumber(customerOrderPositionNumber) + .supplierOrderNumber(supplierOrderNumber) + .quantity(delivery.getDeliveryQuantity().getValue()) + .measurementUnit(delivery.getDeliveryQuantity().getUnit()) + .arrivalType(arrivalEvent.getEventType()) + .dateOfArrival(arrivalEvent.getDateTimeOfEvent()) + .departureType(departureEvent.getEventType()) + .dateOfDeparture(departureEvent.getDateTimeOfEvent()) + .originBpns(delivery.getTransitLocations().getOrigin().getBpnsProperty()) + .originBpna(delivery.getTransitLocations().getOrigin().getBpnaProperty()) + .destinationBpns(delivery.getTransitLocations().getDestination().getBpnsProperty()) + .destinationBpna(delivery.getTransitLocations().getDestination().getBpnaProperty()) + .trackingNumber(delivery.getTrackingNumber()) + .incoterm(delivery.getIncoterm()) + .build(); + outputList.add(newDelivery); + } + } + return outputList; + } + + private record PositionsMappingHelper(String customerOrderId, String supplierOrderId, String customerOrderPositionId) {} +} diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/DeliveryDto.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/DeliveryDto.java index 19dbd6e1..909b0b30 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/DeliveryDto.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/DeliveryDto.java @@ -78,4 +78,6 @@ public class DeliveryDto implements Serializable { private Date dateOfArrival; private EventTypeEnumeration departureType; private EventTypeEnumeration arrivalType; + + private boolean isReported; } diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/Delivery.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/Delivery.java new file mode 100644 index 00000000..a9c6b7ca --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/Delivery.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2024 Volkswagen AG + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.eclipse.tractusx.puris.backend.delivery.logic.dto.deliverysamm; + +import java.util.Date; +import java.util.Objects; +import java.util.Set; + +import org.eclipse.tractusx.puris.backend.common.domain.model.measurement.ItemQuantityEntity; +import org.eclipse.tractusx.puris.backend.common.util.PatternStore; +import org.eclipse.tractusx.puris.backend.delivery.domain.model.IncotermEnumeration; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@NoArgsConstructor +@ToString +public class Delivery { + + @NotNull + private ItemQuantityEntity deliveryQuantity; + + @NotNull + private Date lastUpdatedOnDateTime; + + @NotNull + @Size(min = 1, max = 2) + private Set transitEvents; + + @NotNull + private TransitLocations transitLocations; + + @Pattern(regexp = PatternStore.NON_EMPTY_NON_VERTICAL_WHITESPACE_STRING) + private String trackingNumber; + + private IncotermEnumeration incoterm; + + @JsonCreator + public Delivery(@JsonProperty(value = "deliveryQuantity") ItemQuantityEntity deliveryQuantity, + @JsonProperty(value = "lastUpdatedOnDateTime") Date lastUpdatedOnDateTime, + @JsonProperty(value = "transitEvents") Set transitEvents, + @JsonProperty(value = "transitLocations") TransitLocations transitLocations, + @JsonProperty(value = "trackingNumber") String trackingNumber, + @JsonProperty(value = "incoterm") IncotermEnumeration incoterm) { + this.deliveryQuantity = deliveryQuantity; + this.lastUpdatedOnDateTime = lastUpdatedOnDateTime; + this.transitEvents = transitEvents; + this.transitLocations = transitLocations; + this.trackingNumber = trackingNumber; + this.incoterm = incoterm; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final Delivery that = (Delivery) o; + return Objects.equals(deliveryQuantity, that.deliveryQuantity) + && Objects.equals(lastUpdatedOnDateTime, that.lastUpdatedOnDateTime) + && Objects.equals(transitEvents, that.transitEvents) + && Objects.equals(transitLocations, that.transitLocations) + && Objects.equals(trackingNumber, that.trackingNumber) && Objects.equals(incoterm, that.incoterm); + } + + @Override + public int hashCode() { + return Objects.hash(deliveryQuantity, lastUpdatedOnDateTime, transitEvents, transitLocations, trackingNumber, + incoterm); + } +} diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/DeliveryInformation.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/DeliveryInformation.java new file mode 100644 index 00000000..999a71c7 --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/DeliveryInformation.java @@ -0,0 +1,76 @@ + +/* + * Copyright (c) 2024 Volkswagen AG + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.eclipse.tractusx.puris.backend.delivery.logic.dto.deliverysamm; + +import java.util.HashSet; +import java.util.Objects; + +import org.eclipse.tractusx.puris.backend.common.util.PatternStore; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@NoArgsConstructor +@ToString +public class DeliveryInformation { + + @NotNull + private HashSet positions; + + @NotNull + @Pattern(regexp = PatternStore.URN_OR_UUID_STRING) + private String materialGlobalAssetId; + + @JsonCreator + public DeliveryInformation(@JsonProperty(value = "positions") HashSet positions, + @JsonProperty(value = "materialGlobalAssetId") String materialGlobalAssetId) { + this.positions = positions; + this.materialGlobalAssetId = materialGlobalAssetId; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final DeliveryInformation that = (DeliveryInformation) o; + return Objects.equals(positions, that.positions) + && Objects.equals(materialGlobalAssetId, that.materialGlobalAssetId); + } + + @Override + public int hashCode() { + return Objects.hash(positions, materialGlobalAssetId); + } +} diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/Location.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/Location.java new file mode 100644 index 00000000..6d92121e --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/Location.java @@ -0,0 +1,73 @@ + +/* + * Copyright (c) 2024 Volkswagen AG + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.eclipse.tractusx.puris.backend.delivery.logic.dto.deliverysamm; + +import java.util.Objects; + +import org.eclipse.tractusx.puris.backend.common.util.PatternStore; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@NoArgsConstructor +@ToString +public class Location { + @Pattern(regexp = PatternStore.BPNA_STRING) + private String bpnaProperty; + + @NotNull + @Pattern(regexp = PatternStore.BPNS_STRING) + private String bpnsProperty; + + @JsonCreator + public Location(@JsonProperty(value = "bpnaProperty") String bpnaProperty, + @JsonProperty(value = "bpnsProperty") String bpnsProperty) { + this.bpnaProperty = bpnaProperty; + this.bpnsProperty = bpnsProperty; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final Location that = (Location) o; + return Objects.equals(bpnaProperty, that.bpnaProperty) && Objects.equals(bpnsProperty, that.bpnsProperty); + } + + @Override + public int hashCode() { + return Objects.hash(bpnaProperty, bpnsProperty); + } +} diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/OrderPositionReference.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/OrderPositionReference.java new file mode 100644 index 00000000..1886b4ea --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/OrderPositionReference.java @@ -0,0 +1,73 @@ + +/* + * Copyright (c) 2024 Volkswagen AG + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.eclipse.tractusx.puris.backend.delivery.logic.dto.deliverysamm; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@NoArgsConstructor +@ToString +public class OrderPositionReference { + private String supplierOrderId; + + @NotNull + private String customerOrderId; + + @NotNull + private String customerOrderPositionId; + + @JsonCreator + public OrderPositionReference(@JsonProperty(value = "supplierOrderId") String supplierOrderId, + @JsonProperty(value = "customerOrderId") String customerOrderId, + @JsonProperty(value = "customerOrderPositionId") String customerOrderPositionId) { + this.supplierOrderId = supplierOrderId; + this.customerOrderId = customerOrderId; + this.customerOrderPositionId = customerOrderPositionId; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final OrderPositionReference that = (OrderPositionReference) o; + return Objects.equals(supplierOrderId, that.supplierOrderId) + && Objects.equals(customerOrderId, that.customerOrderId) + && Objects.equals(customerOrderPositionId, that.customerOrderPositionId); + } + + @Override + public int hashCode() { + return Objects.hash(supplierOrderId, customerOrderId, customerOrderPositionId); + } +} diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/Position.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/Position.java new file mode 100644 index 00000000..8c3c3cd8 --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/Position.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2024 Volkswagen AG + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.eclipse.tractusx.puris.backend.delivery.logic.dto.deliverysamm; + +import java.util.HashSet; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@NoArgsConstructor +@ToString +public class Position { + private OrderPositionReference orderPositionReference; + + @NotNull + private HashSet deliveries; + + @JsonCreator + public Position( + @JsonProperty(value = "orderPositionReference") OrderPositionReference orderPositionReference, + @JsonProperty(value = "deliveries") HashSet deliveries) { + this.orderPositionReference = orderPositionReference; + this.deliveries = deliveries; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final Position that = (Position) o; + return Objects.equals(orderPositionReference, that.orderPositionReference) + && Objects.equals(deliveries, that.deliveries); + } + + @Override + public int hashCode() { + return Objects.hash(orderPositionReference, deliveries); + } +} diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/TransitEvent.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/TransitEvent.java new file mode 100644 index 00000000..806b7e04 --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/TransitEvent.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2024 Volkswagen AG + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.eclipse.tractusx.puris.backend.delivery.logic.dto.deliverysamm; + +import java.util.Date; +import java.util.Objects; + +import org.eclipse.tractusx.puris.backend.delivery.domain.model.EventTypeEnumeration; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@NoArgsConstructor +@ToString +public class TransitEvent { + + @NotNull + private Date dateTimeOfEvent; + + @NotNull + private EventTypeEnumeration eventType; + + @JsonCreator + public TransitEvent(@JsonProperty(value = "dateTimeOfEvent") Date dateTimeOfEvent, + @JsonProperty(value = "eventType") EventTypeEnumeration eventType) { + this.dateTimeOfEvent = dateTimeOfEvent; + this.eventType = eventType; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final TransitEvent that = (TransitEvent) o; + return Objects.equals(dateTimeOfEvent, that.dateTimeOfEvent) && Objects.equals(eventType, that.eventType); + } + + @Override + public int hashCode() { + return Objects.hash(dateTimeOfEvent, eventType); + } +} diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/TransitLocations.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/TransitLocations.java new file mode 100644 index 00000000..6a75a84e --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/dto/deliverysamm/TransitLocations.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024 Volkswagen AG + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.eclipse.tractusx.puris.backend.delivery.logic.dto.deliverysamm; + +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +/** + * Generated class for Transit Locations. Transit locations describes the + * specific location where products undergo the process of being transported + * from the source or production facility (origin) to the designated endpoint + * location (destination). + */ +@Getter +@Setter +@NoArgsConstructor +@ToString +public class TransitLocations { + + @NotNull + private Location origin; + + @NotNull + private Location destination; + + @JsonCreator + public TransitLocations(@JsonProperty(value = "origin") Location origin, + @JsonProperty(value = "destination") Location destination) { + this.origin = origin; + this.destination = destination; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final TransitLocations that = (TransitLocations) o; + return Objects.equals(origin, that.origin) && Objects.equals(destination, that.destination); + } + + @Override + public int hashCode() { + return Objects.hash(origin, destination); + } +} diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/service/DeliveryRequestApiService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/service/DeliveryRequestApiService.java new file mode 100644 index 00000000..c4c9b1da --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/service/DeliveryRequestApiService.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2024 Volkswagen AG + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.eclipse.tractusx.puris.backend.delivery.logic.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; + +import java.util.Optional; + +import org.eclipse.tractusx.puris.backend.common.edc.domain.model.SubmodelType; +import org.eclipse.tractusx.puris.backend.common.edc.logic.service.EdcAdapterService; +import org.eclipse.tractusx.puris.backend.delivery.logic.adapter.DeliveryInformationSammMapper; +import org.eclipse.tractusx.puris.backend.delivery.logic.dto.deliverysamm.DeliveryInformation; +import org.eclipse.tractusx.puris.backend.masterdata.domain.model.Material; +import org.eclipse.tractusx.puris.backend.masterdata.domain.model.MaterialPartnerRelation; +import org.eclipse.tractusx.puris.backend.masterdata.domain.model.Partner; +import org.eclipse.tractusx.puris.backend.masterdata.logic.service.MaterialPartnerRelationService; +import org.eclipse.tractusx.puris.backend.masterdata.logic.service.MaterialService; +import org.eclipse.tractusx.puris.backend.masterdata.logic.service.PartnerService; +import org.eclipse.tractusx.puris.backend.stock.logic.dto.itemstocksamm.DirectionCharacteristic; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +/** + * This class is a Service that handles requests for Delivery Information + */ +public class DeliveryRequestApiService { + @Autowired + private PartnerService partnerService; + @Autowired + private MaterialService materialService; + @Autowired + private MaterialPartnerRelationService mprService; + @Autowired + private OwnDeliveryService ownDeliveryService; + @Autowired + private ReportedDeliveryService reportedDeliveryService; + @Autowired + private EdcAdapterService edcAdapterService; + @Autowired + private DeliveryInformationSammMapper sammMapper; + @Autowired + private ObjectMapper objectMapper; + + public DeliveryInformation handleDeliverySubmodelRequest(String bpnl, String materialNumberCx) { + Partner partner = partnerService.findByBpnl(bpnl); + if (partner == null) { + log.error("Unknown Partner BPNL " + bpnl); + return null; + } + MaterialPartnerRelation mpr = mprService.findByPartnerAndPartnerCXNumber(partner, materialNumberCx); + Material material = materialService.findByMaterialNumberCx(materialNumberCx); + if (material == null && mpr == null) { + log.error("Unknown Material " + materialNumberCx); + return null; + } + if (material == null) { + material = mpr.getMaterial(); + } + var currentDeliveries = ownDeliveryService.findAllByFilters(Optional.of(material.getOwnMaterialNumber()), Optional.empty(), Optional.of(partner.getBpnl())); + return sammMapper.ownDeliveryToSamm(currentDeliveries); + } + + public void doReportedDeliveryRequest(Partner partner, Material material) { + try { + var mpr = mprService.find(material, partner); + var direction = material.isMaterialFlag() ? DirectionCharacteristic.OUTBOUND : DirectionCharacteristic.INBOUND; + var data = edcAdapterService.doSubmodelRequest(SubmodelType.DELIVERY, mpr, direction, 1); + var samm = objectMapper.treeToValue(data, DeliveryInformation.class); + var deliveries = sammMapper.sammToReportedDeliveries(samm, partner); + for (var delivery : deliveries) { + var deliveryPartner = delivery.getPartner(); + var deliveryMaterial = delivery.getMaterial(); + if (!partner.equals(deliveryPartner) || !material.equals(deliveryMaterial)) { + log.warn("Received inconsistent data from " + partner.getBpnl() + "\n" + deliveries); + return; + } + } + // delete older data: + var oldDeliveries = reportedDeliveryService.findAllByFilters(Optional.of(material.getOwnMaterialNumber()), Optional.empty(), Optional.of(partner.getBpnl())); + for (var oldDelivery : oldDeliveries) { + reportedDeliveryService.delete(oldDelivery.getUuid()); + } + for (var newDelivery : deliveries) { + reportedDeliveryService.create(newDelivery); + } + log.info("Updated Reported Deliveries for " + material.getOwnMaterialNumber() + " and partner " + partner.getBpnl()); + } catch (Exception e) { + log.error("Error in Reported Deliveries Request for " + material.getOwnMaterialNumber() + " and partner " + partner.getBpnl(), e); + } + } +} diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/service/OwnDeliveryService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/service/OwnDeliveryService.java index a99dd661..039185e0 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/service/OwnDeliveryService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/service/OwnDeliveryService.java @@ -43,6 +43,8 @@ public class OwnDeliveryService { protected final Function validator; + private Partner ownPartnerEntity; + public OwnDeliveryService(DeliveryRepository repository, PartnerService partnerService) { this.repository = repository; this.partnerService = partnerService; @@ -63,11 +65,14 @@ public final List findAllByOwnMaterialNumber(String ownMaterialNumb .toList(); } - public final List findAllByFilters(Optional ownMaterialNumber, Optional bpnl) { + public final List findAllByFilters(Optional ownMaterialNumber, Optional bpns, Optional bpnl) { Stream stream = repository.findAll().stream(); if (ownMaterialNumber.isPresent()) { stream = stream.filter(delivery -> delivery.getMaterial().getOwnMaterialNumber().equals(ownMaterialNumber.get())); } + if (bpns.isPresent()) { + stream = stream.filter(delivery -> delivery.getDestinationBpns().equals(bpns.get()) || delivery.getOriginBpns().equals(bpns.get())); + } if (bpnl.isPresent()) { stream = stream.filter(delivery -> delivery.getPartner().getBpnl().equals(bpnl.get())); } @@ -111,21 +116,21 @@ public final void delete(UUID id) { } public boolean validate(OwnDelivery delivery) { - Partner ownPartnerEntity = partnerService.getOwnPartnerEntity(); + if (ownPartnerEntity == null) { + ownPartnerEntity = partnerService.getOwnPartnerEntity(); + } return delivery.getQuantity() > 0 && delivery.getMeasurementUnit() != null && delivery.getMaterial() != null && delivery.getPartner() != null && delivery.getTrackingNumber() != null && - delivery.getIncoterm() != null && + validateResponsibility(delivery) && this.validateTransitEvent(delivery) && !delivery.getPartner().equals(ownPartnerEntity) && - !ownPartnerEntity.getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getDestinationBpns())) && (( delivery.getCustomerOrderNumber() != null && - delivery.getCustomerOrderPositionNumber() != null && - delivery.getSupplierOrderNumber() != null + delivery.getCustomerOrderPositionNumber() != null ) || ( delivery.getCustomerOrderNumber() == null && delivery.getCustomerOrderPositionNumber() == null && @@ -142,4 +147,30 @@ private boolean validateTransitEvent(OwnDelivery delivery) { !(delivery.getDepartureType() == EventTypeEnumeration.ESTIMATED_DEPARTURE && delivery.getArrivalType() == EventTypeEnumeration.ACTUAL_ARRIVAL) && delivery.getDateOfDeparture().getTime() < delivery.getDateOfArrival().getTime(); } + + private boolean validateResponsibility(OwnDelivery delivery) { + if (ownPartnerEntity == null) { + ownPartnerEntity = partnerService.getOwnPartnerEntity(); + } + return delivery.getIncoterm() != null && switch (delivery.getIncoterm().getResponsibility()) { + case SUPPLIER -> + delivery.getMaterial().isProductFlag() && + ownPartnerEntity.getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getOriginBpns())) && + delivery.getPartner().getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getDestinationBpns())); + case CUSTOMER -> + delivery.getMaterial().isMaterialFlag() && + delivery.getPartner().getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getOriginBpns())) && + ownPartnerEntity.getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getDestinationBpns())); + case PARTIAL -> + ( + delivery.getMaterial().isProductFlag() && + ownPartnerEntity.getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getOriginBpns())) && + delivery.getPartner().getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getDestinationBpns())) + ) || ( + delivery.getMaterial().isMaterialFlag() && + delivery.getPartner().getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getOriginBpns())) && + ownPartnerEntity.getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getDestinationBpns())) + ); + }; + } } diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/service/ReportedDeliveryService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/service/ReportedDeliveryService.java index a791478b..ee99d61c 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/service/ReportedDeliveryService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/service/ReportedDeliveryService.java @@ -29,16 +29,23 @@ import org.eclipse.tractusx.puris.backend.delivery.domain.model.EventTypeEnumeration; import org.eclipse.tractusx.puris.backend.delivery.domain.model.ReportedDelivery; import org.eclipse.tractusx.puris.backend.delivery.domain.repository.ReportedDeliveryRepository; +import org.eclipse.tractusx.puris.backend.masterdata.domain.model.Partner; +import org.eclipse.tractusx.puris.backend.masterdata.logic.service.PartnerService; import org.springframework.stereotype.Service; @Service public class ReportedDeliveryService { public final ReportedDeliveryRepository repository; + private final PartnerService partnerService; + protected final Function validator; - public ReportedDeliveryService(ReportedDeliveryRepository repository) { + private Partner ownPartnerEntity; + + public ReportedDeliveryService(ReportedDeliveryRepository repository, PartnerService partnerService) { this.repository = repository; + this.partnerService = partnerService; this.validator = this::validate; } @@ -55,11 +62,14 @@ public final ReportedDelivery findById(UUID id) { return repository.findById(id).orElse(null); } - public final List findAllByFilters(Optional ownMaterialNumber, Optional bpnl) { + public final List findAllByFilters(Optional ownMaterialNumber, Optional bpns, Optional bpnl) { Stream stream = repository.findAll().stream(); if (ownMaterialNumber.isPresent()) { stream = stream.filter(delivery -> delivery.getMaterial().getOwnMaterialNumber().equals(ownMaterialNumber.get())); } + if (bpns.isPresent()) { + stream = stream.filter(delivery -> delivery.getDestinationBpns().equals(bpns.get()) || delivery.getOriginBpns().equals(bpns.get())); + } if (bpnl.isPresent()) { stream = stream.filter(delivery -> delivery.getPartner().getBpnl().equals(bpnl.get())); } @@ -105,13 +115,11 @@ public boolean validate(ReportedDelivery delivery) { delivery.getMaterial() != null && delivery.getPartner() != null && delivery.getTrackingNumber() != null && - delivery.getIncoterm() != null && + validateResponsibility(delivery) && this.validateTransitEvent(delivery) && - !delivery.getPartner().getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getOriginBpns())) && (( delivery.getCustomerOrderNumber() != null && - delivery.getCustomerOrderPositionNumber() != null && - delivery.getSupplierOrderNumber() != null + delivery.getCustomerOrderPositionNumber() != null ) || ( delivery.getCustomerOrderNumber() == null && delivery.getCustomerOrderPositionNumber() == null && @@ -128,4 +136,31 @@ private boolean validateTransitEvent(ReportedDelivery delivery) { !(delivery.getDepartureType() == EventTypeEnumeration.ESTIMATED_DEPARTURE && delivery.getArrivalType() == EventTypeEnumeration.ACTUAL_ARRIVAL) && delivery.getDateOfDeparture().getTime() < delivery.getDateOfArrival().getTime(); } + + private boolean validateResponsibility(ReportedDelivery delivery) { + if (ownPartnerEntity == null) { + ownPartnerEntity = partnerService.getOwnPartnerEntity(); + } + return delivery.getIncoterm() != null && switch (delivery.getIncoterm().getResponsibility()) { + case CUSTOMER -> + delivery.getMaterial().isProductFlag() && + ownPartnerEntity.getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getDestinationBpns())) && + delivery.getPartner().getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getOriginBpns())); + case SUPPLIER -> + delivery.getMaterial().isMaterialFlag() && + delivery.getPartner().getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getDestinationBpns())) && + ownPartnerEntity.getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getOriginBpns())); + case PARTIAL -> + ( + delivery.getMaterial().isMaterialFlag() && + ownPartnerEntity.getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getDestinationBpns())) && + delivery.getPartner().getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getOriginBpns())) + + ) || ( + delivery.getMaterial().isProductFlag() && + delivery.getPartner().getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getDestinationBpns())) && + ownPartnerEntity.getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getOriginBpns())) + ); + }; + } } diff --git a/frontend/DEPENDENCIES b/frontend/DEPENDENCIES index dbc2562c..09e994b8 100644 --- a/frontend/DEPENDENCIES +++ b/frontend/DEPENDENCIES @@ -211,7 +211,7 @@ npm/npmjs/-/reusify/1.0.4, MIT, approved, clearlydefined npm/npmjs/-/rimraf/3.0.2, ISC, approved, clearlydefined npm/npmjs/-/rollup/4.9.5, MIT, approved, clearlydefined npm/npmjs/-/run-parallel/1.2.0, MIT, approved, clearlydefined -npm/npmjs/-/scheduler/0.23.0, MIT, approved, clearlydefined +npm/npmjs/-/scheduler/0.23.0, MIT, approved, #14589 npm/npmjs/-/semver/6.3.1, ISC, approved, clearlydefined npm/npmjs/-/semver/7.5.4, ISC, approved, clearlydefined npm/npmjs/-/shebang-command/2.0.0, MIT, approved, clearlydefined