Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implemented days of supply edc integration #694

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public JsonNode createMaterialRegistrationRequestBody(MaterialPartnerRelation ma
submodelDescriptorsArray.add(createSubmodelObject(AssetType.ITEM_STOCK_SUBMODEL.URN_SEMANTIC_ID, href + DirectionCharacteristic.INBOUND + "/", variablesService.getItemStockSubmodelApiAssetId()));
submodelDescriptorsArray.add(createSubmodelObject(AssetType.DEMAND_SUBMODEL.URN_SEMANTIC_ID, href, variablesService.getDemandSubmodelApiAssetId()));
submodelDescriptorsArray.add(createSubmodelObject(AssetType.DELIVERY_SUBMODEL.URN_SEMANTIC_ID, href, variablesService.getDeliverySubmodelApiAssetId()));

submodelDescriptorsArray.add(createSubmodelObject(AssetType.DAYS_OF_SUPPLY.URN_SEMANTIC_ID, href + DirectionCharacteristic.INBOUND + "/", variablesService.getDaysOfSupplySubmodelApiAssetId()));
log.debug("Created body for material " + material.getOwnMaterialNumber() + "\n" + body.toPrettyString());
return body;
}
Expand Down Expand Up @@ -145,6 +145,7 @@ public JsonNode createProductRegistrationRequestBody(Material material, String p
submodelDescriptorsArray.add(createSubmodelObject(AssetType.ITEM_STOCK_SUBMODEL.URN_SEMANTIC_ID, href + DirectionCharacteristic.OUTBOUND + "/", variablesService.getItemStockSubmodelApiAssetId()));
submodelDescriptorsArray.add(createSubmodelObject(AssetType.PRODUCTION_SUBMODEL.URN_SEMANTIC_ID, href, variablesService.getProductionSubmodelApiAssetId()));
submodelDescriptorsArray.add(createSubmodelObject(AssetType.DELIVERY_SUBMODEL.URN_SEMANTIC_ID, href, variablesService.getDeliverySubmodelApiAssetId()));
submodelDescriptorsArray.add(createSubmodelObject(AssetType.DAYS_OF_SUPPLY.URN_SEMANTIC_ID, href + DirectionCharacteristic.OUTBOUND + "/", variablesService.getDaysOfSupplySubmodelApiAssetId()));
submodelDescriptorsArray.add(createPartTypeSubmodelObject(material.getOwnMaterialNumber()));

log.debug("Created body for product " + material.getOwnMaterialNumber() + "\n" + body.toPrettyString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public enum AssetType {
DEMAND_SUBMODEL("urn:samm:io.catenax.short_term_material_demand:1.0.0#ShortTermMaterialDemand", "$value", "ShortTermMaterialDemand", "1.0"),
DELIVERY_SUBMODEL("urn:samm:io.catenax.delivery_information:2.0.0#DeliveryInformation", "$value", "DeliveryInformation", "2.0"),
NOTIFICATION("urn:samm:io.catenax.demand_and_capacity_notification:2.0.0#DemandAndCapacityNotification", "none", "none", "2.0"),
DAYS_OF_SUPPLY("urn:samm:io.catenax.days_of_supply:1.0.0#DaysOfSupply", "$value", "DaysOfSupply", "1.0"),
PART_TYPE_INFORMATION_SUBMODEL("urn:samm:io.catenax.part_type_information:1.0.0#PartTypeInformation", "$value", "none", "1.0");

public final String URN_SEMANTIC_ID;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* 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.common.edc.domain.model;

import jakarta.persistence.Entity;
import lombok.ToString;

@Entity
@ToString(callSuper = true)
public class DaysOfSupplyContractMapping extends ContractMapping {
}
Original file line number Diff line number Diff line change
@@ -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.common.edc.domain.repository;

import org.eclipse.tractusx.puris.backend.common.edc.domain.model.ContractMapping;
import org.eclipse.tractusx.puris.backend.common.edc.domain.model.DaysOfSupplyContractMapping;
import org.springframework.stereotype.Repository;

@Repository
public interface DaysOfSupplyContractMappingRepository extends GeneralContractMappingRepository<DaysOfSupplyContractMapping> {
@Override
default Class<? extends ContractMapping> getType() {
return DaysOfSupplyContractMapping.class;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,11 @@ public boolean registerAssetsInitially() {
variablesService.getNotificationApiAssetId(),
variablesService.getNotificationEndpoint()
)));
log.info("Registration of Days of Supply 1.0.0 submodel successful {}", (assetRegistration = registerSubmodelAsset(
variablesService.getDaysOfSupplySubmodelApiAssetId(),
variablesService.getDaysOfSupplySubmodelEndpoint(),
AssetType.DAYS_OF_SUPPLY.URN_SEMANTIC_ID
)));
log.info("Registration of PartTypeInformation 1.0.0 submodel successful {}", (assetRegistration = registerPartTypeInfoSubmodelAsset()));
result &= assetRegistration;
return result;
Expand All @@ -194,6 +199,7 @@ public boolean createPolicyAndContractDefForPartner(Partner partner) {
result &= createSubmodelContractDefinitionForPartner(AssetType.DEMAND_SUBMODEL.URN_SEMANTIC_ID, variablesService.getDemandSubmodelApiAssetId(), partner);
result &= createSubmodelContractDefinitionForPartner(AssetType.DELIVERY_SUBMODEL.URN_SEMANTIC_ID, variablesService.getDeliverySubmodelApiAssetId(), partner);
result &= createSubmodelContractDefinitionForPartner(AssetType.NOTIFICATION.URN_SEMANTIC_ID, variablesService.getNotificationApiAssetId(), partner);
result &= createSubmodelContractDefinitionForPartner(AssetType.DAYS_OF_SUPPLY.URN_SEMANTIC_ID, variablesService.getDaysOfSupplySubmodelApiAssetId(), partner);
result &= createDtrContractDefinitionForPartner(partner);
return createSubmodelContractDefinitionForPartner(AssetType.PART_TYPE_INFORMATION_SUBMODEL.URN_SEMANTIC_ID, variablesService.getPartTypeSubmodelApiAssetId(), partner) && result;
}
Expand Down Expand Up @@ -598,6 +604,7 @@ private JsonNode getSubmodelFromPartner(MaterialPartnerRelation mpr, AssetType t
case DEMAND_SUBMODEL -> fetchSubmodelDataByDirection(mpr, AssetType.DEMAND_SUBMODEL.URN_SEMANTIC_ID, direction);
case DELIVERY_SUBMODEL -> fetchSubmodelDataByDirection(mpr, AssetType.DELIVERY_SUBMODEL.URN_SEMANTIC_ID, direction);
case NOTIFICATION -> throw new IllegalArgumentException("DemandAndCapacityNotification not supported");
case DAYS_OF_SUPPLY -> fetchSubmodelDataByDirection(mpr, AssetType.DAYS_OF_SUPPLY.URN_SEMANTIC_ID, direction);
case PART_TYPE_INFORMATION_SUBMODEL -> fetchPartTypeSubmodelData(mpr);
};
boolean failed = true;
Expand Down Expand Up @@ -1033,6 +1040,7 @@ private boolean negotiateContractForSubmodel(MaterialPartnerRelation mpr, AssetT
case DEMAND_SUBMODEL -> fetchSubmodelDataByDirection(mpr, AssetType.DEMAND_SUBMODEL.URN_SEMANTIC_ID, direction);
case DELIVERY_SUBMODEL -> fetchSubmodelDataByDirection(mpr, AssetType.DELIVERY_SUBMODEL.URN_SEMANTIC_ID, direction);
case NOTIFICATION -> throw new IllegalArgumentException("DemandAndCapacityNotification not supported");
case DAYS_OF_SUPPLY -> fetchSubmodelDataByDirection(mpr, AssetType.DAYS_OF_SUPPLY.URN_SEMANTIC_ID, direction);
case PART_TYPE_INFORMATION_SUBMODEL -> fetchPartTypeSubmodelData(mpr);
};
Map<String, String> equalFilters = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.eclipse.tractusx.puris.backend.common.edc.domain.model.ContractMapping;
import org.eclipse.tractusx.puris.backend.common.edc.domain.model.DtrContractMapping;
import org.eclipse.tractusx.puris.backend.common.edc.domain.model.AssetType;
import org.eclipse.tractusx.puris.backend.common.edc.domain.repository.DaysOfSupplyContractMappingRepository;
import org.eclipse.tractusx.puris.backend.common.edc.domain.repository.DeliveryContractMappingRepository;
import org.eclipse.tractusx.puris.backend.common.edc.domain.repository.DemandAndCapacityNotificationContractMappingRepository;
import org.eclipse.tractusx.puris.backend.common.edc.domain.repository.DemandContractMappingRepository;
Expand Down Expand Up @@ -60,6 +61,9 @@ public class EdcContractMappingService {
@Autowired
private DemandAndCapacityNotificationContractMappingRepository demandAndCapacityNotificationContractMappingRepository;

@Autowired
private DaysOfSupplyContractMappingRepository daysOfSupplyContractMappingRepository;

@Autowired
private PartTypeContractMappingRepository partTypeContractMappingRepository;

Expand Down Expand Up @@ -124,6 +128,7 @@ private GeneralContractMappingRepository<? extends ContractMapping> getContractM
case DEMAND_SUBMODEL -> demandContractMappingRepository;
case DELIVERY_SUBMODEL -> deliveryContractMappingRepository;
case NOTIFICATION -> demandAndCapacityNotificationContractMappingRepository;
case DAYS_OF_SUPPLY -> daysOfSupplyContractMappingRepository;
case PART_TYPE_INFORMATION_SUBMODEL -> partTypeContractMappingRepository;
};
return repository;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,20 @@ public String getNotificationEndpoint() {
*/
private String notificationAssetId;

@Value("${puris.baseurl}" + "catena/days-of-supply/request")
/**
* The url under which this application's request endpoint can
* be reached by external machines.
*/
private String daysOfSupplySubmodelEndpoint;

@Value("${puris.daysofsupplysubmodel.apiassetid}")
/**
* The assetId that shall be assigned to the request API
* during asset creation.
*/
private String daysOfSupplySubmodelAssetId;

@Value("${puris.frameworkagreement.credential}")
/**
* The name of the framework agreement to be used.
Expand Down Expand Up @@ -285,6 +299,10 @@ public String getDeliverySubmodelApiAssetId() {
return deliverySubmodelAssetId + "@" + ownBpnl;
}

public String getDaysOfSupplySubmodelApiAssetId() {
return daysOfSupplySubmodelAssetId + "@" + ownBpnl;
}

public String getNotificationApiAssetId() {
return notificationAssetId + "@" + ownBpnl;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +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.ZoneId;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
Expand All @@ -33,6 +35,9 @@ See the NOTICE file(s) distributed with this work for additional
import org.eclipse.tractusx.puris.backend.masterdata.logic.service.PartnerService;
import org.springframework.stereotype.Service;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class OwnDemandService extends DemandService<OwnDemand, OwnDemandRepository> {
public OwnDemandService(OwnDemandRepository repository, PartnerService partnerService, MaterialPartnerRelationService mprService) {
Expand All @@ -42,11 +47,15 @@ public OwnDemandService(OwnDemandRepository repository, PartnerService partnerSe
public final List<Double> getQuantityForDays(String material, String partnerBpnl, String siteBpns, int numberOfDays) {
List<Double> quantities = new ArrayList<>();
LocalDate localDate = LocalDate.now();

List<OwnDemand> demands = findAllByFilters(Optional.of(material), Optional.of(partnerBpnl), Optional.of(siteBpns), Optional.empty());
for (int i = 0; i < numberOfDays; i++) {
Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
List<OwnDemand> demands = findAllByFilters(Optional.of(material), Optional.of(partnerBpnl), Optional.of(siteBpns), Optional.of(date));
double demandQuantity = getSumOfQuantities(demands);
LocalDate localDayDate = Instant.ofEpochMilli(date.getTime()).atOffset(ZoneOffset.UTC).toLocalDate();
List<OwnDemand> demandsForDate = demands.stream().filter(demand -> {
LocalDate demandDayDate = Instant.ofEpochMilli(demand.getDay().getTime()).atOffset(ZoneOffset.UTC).toLocalDate();
return demandDayDate.getDayOfMonth() == localDayDate.getDayOfMonth();
}).toList();
double demandQuantity = getSumOfQuantities(demandsForDate);
quantities.add(demandQuantity);

localDate = localDate.plusDays(1);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright (c) 2023, 2024 Volkswagen AG
* Copyright (c) 2023, 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 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.stock.logic.dto.itemstocksamm.DirectionCharacteristic;
import org.eclipse.tractusx.puris.backend.supply.logic.dto.daysofsupplysamm.DaysOfSupply;
import org.eclipse.tractusx.puris.backend.supply.logic.service.DaysOfSupplyRequestApiService;
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("days-of-supply")
@Slf4j
/**
* This class offers the endpoint for requesting the DaysOfSupply Submodel 1.0.0
*/
public class DaysOfSupplyRequestApiController {

@Autowired
private DaysOfSupplyRequestApiService daysOfSupplyRequestApiService;

private final Pattern bpnlPattern = PatternStore.BPNL_PATTERN;

private final Pattern urnPattern = PatternStore.URN_OR_UUID_PATTERN;

@Operation(summary = "This endpoint receives the DaysOfSupply Submodel 1.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}/{direction}/{representation}")
public ResponseEntity<DaysOfSupply> getDaysOfSupplyMapping(
@RequestHeader("edc-bpn") String bpnl,
@PathVariable String materialnumbercx,
@PathVariable DirectionCharacteristic direction,
@PathVariable String representation) {
if (!bpnlPattern.matcher(bpnl).matches() || !urnPattern.matcher(materialnumbercx).matches()) {
log.warn("Rejecting request at DaysOfSupply Submodel request 1.0.0 endpoint");
return ResponseEntity.badRequest().build();
}
if (!"$value".equals(representation)) {
log.warn("Rejecting request at DaysOfSupply Submodel request 1.0.0 endpoint, missing '$value' in request");
if (!PatternStore.NON_EMPTY_NON_VERTICAL_WHITESPACE_PATTERN.matcher(representation).matches()) {
representation = "<REPLACED_INVALID_REPRESENTATION>";
}
return ResponseEntity.status(501).build();
}
var samm = daysOfSupplyRequestApiService.handleDaysOfSupplySubmodelRequest(bpnl, materialnumbercx, direction);
if (samm == null) {
return ResponseEntity.status(500).build();
}
return ResponseEntity.ok(samm);
}
}
Loading
Loading