diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/DataInjectionCommandLineRunner.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/DataInjectionCommandLineRunner.java index b84e8c3d..55ee9109 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/DataInjectionCommandLineRunner.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/DataInjectionCommandLineRunner.java @@ -78,7 +78,6 @@ public class DataInjectionCommandLineRunner implements CommandLineRunner { @Autowired private VariablesService variablesService; - @Autowired private ErpAdapterRequestService erpAdapterRequestService; @@ -490,5 +489,4 @@ private Material getNewCentralControlUnitMaterial() { material.setName("Central Control Unit"); return material; } - } 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 468ea19d..7df8c3e8 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 @@ -96,6 +96,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { "/planned-production/**", "/material-demand/**", "/delivery-information/**", + "/days-of-supply/**", "/edc/**", "/erp-adapter/**", "/parttypeinformation/**" 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 df82500e..3b75b5ff 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 @@ -108,9 +108,9 @@ public List getAllDeliveries(String ownMaterialNumber, Optional { +public interface DeliveryRepository extends JpaRepository { } diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/domain/repository/OwnDeliveryRepository.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/domain/repository/OwnDeliveryRepository.java new file mode 100644 index 00000000..f1111d00 --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/domain/repository/OwnDeliveryRepository.java @@ -0,0 +1,27 @@ +/* + * 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.repository; + +import org.eclipse.tractusx.puris.backend.delivery.domain.model.OwnDelivery; + +public interface OwnDeliveryRepository extends DeliveryRepository { + +} diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/domain/repository/ReportedDeliveryRepository.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/domain/repository/ReportedDeliveryRepository.java index 6dc5ef77..dfeaec5c 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/domain/repository/ReportedDeliveryRepository.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/domain/repository/ReportedDeliveryRepository.java @@ -20,11 +20,8 @@ package org.eclipse.tractusx.puris.backend.delivery.domain.repository; -import java.util.UUID; - import org.eclipse.tractusx.puris.backend.delivery.domain.model.ReportedDelivery; -import org.springframework.data.jpa.repository.JpaRepository; -public interface ReportedDeliveryRepository extends JpaRepository { +public interface ReportedDeliveryRepository extends DeliveryRepository { } 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 index b9ecfc97..1711f3d2 100644 --- 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 @@ -130,8 +130,9 @@ public DeliveryInformation handleDeliverySubmodelRequest(String bpnl, String mat List currentDeliveries = ownDeliveryService.findAllByFilters( Optional.of(material.getOwnMaterialNumber()), Optional.empty(), - Optional.of(partner.getBpnl()) - ); + Optional.of(partner.getBpnl()), + Optional.empty(), + Optional.empty()); Predicate parnterRoleDirectionPredicate = partnerRoleDirectionPredicate(partnerIsCustomer, mpr); currentDeliveries = currentDeliveries.stream().filter( @@ -167,7 +168,7 @@ public void doReportedDeliveryRequest(Partner partner, Material material) { } } // delete older data: - var oldDeliveries = reportedDeliveryService.findAllByFilters(Optional.of(material.getOwnMaterialNumber()), Optional.empty(), Optional.of(partner.getBpnl())); + var oldDeliveries = reportedDeliveryService.findAllByFilters(Optional.of(material.getOwnMaterialNumber()), Optional.empty(), Optional.of(partner.getBpnl()), Optional.empty(), Optional.empty()); for (var oldDelivery : oldDeliveries) { reportedDeliveryService.delete(oldDelivery.getUuid()); } diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/service/DeliveryService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/service/DeliveryService.java new file mode 100644 index 00000000..a0904183 --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/delivery/logic/service/DeliveryService.java @@ -0,0 +1,123 @@ +/* + * 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 java.time.Instant; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Stream; + +import org.eclipse.tractusx.puris.backend.delivery.domain.model.Delivery; +import org.eclipse.tractusx.puris.backend.delivery.domain.repository.DeliveryRepository; +import org.eclipse.tractusx.puris.backend.stock.logic.dto.itemstocksamm.DirectionCharacteristic; +import org.springframework.beans.factory.annotation.Autowired; + +public abstract class DeliveryService { + @Autowired + protected DeliveryRepository repository; + + public final List findAll() { + return repository.findAll(); + } + + public final T findById(UUID id) { + return repository.findById(id).orElse(null); + } + + public final List findAllByFilters( + Optional ownMaterialNumber, + Optional bpns, + Optional bpnl, + Optional day, + Optional direction) { + 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())); + } + if (day.isPresent()) { + LocalDate localDayDate = Instant.ofEpochMilli(day.get().getTime()) + .atOffset(ZoneOffset.UTC) + .toLocalDate(); + stream = stream.filter(delivery -> { + long time = direction.get() == DirectionCharacteristic.INBOUND + ? delivery.getDateOfArrival().getTime() + : delivery.getDateOfDeparture().getTime(); + LocalDate deliveryDayDate = Instant.ofEpochMilli(time) + .atOffset(ZoneOffset.UTC) + .toLocalDate(); + return deliveryDayDate.getDayOfMonth() == localDayDate.getDayOfMonth(); + }); + } + if (direction.isPresent()) { + if (direction.get() == DirectionCharacteristic.INBOUND) { + stream = stream.filter(delivery -> delivery.getDestinationBpns().equals(bpns.get())); + } else { + stream = stream.filter(delivery -> delivery.getOriginBpns().equals(bpns.get())); + } + } + return stream.toList(); + } + + public final double getSumOfQuantities(List deliveries) { + double sum = 0; + for (T delivery : deliveries) { + sum += delivery.getQuantity(); + } + return sum; + } + + public final List getQuantityForDays(String material, String partnerBpnl, String siteBpns, DirectionCharacteristic direction, int numberOfDays) { + List deliveryQtys = new ArrayList<>(); + LocalDate localDate = LocalDate.now(); + + for (int i = 0; i < numberOfDays; i++) { + Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); + List deliveries = findAllByFilters(Optional.of(material), Optional.of(siteBpns), Optional.of(partnerBpnl), Optional.of(date), Optional.of(direction)); + deliveryQtys.add(getSumOfQuantities(deliveries)); + + localDate = localDate.plusDays(1); + } + return deliveryQtys; + } + + public final T update(T delivery) { + if (delivery.getUuid() == null || repository.findById(delivery.getUuid()).isEmpty()) { + return null; + } + return repository.save(delivery); + } + + public final void delete(UUID id) { + repository.deleteById(id); + } +} 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 2ccca9d0..a2e97e6f 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 @@ -22,23 +22,20 @@ import java.util.Date; import java.util.List; -import java.util.Optional; -import java.util.UUID; import java.util.function.Function; -import java.util.stream.Stream; import javax.management.openmbean.KeyAlreadyExistsException; 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.repository.DeliveryRepository; +import org.eclipse.tractusx.puris.backend.delivery.domain.repository.OwnDeliveryRepository; 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 OwnDeliveryService { - public final DeliveryRepository repository; +public class OwnDeliveryService extends DeliveryService { + private final OwnDeliveryRepository repository; private final PartnerService partnerService; @@ -46,16 +43,12 @@ public class OwnDeliveryService { private Partner ownPartnerEntity; - public OwnDeliveryService(DeliveryRepository repository, PartnerService partnerService) { + public OwnDeliveryService(OwnDeliveryRepository repository, PartnerService partnerService) { this.repository = repository; this.partnerService = partnerService; this.validator = this::validate; } - public final List findAll() { - return repository.findAll(); - } - public final List findAllByBpnl(String bpnl) { return repository.findAll().stream().filter(delivery -> delivery.getPartner().getBpnl().equals(bpnl)) .toList(); @@ -66,24 +59,6 @@ public final List findAllByOwnMaterialNumber(String ownMaterialNumb .toList(); } - 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())); - } - return stream.toList(); - } - - public final OwnDelivery findById(UUID id) { - return repository.findById(id).orElse(null); - } - public final OwnDelivery create(OwnDelivery delivery) { if (!validator.apply(delivery)) { throw new IllegalArgumentException("Invalid delivery"); @@ -105,23 +80,12 @@ public final List createAll(List deliveries) { return repository.saveAll(deliveries); } - public final OwnDelivery update(OwnDelivery delivery) { - if (delivery.getUuid() == null || repository.findById(delivery.getUuid()).isEmpty()) { - return null; - } - return repository.save(delivery); - } - - public final void delete(UUID id) { - repository.deleteById(id); - } - public boolean validate(OwnDelivery delivery) { if (ownPartnerEntity == null) { ownPartnerEntity = partnerService.getOwnPartnerEntity(); } return - delivery.getQuantity() > 0 && + delivery.getQuantity() >= 0 && delivery.getMeasurementUnit() != null && delivery.getMaterial() != null && delivery.getPartner() != null && 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 3ff3c60b..f0f4f6d3 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 @@ -22,10 +22,8 @@ import java.util.Date; import java.util.List; -import java.util.Optional; import java.util.UUID; import java.util.function.Function; -import java.util.stream.Stream; import org.eclipse.tractusx.puris.backend.delivery.domain.model.EventTypeEnumeration; import org.eclipse.tractusx.puris.backend.delivery.domain.model.ReportedDelivery; @@ -35,8 +33,8 @@ import org.springframework.stereotype.Service; @Service -public class ReportedDeliveryService { - public final ReportedDeliveryRepository repository; +public class ReportedDeliveryService extends DeliveryService { + private final ReportedDeliveryRepository repository; private final PartnerService partnerService; @@ -50,33 +48,11 @@ public ReportedDeliveryService(ReportedDeliveryRepository repository, PartnerSer this.validator = this::validate; } - public final List findAll() { - return repository.findAll(); - } - public final List findAllByReportedId(UUID reportedId) { return repository.findAll().stream().filter(delivery -> delivery.getPartner().getUuid().equals(reportedId)) .toList(); } - public final ReportedDelivery findById(UUID id) { - return repository.findById(id).orElse(null); - } - - 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())); - } - return stream.toList(); - } - public final ReportedDelivery create(ReportedDelivery delivery) { if (delivery.getUuid() != null && repository.findById(delivery.getUuid()).isPresent()) { return null; @@ -98,17 +74,6 @@ public final List createAll(List deliveries) return repository.saveAll(deliveries); } - public final ReportedDelivery update(ReportedDelivery delivery) { - if (delivery.getUuid() == null || repository.findById(delivery.getUuid()).isEmpty()) { - return null; - } - return repository.save(delivery); - } - - public final void delete(UUID id) { - repository.deleteById(id); - } - public boolean validate(ReportedDelivery delivery) { return delivery.getQuantity() > 0 && diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/controller/DemandController.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/controller/DemandController.java index 79bd61cf..15fb5eca 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/controller/DemandController.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/controller/DemandController.java @@ -91,7 +91,7 @@ public class DemandController { @ResponseBody @Operation(summary = "Get all own demands for the given Material", description = "Get all own demands for the given material number. Optionally the demanding site can be filtered by its bpns.") public List getAllDemands(String ownMaterialNumber, Optional site) { - return ownDemandService.findAllByFilters(Optional.of(ownMaterialNumber), Optional.empty(), site) + return ownDemandService.findAllByFilters(Optional.of(ownMaterialNumber), Optional.empty(), site, Optional.empty()) .stream().map(this::convertToDto).collect(Collectors.toList()); } @@ -171,7 +171,7 @@ public void deleteDemand(@PathVariable UUID id) { ) public List getAllDemandsForPartner(String ownMaterialNumber, Optional bpnl, Optional site) { - return reportedDemandService.findAllByFilters(Optional.of(ownMaterialNumber), bpnl, site) + return reportedDemandService.findAllByFilters(Optional.of(ownMaterialNumber), bpnl, site, Optional.empty()) .stream().map(this::convertToDto).collect(Collectors.toList()); } diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/services/DemandRequestApiService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/services/DemandRequestApiService.java index c3811da1..6d3c363a 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/services/DemandRequestApiService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/services/DemandRequestApiService.java @@ -86,7 +86,7 @@ public ShortTermMaterialDemand handleDemandSubmodelRequest(String bpnl, String m return null; } - var currentDemands = ownDemandService.findAllByFilters(Optional.of(material.getOwnMaterialNumber()), Optional.of(partner.getBpnl()), Optional.empty()); + var currentDemands = ownDemandService.findAllByFilters(Optional.of(material.getOwnMaterialNumber()), Optional.of(partner.getBpnl()), Optional.empty(), Optional.empty()); return sammMapper.ownDemandToSamm(currentDemands, partner, material); } @@ -109,7 +109,7 @@ public void doReportedDemandRequest(Partner partner, Material material) { } } // delete older data: - var oldDemands = reportedDemandService.findAllByFilters(Optional.of(material.getOwnMaterialNumber()), Optional.of(partner.getBpnl()), Optional.empty()); + var oldDemands = reportedDemandService.findAllByFilters(Optional.of(material.getOwnMaterialNumber()), Optional.of(partner.getBpnl()), Optional.empty(), Optional.empty()); for (var oldDemand : oldDemands) { reportedDemandService.delete(oldDemand.getUuid()); } diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/services/DemandService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/services/DemandService.java index 391bbf90..ffde7cdf 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/services/DemandService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/services/DemandService.java @@ -19,6 +19,10 @@ See the NOTICE file(s) distributed with this work for additional */ package org.eclipse.tractusx.puris.backend.demand.logic.services; +import java.time.Instant; +import java.time.LocalDate; +import java.time.ZoneOffset; +import java.util.Date; import java.util.List; import java.util.Optional; import java.util.UUID; @@ -63,7 +67,11 @@ public final List findAllByOwnMaterialNumber(String ownMaterialNumber) .toList(); } - public final List findAllByFilters(Optional ownMaterialNumber, Optional bpnl, Optional demandLocationBpns) { + public final List findAllByFilters( + Optional ownMaterialNumber, + Optional bpnl, + Optional demandLocationBpns, + Optional day) { var stream = repository.findAll().stream(); if (ownMaterialNumber.isPresent()) { stream = stream.filter(demand -> demand.getMaterial().getOwnMaterialNumber().equals(ownMaterialNumber.get())); @@ -74,6 +82,17 @@ public final List findAllByFilters(Optional ownMaterialNumber, if (demandLocationBpns.isPresent()) { stream = stream.filter(demand -> demand.getDemandLocationBpns().equals(demandLocationBpns.get())); } + if (day.isPresent()) { + LocalDate localDayDate = Instant.ofEpochMilli(day.get().getTime()) + .atOffset(ZoneOffset.UTC) + .toLocalDate(); + stream = stream.filter(demand -> { + LocalDate demandDayDate = Instant.ofEpochMilli(demand.getDay().getTime()) + .atOffset(ZoneOffset.UTC) + .toLocalDate(); + return demandDayDate.getDayOfMonth() == localDayDate.getDayOfMonth(); + }); + } return stream.toList(); } diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/services/OwnDemandService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/services/OwnDemandService.java index 68ed3bf2..027a8de2 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/services/OwnDemandService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/demand/logic/services/OwnDemandService.java @@ -19,6 +19,13 @@ See the NOTICE file(s) distributed with this work for additional */ package org.eclipse.tractusx.puris.backend.demand.logic.services; +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Optional; + import org.eclipse.tractusx.puris.backend.demand.domain.model.OwnDemand; import org.eclipse.tractusx.puris.backend.demand.domain.repository.OwnDemandRepository; import org.eclipse.tractusx.puris.backend.masterdata.domain.model.Partner; @@ -32,6 +39,21 @@ public OwnDemandService(OwnDemandRepository repository, PartnerService partnerSe super(repository, partnerService, mprService); } + public final List getQuantityForDays(String material, String partnerBpnl, String siteBpns, int numberOfDays) { + List quantities = new ArrayList<>(); + LocalDate localDate = LocalDate.now(); + + for (int i = 0; i < numberOfDays; i++) { + Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); + List demands = findAllByFilters(Optional.of(material), Optional.of(partnerBpnl), Optional.of(siteBpns), Optional.of(date)); + double demandQuantity = getSumOfQuantities(demands); + quantities.add(demandQuantity); + + localDate = localDate.plusDays(1); + } + return quantities; + } + @Override public boolean validate(OwnDemand demand) { Partner ownPartnerEntity = partnerService.getOwnPartnerEntity(); @@ -48,4 +70,12 @@ public boolean validate(OwnDemand demand) { ownPartnerEntity.getSites().stream().anyMatch(site -> site.getBpns().equals(demand.getDemandLocationBpns())) && (demand.getSupplierLocationBpns() == null || demand.getPartner().getSites().stream().anyMatch(site -> site.getBpns().equals(demand.getSupplierLocationBpns()))); } + + private final double getSumOfQuantities(List demands) { + double sum = 0; + for (OwnDemand demand : demands) { + sum += demand.getQuantity(); + } + return sum; + } } diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/controller/ProductionController.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/controller/ProductionController.java index 259e7289..4420f507 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/controller/ProductionController.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/controller/ProductionController.java @@ -91,7 +91,7 @@ public class ProductionController { @ResponseBody @Operation(summary = "Get all planned productions for the given Material", description = "Get all planned productions for the given material number. Optionally the production site can be filtered by its bpns.") public List getAllProductions(String ownMaterialNumber, Optional site) { - return ownProductionService.findAllByFilters(Optional.of(ownMaterialNumber), Optional.empty(), site) + return ownProductionService.findAllByFilters(Optional.of(ownMaterialNumber), Optional.empty(), site, Optional.empty()) .stream().map(this::convertToDto).collect(Collectors.toList()); } @@ -207,7 +207,7 @@ public void deleteProduction(@PathVariable UUID id) { ) public List getAllProductionsForPartner(String ownMaterialNumber, Optional bpnl, Optional site) { - return reportedProductionService.findAllByFilters(Optional.of(ownMaterialNumber), bpnl, site) + return reportedProductionService.findAllByFilters(Optional.of(ownMaterialNumber), bpnl, site, Optional.empty()) .stream().map(this::convertToDto).collect(Collectors.toList()); } diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/domain/repository/OwnProductionRepository.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/domain/repository/OwnProductionRepository.java index fd4988b3..c8b03cbb 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/domain/repository/OwnProductionRepository.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/domain/repository/OwnProductionRepository.java @@ -21,12 +21,9 @@ See the NOTICE file(s) distributed with this work for additional package org.eclipse.tractusx.puris.backend.production.domain.repository; import org.eclipse.tractusx.puris.backend.production.domain.model.OwnProduction; -import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import java.util.UUID; - @Repository -public interface OwnProductionRepository extends JpaRepository { +public interface OwnProductionRepository extends ProductionRepository { } diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/domain/repository/ProductionRepository.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/domain/repository/ProductionRepository.java new file mode 100644 index 00000000..161eb58e --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/domain/repository/ProductionRepository.java @@ -0,0 +1,10 @@ +package org.eclipse.tractusx.puris.backend.production.domain.repository; + +import java.util.UUID; + +import org.eclipse.tractusx.puris.backend.production.domain.model.Production; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ProductionRepository extends JpaRepository { + +} diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/domain/repository/ReportedProductionRepository.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/domain/repository/ReportedProductionRepository.java index 065295ab..542a242f 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/domain/repository/ReportedProductionRepository.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/domain/repository/ReportedProductionRepository.java @@ -20,13 +20,10 @@ See the NOTICE file(s) distributed with this work for additional package org.eclipse.tractusx.puris.backend.production.domain.repository; -import java.util.UUID; - import org.eclipse.tractusx.puris.backend.production.domain.model.ReportedProduction; -import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository -public interface ReportedProductionRepository extends JpaRepository { +public interface ReportedProductionRepository extends ProductionRepository { } diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/logic/service/OwnProductionService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/logic/service/OwnProductionService.java index d7602179..255f750a 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/logic/service/OwnProductionService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/logic/service/OwnProductionService.java @@ -21,10 +21,7 @@ See the NOTICE file(s) distributed with this work for additional package org.eclipse.tractusx.puris.backend.production.logic.service; import java.util.List; -import java.util.Optional; -import java.util.UUID; import java.util.function.Function; -import java.util.stream.Stream; import javax.management.openmbean.KeyAlreadyExistsException; @@ -35,7 +32,7 @@ See the NOTICE file(s) distributed with this work for additional import org.springframework.stereotype.Service; @Service -public class OwnProductionService { +public class OwnProductionService extends ProductionService { private final OwnProductionRepository repository; private final PartnerService partnerService; @@ -48,38 +45,6 @@ public OwnProductionService(OwnProductionRepository repository, PartnerService p this.validator = this::validate; } - public final List findAll() { - return repository.findAll(); - } - - public final List findAllByBpnl(String bpnl) { - return repository.findAll().stream().filter(production -> production.getPartner().getBpnl().equals(bpnl)) - .toList(); - } - - public final List findAllByOwnMaterialNumber(String ownMaterialNumber) { - return repository.findAll().stream().filter(production -> production.getMaterial().getOwnMaterialNumber().equals(ownMaterialNumber)) - .toList(); - } - - public final List findAllByFilters(Optional ownMaterialNumber, Optional bpnl, Optional bpns) { - Stream stream = repository.findAll().stream(); - if (ownMaterialNumber.isPresent()) { - stream = stream.filter(production -> production.getMaterial().getOwnMaterialNumber().equals(ownMaterialNumber.get())); - } - if (bpnl.isPresent()) { - stream = stream.filter(production -> production.getPartner().getBpnl().equals(bpnl.get())); - } - if (bpns.isPresent()) { - stream = stream.filter(production -> production.getProductionSiteBpns().equals(bpns.get())); - } - return stream.toList(); - } - - public final OwnProduction findById(UUID uuid) { - return repository.findById(uuid).orElse(null); - } - public final OwnProduction create(OwnProduction production) { if (!validator.apply(production)) { @@ -102,17 +67,6 @@ public final List createAll(List productions) { return repository.saveAll(productions); } - public final OwnProduction update(OwnProduction production) { - if (production.getUuid() == null || repository.findById(production.getUuid()).isEmpty()) { - return null; - } - return repository.save(production); - } - - public final void delete(UUID uuid) { - repository.deleteById(uuid); - } - public boolean validate(OwnProduction production) { Partner ownPartnerEntity = partnerService.getOwnPartnerEntity(); return diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/logic/service/ProductionRequestApiService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/logic/service/ProductionRequestApiService.java index 3aa173b6..e2b69a15 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/logic/service/ProductionRequestApiService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/logic/service/ProductionRequestApiService.java @@ -73,7 +73,7 @@ public PlannedProductionOutput handleProductionSubmodelRequest(String bpnl, Stri // only send an answer if partner is registered as customer return null; } - var currentProduction = ownProductionService.findAllByFilters(Optional.of(material.getOwnMaterialNumber()), Optional.of(partner.getBpnl()), Optional.empty()); + var currentProduction = ownProductionService.findAllByFilters(Optional.of(material.getOwnMaterialNumber()), Optional.of(partner.getBpnl()), Optional.empty(), Optional.empty()); return sammMapper.ownProductionToSamm(currentProduction, partner, material); } @@ -92,7 +92,7 @@ public void doReportedProductionRequest(Partner partner, Material material) { } } // delete older data: - var oldProductions = reportedProductionService.findAllByFilters(Optional.of(material.getOwnMaterialNumber()), Optional.of(partner.getBpnl()), Optional.empty()); + var oldProductions = reportedProductionService.findAllByFilters(Optional.of(material.getOwnMaterialNumber()), Optional.of(partner.getBpnl()), Optional.empty(), Optional.empty()); for (var oldProduction : oldProductions) { reportedProductionService.delete(oldProduction.getUuid()); } diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/logic/service/ProductionService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/logic/service/ProductionService.java new file mode 100644 index 00000000..bbfd2765 --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/logic/service/ProductionService.java @@ -0,0 +1,102 @@ +package org.eclipse.tractusx.puris.backend.production.logic.service; + +import java.time.Instant; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Stream; + +import org.eclipse.tractusx.puris.backend.production.domain.model.Production; +import org.eclipse.tractusx.puris.backend.production.domain.repository.ProductionRepository; +import org.springframework.beans.factory.annotation.Autowired; + +public abstract class ProductionService { + @Autowired + protected ProductionRepository repository; + + public final List findAll() { + return repository.findAll(); + } + + public final T findById(UUID uuid) { + return repository.findById(uuid).orElse(null); + } + + public final List findAllByBpnl(String bpnl) { + return repository.findAll().stream().filter(production -> production.getPartner().getBpnl().equals(bpnl)) + .toList(); + } + + public final List findAllByOwnMaterialNumber(String ownMaterialNumber) { + return repository.findAll().stream().filter(production -> production.getMaterial().getOwnMaterialNumber().equals(ownMaterialNumber)) + .toList(); + } + + public final List findAllByFilters( + Optional ownMaterialNumber, + Optional bpnl, + Optional bpns, + Optional dayOfCompletion) { + Stream stream = repository.findAll().stream(); + if (ownMaterialNumber.isPresent()) { + stream = stream.filter(production -> production.getMaterial().getOwnMaterialNumber().equals(ownMaterialNumber.get())); + } + if (bpnl.isPresent()) { + stream = stream.filter(production -> production.getPartner().getBpnl().equals(bpnl.get())); + } + if (bpns.isPresent()) { + stream = stream.filter(production -> production.getProductionSiteBpns().equals(bpns.get())); + } + if (dayOfCompletion.isPresent()) { + LocalDate localEstimatedTimeOfCompletion = Instant.ofEpochMilli(dayOfCompletion.get().getTime()) + .atOffset(ZoneOffset.UTC) + .toLocalDate(); + stream = stream.filter(production -> { + LocalDate productionEstimatedTimeOfCompletion = Instant.ofEpochMilli(production.getEstimatedTimeOfCompletion().getTime()) + .atOffset(ZoneOffset.UTC) + .toLocalDate(); + return productionEstimatedTimeOfCompletion.getDayOfMonth() == localEstimatedTimeOfCompletion.getDayOfMonth(); + }); + } + return stream.toList(); + } + + public final List getQuantityForDays(String material, String partnerBpnl, String siteBpns, int numberOfDays) { + List quantities = new ArrayList<>(); + LocalDate localDate = LocalDate.now(); + + for (int i = 0; i < numberOfDays; i++) { + Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); + List productions = findAllByFilters(Optional.of(material), Optional.of(partnerBpnl), Optional.of(siteBpns), Optional.of(date)); + double productionQuantity = getSumOfQuantities(productions); + quantities.add(productionQuantity); + + localDate = localDate.plusDays(1); + } + return quantities; + } + + public final T update(T production) { + if (production.getUuid() == null || repository.findById(production.getUuid()).isEmpty()) { + return null; + } + return repository.save(production); + } + + public final void delete(UUID uuid) { + repository.deleteById(uuid); + } + + private final double getSumOfQuantities(List productions) { + double sum = 0; + for (T production : productions) { + sum += production.getQuantity(); + } + return sum; + } +} diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/logic/service/ReportedProductionService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/logic/service/ReportedProductionService.java index 4521f8a7..69070ef7 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/logic/service/ReportedProductionService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/production/logic/service/ReportedProductionService.java @@ -21,17 +21,14 @@ See the NOTICE file(s) distributed with this work for additional package org.eclipse.tractusx.puris.backend.production.logic.service; import java.util.List; -import java.util.Optional; -import java.util.UUID; import java.util.function.Function; -import java.util.stream.Stream; import org.eclipse.tractusx.puris.backend.production.domain.model.ReportedProduction; import org.eclipse.tractusx.puris.backend.production.domain.repository.ReportedProductionRepository; import org.springframework.stereotype.Service; @Service -public class ReportedProductionService { +public class ReportedProductionService extends ProductionService { private final ReportedProductionRepository repository; protected final Function validator; @@ -41,38 +38,6 @@ public ReportedProductionService(ReportedProductionRepository repository) { this.validator = this::validate; } - public final List findAll() { - return repository.findAll(); - } - - public final List findAllByBpnl(String bpnl) { - return repository.findAll().stream().filter(production -> production.getPartner().getBpnl().equals(bpnl)) - .toList(); - } - - public final List findAllByOwnMaterialNumber(String ownMaterialNumber) { - return repository.findAll().stream().filter(production -> production.getMaterial().getOwnMaterialNumber().equals(ownMaterialNumber)) - .toList(); - } - - public final List findAllByFilters(Optional ownMaterialNumber, Optional bpnl, Optional bpns) { - Stream stream = repository.findAll().stream(); - if (ownMaterialNumber.isPresent()) { - stream = stream.filter(production -> production.getMaterial().getOwnMaterialNumber().equals(ownMaterialNumber.get())); - } - if (bpnl.isPresent()) { - stream = stream.filter(production -> production.getPartner().getBpnl().equals(bpnl.get())); - } - if (bpns.isPresent()) { - stream = stream.filter(production -> production.getProductionSiteBpns().equals(bpns.get())); - } - return stream.toList(); - } - - public final ReportedProduction findById(UUID uuid) { - return repository.findById(uuid).orElse(null); - } - public final ReportedProduction create(ReportedProduction production) { if (repository.findAll().stream().anyMatch(prod -> prod.equals(production))) { return null; @@ -94,17 +59,6 @@ public final List createAll(List product return repository.saveAll(productions); } - public final ReportedProduction update(ReportedProduction production) { - if (production.getUuid() == null || repository.findById(production.getUuid()).isEmpty()) { - return null; - } - return repository.save(production); - } - - public final void delete(UUID uuid) { - repository.deleteById(uuid); - } - public boolean validate(ReportedProduction production) { return production.getQuantity() > 0 && diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/stock/logic/service/ItemStockService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/stock/logic/service/ItemStockService.java index b3d8258f..06362371 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/stock/logic/service/ItemStockService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/stock/logic/service/ItemStockService.java @@ -20,6 +20,7 @@ package org.eclipse.tractusx.puris.backend.stock.logic.service; import lombok.extern.slf4j.Slf4j; + 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; @@ -32,7 +33,7 @@ import java.util.Objects; import java.util.UUID; import java.util.function.Function; - +import java.util.stream.Stream; @Slf4j public abstract class ItemStockService { @@ -45,7 +46,8 @@ public abstract class ItemStockService { protected final Function validator; - public ItemStockService(PartnerService partnerService, MaterialPartnerRelationService mprService, ItemStockRepository repository) { + public ItemStockService(PartnerService partnerService, MaterialPartnerRelationService mprService, + ItemStockRepository repository) { this.partnerService = partnerService; this.mprService = mprService; this.repository = repository; @@ -105,6 +107,29 @@ public final List findByPartnerBpnlAndOwnMaterialNumber(String partnerBpnl, S return repository.getForPartnerBpnlAndOwnMatNbr(partnerBpnl, ownMaterialNumber); } + public final List findAllByMaterialAndPartner(String ownMaterialNumber, String partnerBpnl) { + Stream stream = repository.findAll().stream(); + + stream = stream.filter(stock -> stock.getMaterial().getOwnMaterialNumber().equals(ownMaterialNumber)); + stream = stream.filter(stock -> stock.getPartner().getBpnl().equals(partnerBpnl)); + return stream.toList(); + } + + public final double getSumOfQuantities(List stocks) { + double sum = 0; + for (T stock : stocks) { + sum = stock.getQuantity(); + } + return sum; + } + + public final double getInitialStockQuantity(String material, String partnerBpnl) { + List stocks = findAllByMaterialAndPartner(material, partnerBpnl); + double initialStockQuantity = getSumOfQuantities(stocks); + + return initialStockQuantity; + } + public abstract boolean validate(T itemStock); protected boolean basicValidation(ItemStock itemStock) { @@ -171,12 +196,12 @@ protected final boolean validateProductItemStock(ItemStock itemStock) { protected boolean validateLocation(ItemStock itemStock, Partner partner) { try { var stockSite = partner.getSites().stream() - .filter(site -> site.getBpns().equals(itemStock.getLocationBpns())) - .findFirst().orElse(null); + .filter(site -> site.getBpns().equals(itemStock.getLocationBpns())) + .findFirst().orElse(null); Objects.requireNonNull(stockSite, "Site not found"); var stockAddress = stockSite.getAddresses().stream() - .filter(addr -> addr.getBpna().equals(itemStock.getLocationBpna())) - .findFirst().orElse(null); + .filter(addr -> addr.getBpna().equals(itemStock.getLocationBpna())) + .findFirst().orElse(null); Objects.requireNonNull(stockAddress, "Address not found"); } catch (Exception e) { log.error("Location Validation failed: " + itemStock + "\n" + e.getMessage()); diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/stock/logic/service/MaterialItemStockService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/stock/logic/service/MaterialItemStockService.java index 8f0b79e0..a4430938 100644 --- a/backend/src/main/java/org/eclipse/tractusx/puris/backend/stock/logic/service/MaterialItemStockService.java +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/stock/logic/service/MaterialItemStockService.java @@ -44,6 +44,4 @@ public boolean validate(MaterialItemStock materialItemStock) { return basicValidation(materialItemStock) && validateLocalStock(materialItemStock) && validateMaterialItemStock(materialItemStock); } - - } diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/controller/SupplyController.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/controller/SupplyController.java new file mode 100644 index 00000000..3a102e76 --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/controller/SupplyController.java @@ -0,0 +1,87 @@ +/* + * 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.supply.controller; + +import java.util.List; + +import org.eclipse.tractusx.puris.backend.supply.domain.model.Supply; +import org.eclipse.tractusx.puris.backend.supply.logic.dto.SupplyDto; +import org.eclipse.tractusx.puris.backend.supply.logic.service.CustomerSupplyService; +import org.eclipse.tractusx.puris.backend.supply.logic.service.SupplierSupplyService; +import org.modelmapper.ModelMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +@RestController +@RequestMapping("days-of-supply") +public class SupplyController { + @Autowired + private CustomerSupplyService customerSupplyService; + @Autowired + private SupplierSupplyService supplierSupplyService; + + @Autowired + private ModelMapper modelMapper; + + @GetMapping("customer") + @ResponseBody + @Operation(summary = "Calculate days of supply for customer for given number of days.", + description = "Calculate days of supply for customer for given number of days. Filtered by given material number, partner bpnl and site bpns.") + public List calculateCustomerDaysOfSupply(String materialNumber, String bpnl, String siteBpns, int numberOfDays) { + return customerSupplyService.calculateCustomerDaysOfSupply(materialNumber, bpnl, siteBpns, numberOfDays) + .stream().map(this::convertToDto).toList(); + } + + @GetMapping("customer/reported") + @Operation(summary = "Get days of supply for customer.", + description = "Get days of supply for customer for given material number and partner bpnl.") + public List getCustomerDaysOfSupply(String materialNumber, String bpnl) { + return customerSupplyService.findByPartnerBpnlAndOwnMaterialNumber(materialNumber, bpnl) + .stream().map(this::convertToDto).toList(); + } + + @GetMapping("supplier") + @Operation(summary = "Calculate days of supply for supplier for given number of days.", + description = "Calculate days of supply for supplier for given number of days. Filtered by given material number, partner bpnl and site bpns.") + public List calculateSupplierDaysOfSupply(String materialNumber, String bpnl, String siteBpns, int numberOfDays) { + return supplierSupplyService.calculateSupplierDaysOfSupply(materialNumber, bpnl, siteBpns, numberOfDays) + .stream().map(this::convertToDto).toList(); + } + + @GetMapping("supplier/reported") + @Operation(summary = "Get days of supply for supplier.", + description = "Get days of supply for supplier for given material number and partner bpnl.") + public List getSupplierDaysOfSupply(String materialNumber, String bpnl) { + return supplierSupplyService.findByPartnerBpnlAndOwnMaterialNumber(materialNumber, bpnl) + .stream().map(this::convertToDto).toList(); + } + + private SupplyDto convertToDto(Supply entity) { + SupplyDto dto = modelMapper.map(entity, SupplyDto.class); + + return dto; + } +} diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/domain/model/OwnCustomerSupply.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/domain/model/OwnCustomerSupply.java new file mode 100644 index 00000000..c1030bbe --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/domain/model/OwnCustomerSupply.java @@ -0,0 +1,35 @@ +/* +* 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.supply.domain.model; + +import jakarta.persistence.Entity; +import lombok.NoArgsConstructor; +import lombok.ToString; +import lombok.experimental.SuperBuilder; + +@Entity +@SuperBuilder +@NoArgsConstructor +@ToString(callSuper = true) +public class OwnCustomerSupply extends Supply { + +} + diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/domain/model/OwnSupplierSupply.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/domain/model/OwnSupplierSupply.java new file mode 100644 index 00000000..24a2a81e --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/domain/model/OwnSupplierSupply.java @@ -0,0 +1,35 @@ +/* + * 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.supply.domain.model; + +import jakarta.persistence.Entity; +import lombok.NoArgsConstructor; +import lombok.ToString; +import lombok.experimental.SuperBuilder; + +@Entity +@SuperBuilder +@NoArgsConstructor +@ToString(callSuper = true) +public class OwnSupplierSupply extends Supply { + +} + diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/domain/model/ReportedCustomerSupply.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/domain/model/ReportedCustomerSupply.java new file mode 100644 index 00000000..6f0b6dd6 --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/domain/model/ReportedCustomerSupply.java @@ -0,0 +1,35 @@ +/* + * 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.supply.domain.model; + + import jakarta.persistence.Entity; + import lombok.NoArgsConstructor; + import lombok.ToString; + import lombok.experimental.SuperBuilder; + + @Entity + @SuperBuilder + @NoArgsConstructor + @ToString(callSuper = true) + public class ReportedCustomerSupply extends Supply { + + } + \ No newline at end of file diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/domain/model/ReportedSupplierSupply.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/domain/model/ReportedSupplierSupply.java new file mode 100644 index 00000000..ff2583fa --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/domain/model/ReportedSupplierSupply.java @@ -0,0 +1,34 @@ +/* + * 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.supply.domain.model; + +import jakarta.persistence.Entity; +import lombok.NoArgsConstructor; +import lombok.ToString; +import lombok.experimental.SuperBuilder; + +@Entity +@SuperBuilder +@NoArgsConstructor +@ToString(callSuper = true) +public class ReportedSupplierSupply extends Supply { + +} diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/domain/model/Supply.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/domain/model/Supply.java new file mode 100644 index 00000000..fcd661b8 --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/domain/model/Supply.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.supply.domain.model; + +import org.eclipse.tractusx.puris.backend.common.util.PatternStore; +import org.eclipse.tractusx.puris.backend.masterdata.domain.model.Material; +import org.eclipse.tractusx.puris.backend.masterdata.domain.model.Partner; + +import java.util.UUID; +import java.util.Date; +import java.util.Objects; + +import jakarta.persistence.*; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import lombok.experimental.SuperBuilder; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@SuperBuilder +@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) +@Entity +@ToString +public abstract class Supply { + @Id + @GeneratedValue + protected UUID uuid; + + @ManyToOne() + @JoinColumn(name = "partner_uuid") + @ToString.Exclude + @NotNull + protected Partner partner; + + @ManyToOne() + @JoinColumn(name = "material_ownMaterialNumber") + @ToString.Exclude + @NotNull + protected Material material; + + @Pattern(regexp = PatternStore.BPNA_STRING) + private String stockLocationBPNA; + + @Pattern(regexp = PatternStore.BPNS_STRING) + private String stockLocationBPNS; + + private Date date; + private double daysOfSupply; + + @ToString.Include + private String material_ownMaterialNumber() { + return material.getOwnMaterialNumber(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final Supply that = (Supply) o; + return this.getMaterial().getOwnMaterialNumber().equals(that.getMaterial().getOwnMaterialNumber()) && + this.getPartner().getUuid().equals(that.getPartner().getUuid()) && + this.getStockLocationBPNA().equals(that.getStockLocationBPNA()) && + this.getStockLocationBPNS().equals(that.getStockLocationBPNS()) && + this.getDate().equals(that.getDate()) && + this.getDaysOfSupply() == that.getDaysOfSupply(); + } + + @Override + public int hashCode() { + return Objects.hash(partner, material, stockLocationBPNA, stockLocationBPNS, date, daysOfSupply); + } +} diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/domain/repository/ReportedCustomerSupplyRepository.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/domain/repository/ReportedCustomerSupplyRepository.java new file mode 100644 index 00000000..a4577527 --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/domain/repository/ReportedCustomerSupplyRepository.java @@ -0,0 +1,31 @@ +/* + * 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.supply.domain.repository; + +import java.util.List; +import java.util.UUID; + +import org.eclipse.tractusx.puris.backend.supply.domain.model.ReportedCustomerSupply; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ReportedCustomerSupplyRepository extends JpaRepository { + List findByPartner_BpnlAndMaterial_OwnMaterialNumber(String partnerBpnl, String ownMaterialNumber); +} diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/domain/repository/ReportedSupplierSupplyRepository.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/domain/repository/ReportedSupplierSupplyRepository.java new file mode 100644 index 00000000..f949ddb9 --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/domain/repository/ReportedSupplierSupplyRepository.java @@ -0,0 +1,32 @@ +/* + * 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.supply.domain.repository; + +import java.util.List; +import java.util.UUID; + +import org.eclipse.tractusx.puris.backend.supply.domain.model.ReportedSupplierSupply; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ReportedSupplierSupplyRepository extends JpaRepository { + List findByPartner_BpnlAndMaterial_OwnMaterialNumber(String partnerBpnl, String ownMaterialNumber); +} + diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/logic/dto/SupplyDto.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/logic/dto/SupplyDto.java new file mode 100644 index 00000000..2a188af5 --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/logic/dto/SupplyDto.java @@ -0,0 +1,38 @@ +/* + * 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.supply.logic.dto; + +import java.io.Serializable; +import java.util.Date; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@NoArgsConstructor +@ToString +public class SupplyDto implements Serializable { + private Date date; + private double daysOfSupply; +} diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/logic/service/CustomerSupplyService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/logic/service/CustomerSupplyService.java new file mode 100644 index 00000000..565a7e0c --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/logic/service/CustomerSupplyService.java @@ -0,0 +1,125 @@ +/* + * 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.supply.logic.service; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.function.Function; +import java.util.stream.Stream; + +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.demand.logic.services.OwnDemandService; +import org.eclipse.tractusx.puris.backend.masterdata.logic.service.PartnerService; +import org.eclipse.tractusx.puris.backend.stock.logic.dto.itemstocksamm.DirectionCharacteristic; +import org.eclipse.tractusx.puris.backend.supply.domain.model.OwnCustomerSupply; +import org.eclipse.tractusx.puris.backend.supply.domain.model.ReportedCustomerSupply; +import org.eclipse.tractusx.puris.backend.supply.domain.repository.ReportedCustomerSupplyRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class CustomerSupplyService extends SupplyService { + @Autowired + private ReportedCustomerSupplyRepository repository; + @Autowired + private PartnerService partnerService; + @Autowired + private OwnDeliveryService ownDeliveryService; + @Autowired + private ReportedDeliveryService reportedDeliveryService; + @Autowired + private OwnDemandService demandService; + + protected final Function validator; + + public CustomerSupplyService() { + this.validator = this::validate; + } + + @Override + protected OwnCustomerSupply createSupplyInstance() { + return new OwnCustomerSupply(); + } + + @Override + protected List getAddedValues(String material, String partnerBpnl, String siteBpns, int numberOfDays) { + List ownDeliveries = ownDeliveryService.getQuantityForDays(material, partnerBpnl, siteBpns, DirectionCharacteristic.INBOUND, numberOfDays); + List reportedDeliveries = reportedDeliveryService.getQuantityForDays(material, partnerBpnl, siteBpns, DirectionCharacteristic.INBOUND, numberOfDays); + List deliveries = mergeDeliveries(ownDeliveries, reportedDeliveries); + return deliveries; + } + + @Override + protected List getConsumedValues(String material, String partnerBpnl, String siteBpns, int numberOfDays) { + List demands = demandService.getQuantityForDays(material, partnerBpnl, siteBpns, numberOfDays); + return demands; + } + + /** + * Calculates the customer's days of supply for a given material, partner, and site over a specified number of days. + * It combines own and reported deliveries, and demand quantities to forecast the number of days the stock will last. + * + * @param material the material identifier for which the days of supply are being calculated. + * @param partnerBpnl The bpnl of the customer's partner. + * @param siteBpns the bpns of the site where the deliveries and demands are recorded. + * @param numberOfDays the number of days over which the forecast should be calculated. + * @return a list of {@link OwnCustomerSupply} objects, each containing the calculated days of supply for a specific date. + */ + public final List calculateCustomerDaysOfSupply(String material, String partnerBpnl, String siteBpns, int numberOfDays) { + return calculateDaysOfSupply(material, partnerBpnl, siteBpns, numberOfDays); + } + + public final List findAll() { + return repository.findAll(); + } + + public final ReportedCustomerSupply findById(UUID id) { + return repository.findById(id).orElse(null); + } + + public final List findAllByFilters(Optional ownMaterialNumber, Optional bpnl) { + Stream stream = repository.findAll().stream(); + if (ownMaterialNumber.isPresent()) { + stream = stream.filter(dayOfSupply -> dayOfSupply.getMaterial().getOwnMaterialNumber().equals(ownMaterialNumber.get())); + } + if (bpnl.isPresent()) { + stream = stream.filter(dayOfSupply -> dayOfSupply.getPartner().getBpnl().equals(bpnl.get())); + } + return stream.toList(); + } + + public final List findByPartnerBpnlAndOwnMaterialNumber(String partnerBpnl, String ownMaterialNumber) { + return repository.findByPartner_BpnlAndMaterial_OwnMaterialNumber(partnerBpnl, ownMaterialNumber); + } + + public boolean validate(ReportedCustomerSupply daysOfSupply) { + return + daysOfSupply.getPartner() != null && + daysOfSupply.getMaterial() != null && + daysOfSupply.getDate() != null && + daysOfSupply.getStockLocationBPNS() != null && + daysOfSupply.getPartner() != partnerService.getOwnPartnerEntity() && + daysOfSupply.getPartner().getSites().stream().anyMatch(site -> site.getBpns().equals(daysOfSupply.getStockLocationBPNS())) && + (daysOfSupply.getStockLocationBPNA().equals(null) || daysOfSupply.getStockLocationBPNA().equals(daysOfSupply.getStockLocationBPNS())); + } +} diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/logic/service/SupplierSupplyService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/logic/service/SupplierSupplyService.java new file mode 100644 index 00000000..ba2d83a5 --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/logic/service/SupplierSupplyService.java @@ -0,0 +1,125 @@ +/* + * 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.supply.logic.service; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.function.Function; +import java.util.stream.Stream; + +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.logic.service.PartnerService; +import org.eclipse.tractusx.puris.backend.production.logic.service.OwnProductionService; +import org.eclipse.tractusx.puris.backend.stock.logic.dto.itemstocksamm.DirectionCharacteristic; +import org.eclipse.tractusx.puris.backend.supply.domain.model.OwnSupplierSupply; +import org.eclipse.tractusx.puris.backend.supply.domain.model.ReportedSupplierSupply; +import org.eclipse.tractusx.puris.backend.supply.domain.repository.ReportedSupplierSupplyRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class SupplierSupplyService extends SupplyService { + @Autowired + private ReportedSupplierSupplyRepository repository; + @Autowired + private PartnerService partnerService; + @Autowired + private OwnDeliveryService ownDeliveryService; + @Autowired + private ReportedDeliveryService reportedDeliveryService; + @Autowired + private OwnProductionService productionService; + + protected final Function validator; + + public SupplierSupplyService() { + this.validator = this::validate; + } + + @Override + protected OwnSupplierSupply createSupplyInstance() { + return new OwnSupplierSupply(); + } + + @Override + protected List getAddedValues(String material, String partnerBpnl, String siteBpns, int numberOfDays) { + List productions = productionService.getQuantityForDays(material, partnerBpnl, siteBpns, numberOfDays); + return productions; + } + + @Override + protected List getConsumedValues(String material, String partnerBpnl, String siteBpns, int numberOfDays) { + List ownDeliveries = ownDeliveryService.getQuantityForDays(material, partnerBpnl, siteBpns, DirectionCharacteristic.OUTBOUND, numberOfDays); + List reportedDeliveries = reportedDeliveryService.getQuantityForDays(material, partnerBpnl, siteBpns, DirectionCharacteristic.OUTBOUND, numberOfDays); + List deliveries = mergeDeliveries(ownDeliveries, reportedDeliveries); + return deliveries; + } + + /** + * Calculates the supplier's days of supply for a given material, partner, and site over a specified number of days. + * It combines own and reported deliveries, and production quantities to forecast the number of days the stock will last. + * + * @param material the material identifier for which the days of supply are being calculated. + * @param partnerBpnl The bpnl of the supplier's partner. + * @param siteBpns the bpns of the site where the deliveries and productions are recorded. + * @param numberOfDays the number of days over which the forecast should be calculated. + * @return a list of {@link OwnSupplierSupply} objects, each containing the calculated days of supply for a specific date. + */ + public final List calculateSupplierDaysOfSupply(String material, String partnerBpnl, String siteBpns, int numberOfDays) { + return calculateDaysOfSupply(material, partnerBpnl, siteBpns, numberOfDays); + } + + public final List findAll() { + return repository.findAll(); + } + + public final ReportedSupplierSupply findById(UUID id) { + return repository.findById(id).orElse(null); + } + + public final List findAllByFilters(Optional ownMaterialNumber, Optional bpnl) { + Stream stream = repository.findAll().stream(); + if (ownMaterialNumber.isPresent()) { + stream = stream.filter(dayOfSupply -> dayOfSupply.getMaterial().getOwnMaterialNumber().equals(ownMaterialNumber.get())); + } + if (bpnl.isPresent()) { + stream = stream.filter(dayOfSupply -> dayOfSupply.getPartner().getBpnl().equals(bpnl.get())); + } + return stream.toList(); + } + + public final List findByPartnerBpnlAndOwnMaterialNumber(String partnerBpnl, String ownMaterialNumber) { + return repository.findByPartner_BpnlAndMaterial_OwnMaterialNumber(partnerBpnl, ownMaterialNumber); + } + + public boolean validate(ReportedSupplierSupply daysOfSupply) { + return + daysOfSupply.getPartner() != null && + daysOfSupply.getMaterial() != null && + daysOfSupply.getDate() != null && + daysOfSupply.getStockLocationBPNS() != null && + daysOfSupply.getPartner() != partnerService.getOwnPartnerEntity() && + daysOfSupply.getPartner().getSites().stream().anyMatch(site -> site.getBpns().equals(daysOfSupply.getStockLocationBPNS())) && + (daysOfSupply.getStockLocationBPNA().equals(null) || daysOfSupply.getStockLocationBPNA().equals(daysOfSupply.getStockLocationBPNS())); + } +} diff --git a/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/logic/service/SupplyService.java b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/logic/service/SupplyService.java new file mode 100644 index 00000000..bccf067c --- /dev/null +++ b/backend/src/main/java/org/eclipse/tractusx/puris/backend/supply/logic/service/SupplyService.java @@ -0,0 +1,131 @@ +/* + * 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.supply.logic.service; + +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.eclipse.tractusx.puris.backend.masterdata.logic.service.MaterialService; +import org.eclipse.tractusx.puris.backend.stock.logic.service.MaterialItemStockService; +import org.eclipse.tractusx.puris.backend.supply.domain.model.Supply; +import org.springframework.beans.factory.annotation.Autowired; + +public abstract class SupplyService { + @Autowired + private MaterialItemStockService stockService; + @Autowired + private MaterialService materialService; + + protected abstract T createSupplyInstance(); + protected abstract List getAddedValues(String material, String partnerBpnl, String siteBpns, int numberOfDays); + protected abstract List getConsumedValues(String material, String partnerBpnl, String siteBpns, int numberOfDays); + + /** + * Calculates the days of supply for a given material, partner, and site over a specified number of days. + * It combines added values (deliveries/productions), and consumed values (deliveries/demands) to forecast the number of days the stock will last. + * + * @param material the material identifier for which the days of supply are being calculated. + * @param partnerBpnl The bpnl of the partner. + * @param siteBpns the bpns of the site where the added values and consumed values are recorded. + * @param numberOfDays the number of days over which the forecast should be calculated. + * @return a list of {@link Supply} objects, each containing the calculated days of supply for a specific date. + */ + public final List calculateDaysOfSupply(String material, String partnerBpnl, String siteBpns, int numberOfDays) { + List supplyList = new ArrayList<>(); + LocalDate localDate = LocalDate.now(); + + List addedValues = getAddedValues(material, partnerBpnl, siteBpns, numberOfDays); + List consumedValues = getConsumedValues(material, partnerBpnl, siteBpns, numberOfDays); + double stockQuantity = stockService.getInitialStockQuantity(material, partnerBpnl); + + for (int i = 0; i < numberOfDays; i++) { + Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); + + var remainingAddedValues = addedValues.subList(i, addedValues.size()); + var remainingConsumedValues = consumedValues.subList(i, consumedValues.size()); + double daysOfSupply = getDaysOfSupply(stockQuantity, remainingAddedValues, remainingConsumedValues); + + T supply = createSupplyInstance(); + supply.setMaterial(materialService.findByOwnMaterialNumber(material)); + supply.setDate(date); + supply.setDaysOfSupply(daysOfSupply); + supplyList.add(supply); + + stockQuantity = stockQuantity - consumedValues.get(i) + addedValues.get(i); + + localDate = localDate.plusDays(1); + } + + return supplyList; + } + + /** + * Merges own and reported deliveries into a single list. + * @param list1 Own deliveries + * @param list2 Reported deliveries + * @return a new list containing the summed delivery quantities from the input lists. + */ + public static List mergeDeliveries(List list1, List list2) { + if (list1.size() != list2.size()) { + throw new IllegalArgumentException("Lists must be of the same length"); + } + + List mergedList = new ArrayList<>(list1.size()); + + for (int i = 0; i < list1.size(); i++) { + mergedList.add(list1.get(i) + list2.get(i)); + } + + return mergedList; + } + + /** + * Calculates the number of days of supply based on the current stock quantity and a list of consumed values. + * @param stockQuantity Current stock amount + * @param addedValues Remaining list of added values for current iteration + * @param consumedValues Remaining list of consumed values for current iteration + * @return The number of days of supply that the stock can cover. + */ + private final double getDaysOfSupply(double stockQuantity, List addedValues, List consumedValues) { + double daysOfSupply = 0; + + for (int i = 0; i < addedValues.size(); i++) { + Double addedValue = addedValues.get(i); + Double consumedValue = consumedValues.get(i); + + if ((stockQuantity + addedValue - consumedValue) >= 0) { + daysOfSupply += 1; + stockQuantity = stockQuantity + addedValue - consumedValue; + } else if ((stockQuantity + addedValue - consumedValue) < 0 && stockQuantity > 0) { + double fractional = (stockQuantity + addedValue) / consumedValue; + daysOfSupply += fractional; + stockQuantity = stockQuantity + addedValue - consumedValue; + break; + } else { + break; + } + } + return daysOfSupply; + } +} diff --git a/backend/src/test/java/org/eclipse/tractusx/puris/backend/delivery/controller/DeliveryRequestApiServiceTest.java b/backend/src/test/java/org/eclipse/tractusx/puris/backend/delivery/controller/DeliveryRequestApiServiceTest.java index 9cdc187a..c3890972 100644 --- a/backend/src/test/java/org/eclipse/tractusx/puris/backend/delivery/controller/DeliveryRequestApiServiceTest.java +++ b/backend/src/test/java/org/eclipse/tractusx/puris/backend/delivery/controller/DeliveryRequestApiServiceTest.java @@ -182,7 +182,9 @@ void customerGetsRequestNoCxId_testHandleDeliverySubmodelRequest_works() { when(ownDeliveryService.findAllByFilters( Optional.of(mpr.getMaterial().getOwnMaterialNumber()), Optional.empty(), - Optional.of(BPNL_SUPPLIER) + Optional.of(BPNL_SUPPLIER), + Optional.empty(), + Optional.empty() )).thenReturn(deliveries); // return mpr after update