diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b38f914ce..5d5c50610e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- Added fetchCatalog to EDCCatalogFacade ## [3.3.4] - 2023-08-24 ### Fixed diff --git a/DEPENDENCIES b/DEPENDENCIES index f033c05c3c..d731363801 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -158,7 +158,7 @@ maven/mavencentral/org.eclipse.tractusx.irs/irs-edc-client/0.0.2-SNAPSHOT, Apach maven/mavencentral/org.eclipse.tractusx.irs/irs-ess/0.0.2-SNAPSHOT, Apache-2.0, approved, automotive.tractusx maven/mavencentral/org.eclipse.tractusx.irs/irs-models/0.0.2-SNAPSHOT, Apache-2.0, approved, automotive.tractusx maven/mavencentral/org.eclipse.tractusx.irs/irs-policy-store/0.0.2-SNAPSHOT, Apache-2.0, approved, automotive.tractusx -maven/mavencentral/org.eclipse.tractusx.irs/irs-registry-client/1.1.0-SNAPSHOT, Apache-2.0, approved, automotive.tractusx +maven/mavencentral/org.eclipse.tractusx.irs/irs-registry-client/1.1.1-SNAPSHOT, Apache-2.0, approved, automotive.tractusx maven/mavencentral/org.glassfish/jakarta.json/2.0.1, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jsonp maven/mavencentral/org.graalvm.sdk/graal-sdk/23.0.1, UPL-1.0, approved, #9850 maven/mavencentral/org.hamcrest/hamcrest-core/2.2, BSD-3-Clause, approved, clearlydefined diff --git a/docs/src/api/irs-v1.0.yaml b/docs/src/api/irs-v1.0.yaml index c2337d9f1a..2b772d4aea 100644 --- a/docs/src/api/irs-v1.0.yaml +++ b/docs/src/api/irs-v1.0.yaml @@ -1817,6 +1817,7 @@ components: enum: - asBuilt - asPlanned + - asSpecified bpn: type: string callbackUrl: @@ -1934,6 +1935,7 @@ components: enum: - asBuilt - asPlanned + - asSpecified quantity: $ref: '#/components/schemas/Quantity' MeasurementUnit: @@ -2095,6 +2097,7 @@ components: enum: - asBuilt - asPlanned + - asSpecified callbackUrl: type: string description: "Callback url to notify requestor when job processing is finished.\ @@ -2157,6 +2160,7 @@ components: enum: - asBuilt - asPlanned + - asSpecified callbackUrl: type: string description: "Callback url to notify requestor when job processing is finished.\ @@ -2190,6 +2194,7 @@ components: enum: - asBuilt - asPlanned + - asSpecified callbackUrl: type: string description: "Callback url to notify requestor when job processing is finished.\ diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/ItemTreesAssembler.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/ItemTreesAssembler.java index a3b72c93c7..e3ed3107c9 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/ItemTreesAssembler.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/ItemTreesAssembler.java @@ -31,6 +31,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.eclipse.tractusx.irs.component.Bpn; import org.eclipse.tractusx.irs.component.Relationship; import org.eclipse.tractusx.irs.component.Submodel; @@ -64,7 +65,7 @@ public class ItemTreesAssembler { tombstones.addAll(itemGraph.getTombstones()); shells.addAll(itemGraph.getShells()); submodels.addAll(itemGraph.getSubmodels()); - bpns.addAll(itemGraph.getBpns()); + bpns.addAll(itemGraph.getBpns().stream().filter(bpn -> StringUtils.isNotBlank(bpn.getManufacturerName())).toList()); }); log.info("Assembled item graph from {} partial graphs", numberOfPartialTrees); diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegate.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegate.java index 64593084a7..b2ff726aed 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegate.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegate.java @@ -126,7 +126,7 @@ private void processEndpoint(final Endpoint endpoint, final RelationshipAspect r } private static List getBpnsFrom(final List relationships) { - return relationships.stream().map(Relationship::getBpn).map(Bpn::withManufacturerId).toList(); + return relationships.stream().map(Relationship::getBpn).filter(StringUtils::isNotBlank).map(Bpn::withManufacturerId).toList(); } private List getIdsToProcess(final List relationships, diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/semanticshub/SemanticsHubClient.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/semanticshub/SemanticsHubClient.java index d591123f67..2265eea6e4 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/semanticshub/SemanticsHubClient.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/semanticshub/SemanticsHubClient.java @@ -93,6 +93,8 @@ public List getAllAspectModels() { "EsrCertificate", MODEL_TYPE, MODEL_STATUS), new AspectModel("urn:bamm:io.catenax.single_level_bom_as_built:1.0.0#SingleLevelBomAsBuilt", "1.0.0", "SingleLevelBomAsBuilt", MODEL_TYPE, MODEL_STATUS), + new AspectModel("urn:bamm:io.catenax.part_as_specified:2.0.0#PartAsSpecified", + "2.0.0", "PartAsSpecified", MODEL_TYPE, MODEL_STATUS), new AspectModel("urn:bamm:io.catenax.part_as_planned:1.0.1#PartAsPlanned", "1.0.1", "PartAsPlanned", MODEL_TYPE, MODEL_STATUS)); } diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryService.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryService.java index 97a1de1b77..6b63d122e9 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryService.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryService.java @@ -170,10 +170,9 @@ public JobHandle registerItemJob(final @NonNull RegisterJob request) { public JobHandle registerItemJob(final @NonNull RegisterJob request, final UUID batchId) { final var params = buildJobParameter(request); - if (params.getBomLifecycle().equals(BomLifecycle.AS_PLANNED) && params.getDirection() - .equals(Direction.UPWARD)) { + if (params.getDirection().equals(Direction.UPWARD) && !params.getBomLifecycle().equals(BomLifecycle.AS_BUILT)) { // Currently not supported variant - throw new IllegalArgumentException("BomLifecycle asPlanned with direction upward is not supported yet!"); + throw new IllegalArgumentException("Upward direction is supported only for asBuilt bomLifecycle parameter!"); } if (params.isLookupBPNs() && StringUtils.isBlank(bpdmUrl)) { throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsFunctionalTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsFunctionalTest.java index 3c81db74c0..0f14d346da 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsFunctionalTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsFunctionalTest.java @@ -117,7 +117,7 @@ void shouldStartJobAndRetrieveResult() { assertThat(finishedJob.get().getShells()).isNotEmpty(); assertThat(finishedJob.get().getTombstones()).isEmpty(); assertThat(finishedJob.get().getSubmodels()).isEmpty(); - assertThat(finishedJob.get().getBpns()).isNotEmpty(); + assertThat(finishedJob.get().getBpns()).isEmpty(); assertThat(finishedJob.get().getJob()).isNotNull(); assertThat(finishedJob.get().getJob().getSummary()).isNotNull(); assertThat(finishedJob.get().getJob().getParameter()).isNotNull(); diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryServiceSpringBootTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryServiceSpringBootTest.java index 790b7441e2..dfde7c8c4e 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryServiceSpringBootTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryServiceSpringBootTest.java @@ -283,6 +283,16 @@ void shouldThrowIllegalArgumentExceptionForLifecycleAsPlannedAndDirectionUpward( assertThrows(IllegalArgumentException.class, () -> service.registerItemJob(registerJob)); } + @Test + void shouldThrowIllegalArgumentExceptionForLifecycleAsSpecifiedAndDirectionUpward() { + final RegisterJob registerJob = new RegisterJob(); + registerJob.setKey(PartChainIdentificationKey.builder().globalAssetId(UUID.randomUUID().toString()).build()); + registerJob.setDirection(Direction.UPWARD); + registerJob.setBomLifecycle(BomLifecycle.AS_SPECIFIED); + + assertThrows(IllegalArgumentException.class, () -> service.registerItemJob(registerJob)); + } + private int getRelationshipsSize(final UUID jobId) { return service.getJobForJobId(jobId, false).getRelationships().size(); } diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EDCCatalogFacade.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EDCCatalogFacade.java index 69ee8e7317..5aa21d692f 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EDCCatalogFacade.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EDCCatalogFacade.java @@ -34,10 +34,12 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.edc.catalog.spi.Catalog; +import org.eclipse.edc.catalog.spi.CatalogRequest; import org.eclipse.edc.catalog.spi.Dataset; import org.eclipse.edc.policy.model.Policy; import org.eclipse.tractusx.irs.edc.client.configuration.JsonLdConfiguration; import org.eclipse.tractusx.irs.edc.client.model.CatalogItem; + import org.springframework.stereotype.Component; /** @@ -74,6 +76,19 @@ private static CatalogItem createCatalogItem(final Catalog pageableCatalog, fina return builder.build(); } + /** + * Fetches a list of {@link CatalogItem} objects based on the given {@link CatalogRequest}. + * This method communicates with the control plane client to retrieve the catalog + * and maps it to a list of catalog items. + * + * @param catalogRequest The request containing the parameters needed to fetch the catalog. + * @return A list of {@link CatalogItem} objects representing the items in the catalog. + */ + public List fetchCatalogItems(final CatalogRequest catalogRequest) { + final Catalog catalog = controlPlaneClient.getCatalog(catalogRequest); + return mapToCatalogItems(catalog); + } + private static List mapToCatalogItems(final Catalog catalog) { if (catalog.getDatasets() == null) { return List.of(); diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/RelationshipAspect.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/RelationshipAspect.java index cf3efa2df0..5b95d34ae0 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/RelationshipAspect.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/RelationshipAspect.java @@ -42,6 +42,8 @@ public enum RelationshipAspect { Direction.DOWNWARD), SINGLE_LEVEL_BOM_AS_BUILT("SingleLevelBomAsBuilt", SingleLevelBomAsBuilt.class, BomLifecycle.AS_BUILT, Direction.DOWNWARD), + SINGLE_LEVEL_BOM_AS_SPECIFIED("SingleLevelBomAsSpecified", SingleLevelBomAsSpecified.class, BomLifecycle.AS_SPECIFIED, + Direction.DOWNWARD), SINGLE_LEVEL_USAGE_AS_BUILT("SingleLevelUsageAsBuilt", SingleLevelUsageAsBuilt.class, BomLifecycle.AS_BUILT, Direction.UPWARD); @@ -56,6 +58,7 @@ public enum RelationshipAspect { * @return Returns traversal aspect type * asBuilt + downward => SingleLevelBomAsBuilt * asPlanned + downward => SingleLevelBomAsPlanned + * asSpecified + downward => SingleLevelBomAsSpecified * asBuilt + upward => SingleLevelUsageAsBuilt * asPlanned + upward => SingleLevelXXXAsPlanned */ diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/SingleLevelBomAsSpecified.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/SingleLevelBomAsSpecified.java new file mode 100644 index 0000000000..8537a20f92 --- /dev/null +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/SingleLevelBomAsSpecified.java @@ -0,0 +1,125 @@ +/******************************************************************************** + * Copyright (c) 2021,2022,2023 + * 2022: ZF Friedrichshafen AG + * 2022: ISTOS GmbH + * 2022,2023: Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * 2022,2023: BOSCH AG + * Copyright (c) 2021,2022,2023 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.irs.edc.client; + +import java.time.ZonedDateTime; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.extern.jackson.Jacksonized; +import org.eclipse.tractusx.irs.component.GlobalAssetIdentification; +import org.eclipse.tractusx.irs.component.LinkedItem; +import org.eclipse.tractusx.irs.component.MeasurementUnit; +import org.eclipse.tractusx.irs.component.Quantity; +import org.eclipse.tractusx.irs.component.Relationship; +import org.eclipse.tractusx.irs.component.enums.AspectType; +import org.eclipse.tractusx.irs.component.enums.BomLifecycle; + +/** + * SingleLevelBomAsSpecified + */ +@Data +@Jacksonized +@AllArgsConstructor +@NoArgsConstructor +public class SingleLevelBomAsSpecified implements RelationshipSubmodel { + + private String catenaXId; + private Set childParts; + + @Override + public List asRelationships() { + return Optional.ofNullable(this.childParts).stream().flatMap(Collection::stream) + .map(childData -> childData.toRelationship(this.catenaXId)) + .toList(); + } + + /** + * ChildData + */ + @Data + @AllArgsConstructor + @NoArgsConstructor + /* package */ static class ChildData { + + private String childPartsCategory; + private Set part; + private String childCatenaXId; + private String businessPartner; + + public Relationship toRelationship(final String catenaXId) { + final Part childPart = this.part.stream().findFirst().orElse(new Part()); + + final LinkedItem.LinkedItemBuilder linkedItem = LinkedItem.builder() + .childCatenaXId(GlobalAssetIdentification.of(this.childCatenaXId)) + .lifecycleContext(BomLifecycle.AS_SPECIFIED) + .assembledOn(childPart.getCreatedOn()) + .lastModifiedOn(childPart.getLastModifiedOn()); + + if (childPart.getPartQuantity() != null) { + linkedItem.quantity(Quantity.builder() + .quantityNumber(childPart.getPartQuantity().getQuantityNumber()) + .measurementUnit(MeasurementUnit.builder().lexicalValue(childPart.getPartQuantity().getMeasurementUnit()).build()) + .build()); + } + + return Relationship.builder() + .catenaXId(GlobalAssetIdentification.of(catenaXId)) + .linkedItem(linkedItem.build()) + .bpn(this.businessPartner) + .aspectType(AspectType.SINGLE_LEVEL_BOM_AS_SPECIFIED.toString()) + .build(); + } + + /** + * Part + */ + @Data + @Jacksonized + @SuppressWarnings("PMD.ShortClassName") + /* package */ static class Part { + + private String ownerPartId; + private String partVersion; + private PartQuantity partQuantity; + private String partDescription; + private ZonedDateTime createdOn; + private ZonedDateTime lastModifiedOn; + + /** + * Part Quantity + */ + @Data + @Jacksonized + /* package */ static class PartQuantity { + private Double quantityNumber; + private String measurementUnit; + } + } + } +} diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/SubmodelTestdataCreator.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/SubmodelTestdataCreator.java index c8d49342c2..f440217d4c 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/SubmodelTestdataCreator.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/SubmodelTestdataCreator.java @@ -58,6 +58,8 @@ public Map createSubmodelForId(final String endpointAddress) { return this.cxTestDataContainer.getByCatenaXId(catenaXId).flatMap(CxTestDataContainer.CxTestData::getSingleLevelBomAsBuilt).orElse(Map.of()); } else if (endpointAddress.contains("singleLevelUsageAsBuilt")) { return this.cxTestDataContainer.getByCatenaXId(catenaXId).flatMap(CxTestDataContainer.CxTestData::getSingleLevelUsageAsBuilt).orElse(Map.of()); + } else if (endpointAddress.contains("singleLevelBomAsSpecified")) { + return this.cxTestDataContainer.getByCatenaXId(catenaXId).flatMap(CxTestDataContainer.CxTestData::getSingleLevelBomAsSpecified).orElse(Map.of()); } else if (endpointAddress.contains("serialPart")) { return this.cxTestDataContainer.getByCatenaXId(catenaXId).flatMap(CxTestDataContainer.CxTestData::getSerialPart).orElse(Map.of()); } else if (endpointAddress.contains("singleLevelBomAsPlanned")) { @@ -72,6 +74,8 @@ public Map createSubmodelForId(final String endpointAddress) { return this.cxTestDataContainer.getByCatenaXId(catenaXId).flatMap(CxTestDataContainer.CxTestData::getProductDescription).orElse(Map.of()); } else if (endpointAddress.contains("physicalDimension")) { return this.cxTestDataContainer.getByCatenaXId(catenaXId).flatMap(CxTestDataContainer.CxTestData::getPhysicalDimension).orElse(Map.of()); + } else if (endpointAddress.contains("partAsSpecified")) { + return this.cxTestDataContainer.getByCatenaXId(catenaXId).flatMap(CxTestDataContainer.CxTestData::getPartAsSpecified).orElse(Map.of()); } return Map.of(); } diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java index 33d4c0deda..1442d0db01 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java @@ -58,7 +58,6 @@ import org.eclipse.tractusx.irs.component.enums.Direction; import org.eclipse.tractusx.irs.data.StringMapper; import org.eclipse.tractusx.irs.edc.client.exceptions.ContractNegotiationException; -import org.eclipse.tractusx.irs.edc.client.exceptions.EdcClientException; import org.eclipse.tractusx.irs.edc.client.exceptions.TimeoutException; import org.eclipse.tractusx.irs.edc.client.exceptions.TransferProcessException; import org.eclipse.tractusx.irs.edc.client.exceptions.UsagePolicyException; @@ -223,6 +222,19 @@ void shouldReturnRelationshipsWhenRequestingWithCatenaXIdAndSingleLevelBomAsPlan assertThat(submodelResponse).contains("urn:uuid:e5c96ab5-896a-482c-8761-efd74777ca97"); } + @Test + void shouldReturnRelationshipsWhenRequestingWithCatenaXIdAndSingleLevelBomAsSpecified() throws Exception { + final String catenaXId = "urn:uuid:ed333e9a-5afa-40b2-99da-bae2fd21501e"; + when(catalogFacade.fetchCatalogByFilter(any(), any(), any())).thenReturn( + List.of(CatalogItem.builder().itemId(catenaXId).build())); + prepareTestdata(catenaXId, "_singleLevelBomAsSpecified"); + + final String submodelResponse = testee.getSubmodelRawPayload("http://localhost/", "/submodel", ASSET_ID) + .get(5, TimeUnit.SECONDS); + + assertThat(submodelResponse).contains("urn:uuid:7eeeac86-7b69-444d-81e6-655d0f1513bd"); + } + @Test void shouldReturnEmptyRelationshipsWhenRequestingWithCatenaXIdAndSingleLevelUsageAsBuilt() throws Exception { final String catenaXId = "urn:uuid:61c83b41-def0-4742-a1a8-e4e8a8cb210e"; diff --git a/irs-models/src/main/java/org/eclipse/tractusx/irs/component/enums/AspectType.java b/irs-models/src/main/java/org/eclipse/tractusx/irs/component/enums/AspectType.java index b7e51d7fd1..7c9fc2d492 100644 --- a/irs-models/src/main/java/org/eclipse/tractusx/irs/component/enums/AspectType.java +++ b/irs-models/src/main/java/org/eclipse/tractusx/irs/component/enums/AspectType.java @@ -54,12 +54,14 @@ public enum AspectType { MATERIAL_FOR_HOMOLOGATION(AspectTypesConstants.MATERIAL_FOR_HOMOLOGATION), MATERIAL_FOR_RECYCLING(AspectTypesConstants.MATERIAL_FOR_RECYCLING), PART_AS_PLANNED(AspectTypesConstants.PART_AS_PLANNED), + PART_AS_SPECIFIED(AspectTypesConstants.PART_AS_SPECIFIED), PHYSICAL_DIMENSION(AspectTypesConstants.PHYSICAL_DIMENSION), PRODUCT_DESCRIPTION(AspectTypesConstants.PRODUCT_DESCRIPTION), RETURN_REQUEST(AspectTypesConstants.RETURN_REQUEST), SERIAL_PART(AspectTypesConstants.SERIAL_PART), SINGLE_LEVEL_BOM_AS_BUILT(AspectTypesConstants.SINGLE_LEVEL_BOM_AS_BUILT), SINGLE_LEVEL_BOM_AS_PLANNED(AspectTypesConstants.SINGLE_LEVEL_BOM_AS_PLANNED), + SINGLE_LEVEL_BOM_AS_SPECIFIED(AspectTypesConstants.SINGLE_LEVEL_BOM_AS_SPECIFIED), SINGLE_LEVEL_USAGE_AS_BUILT(AspectTypesConstants.SINGLE_LEVEL_USAGE_AS_BUILT); private final String name; @@ -120,12 +122,14 @@ public static final class AspectTypesConstants { public static final String MATERIAL_FOR_HOMOLOGATION = "MaterialForHomologation"; public static final String MATERIAL_FOR_RECYCLING = "MaterialForRecycling"; public static final String PART_AS_PLANNED = "PartAsPlanned"; + public static final String PART_AS_SPECIFIED = "PartAsSpecified"; public static final String PHYSICAL_DIMENSION = "PhysicalDimension"; public static final String PRODUCT_DESCRIPTION = "ProductDescription"; public static final String RETURN_REQUEST = "ReturnRequest"; public static final String SERIAL_PART = "SerialPart"; public static final String SINGLE_LEVEL_BOM_AS_BUILT = "SingleLevelBomAsBuilt"; public static final String SINGLE_LEVEL_BOM_AS_PLANNED = "SingleLevelBomAsPlanned"; + public static final String SINGLE_LEVEL_BOM_AS_SPECIFIED = "SingleLevelBomAsSpecified"; public static final String SINGLE_LEVEL_USAGE_AS_BUILT = "SingleLevelUsageAsBuilt"; } } diff --git a/irs-models/src/main/java/org/eclipse/tractusx/irs/component/enums/BomLifecycle.java b/irs-models/src/main/java/org/eclipse/tractusx/irs/component/enums/BomLifecycle.java index 4508fee002..c153ba52c7 100644 --- a/irs-models/src/main/java/org/eclipse/tractusx/irs/component/enums/BomLifecycle.java +++ b/irs-models/src/main/java/org/eclipse/tractusx/irs/component/enums/BomLifecycle.java @@ -41,7 +41,8 @@ @Getter public enum BomLifecycle { AS_BUILT("asBuilt", AspectType.SERIAL_PART), - AS_PLANNED("asPlanned", AspectType.PART_AS_PLANNED); + AS_PLANNED("asPlanned", AspectType.PART_AS_PLANNED), + AS_SPECIFIED("asSpecified", AspectType.PART_AS_SPECIFIED); private final String name; private final String defaultAspect; diff --git a/irs-models/src/main/java/org/eclipse/tractusx/irs/data/CxTestDataContainer.java b/irs-models/src/main/java/org/eclipse/tractusx/irs/data/CxTestDataContainer.java index 5f22c559cb..ba2485753e 100644 --- a/irs-models/src/main/java/org/eclipse/tractusx/irs/data/CxTestDataContainer.java +++ b/irs-models/src/main/java/org/eclipse/tractusx/irs/data/CxTestDataContainer.java @@ -56,12 +56,14 @@ public static class CxTestData { public static final String SERIAL_PART_ASPECT_TYPE = "urn:bamm:io.catenax.serial_part:1.1.0#SerialPart"; public static final String SINGLE_LEVEL_BOM_AS_BUILT_ASPECT_TYPE = "urn:bamm:io.catenax.single_level_bom_as_built:1.0.0#SingleLevelBomAsBuilt"; public static final String SINGLE_LEVEL_USAGE_BUILT_ASPECT_TYPE = "urn:bamm:io.catenax.single_level_usage_as_built:1.0.1#SingleLevelUsageAsBuilt"; + public static final String SINGLE_LEVEL_BOM_AS_SPECIFIED_ASPECT_TYPE = "urn:bamm:io.catenax.single_level_bom_as_specified:1.0.0#SingleLevelBomAsSpecified"; public static final String PART_AS_PLANNED_ASPECT_TYPE = "urn:bamm:io.catenax.part_as_planned:1.0.0#PartAsPlanned"; public static final String SINGLE_LEVEL_BOM_AS_PLANNED_ASPECT_TYPE = "urn:bamm:io.catenax.single_level_bom_as_planned:2.0.0#SingleLevelBomAsPlanned"; public static final String BATCH_ASPECT_TYPE = "urn:bamm:io.catenax.batch:1.0.0#Batch"; public static final String MATERIAL_FOR_RECYCLING_ASPECT_TYPE = "urn:bamm:io.catenax.material_for_recycling:1.1.0#MaterialForRecycling"; public static final String PRODUCT_DESCRIPTION_ASPECT_TYPE = "urn:bamm:io.catenax.battery.product_description:1.0.1#ProductDescription"; public static final String PHYSICAL_DIMENSION_ASPECT_TYPE = "urn:bamm:io.catenax.physical_dimension:1.0.0#PhysicalDimension"; + public static final String PART_AS_SPECIFIED_ASPECT_TYPE = "urn:bamm:io.catenax.part_as_specified:2.0.0#PartAsSpecified"; private String catenaXId; @JsonProperty(SERIAL_PART_ASPECT_TYPE) @@ -70,6 +72,8 @@ public static class CxTestData { private List> singleLevelBomAsBuilt; @JsonProperty(SINGLE_LEVEL_USAGE_BUILT_ASPECT_TYPE) private List> singleLevelUsageAsBuilt; + @JsonProperty(SINGLE_LEVEL_BOM_AS_SPECIFIED_ASPECT_TYPE) + private List> singleLevelBomAsSpecified; @JsonProperty(PART_AS_PLANNED_ASPECT_TYPE) private List> partAsPlanned; @JsonProperty(SINGLE_LEVEL_BOM_AS_PLANNED_ASPECT_TYPE) @@ -82,6 +86,8 @@ public static class CxTestData { private List> productDescription; @JsonProperty(PHYSICAL_DIMENSION_ASPECT_TYPE) private List> physicalDimension; + @JsonProperty(PART_AS_SPECIFIED_ASPECT_TYPE) + private List> partAsSpecified; public Optional> getSerialPart() { return serialPart != null ? serialPart.stream().findFirst() : Optional.empty(); @@ -95,6 +101,10 @@ public Optional> getSingleLevelUsageAsBuilt() { return singleLevelUsageAsBuilt != null ? singleLevelUsageAsBuilt.stream().findFirst() : Optional.empty(); } + public Optional> getSingleLevelBomAsSpecified() { + return singleLevelBomAsSpecified != null ? singleLevelBomAsSpecified.stream().findFirst() : Optional.empty(); + } + public Optional> getPartAsPlanned() { return partAsPlanned != null ? partAsPlanned.stream().findFirst() : Optional.empty(); } @@ -118,5 +128,9 @@ public Optional> getProductDescription() { public Optional> getPhysicalDimension() { return physicalDimension != null ? physicalDimension.stream().findFirst() : Optional.empty(); } + + public Optional> getPartAsSpecified() { + return partAsSpecified != null ? partAsSpecified.stream().findFirst() : Optional.empty(); + } } } diff --git a/irs-models/src/main/resources/test_data/CX_Testdata.json b/irs-models/src/main/resources/test_data/CX_Testdata.json index b770ad84b2..2cc2804204 100644 --- a/irs-models/src/main/resources/test_data/CX_Testdata.json +++ b/irs-models/src/main/resources/test_data/CX_Testdata.json @@ -473,6 +473,50 @@ "lastModifiedOn" : "2022-02-03T14:48:54.709Z" } ] } ], + "urn:bamm:io.catenax.single_level_bom_as_specified:1.0.0#SingleLevelBomAsSpecified": [ { + "catenaXId": "urn:uuid:ed333e9a-5afa-40b2-99da-bae2fd21501e", + "childParts": [ { + "childPartsCategory": "e.g. vehicle, winter wheels, bicycle rack", + "part": [ { + "ownerPartId": "22782277-50", + "partVersion": "05", + "partQuantity": { + "quantityNumber": 350.0, + "measurementUnit": "kW" + }, + "partDescription": "The steering wheel is nice and round", + "partClassification": [ { + "value": "STEEWHL", + "key": "BMW:PartFamily" + } + ], + "createdOn": "2022-02-03T14:48:54.709Z", + "lastModifiedOn": "2022-02-03T14:48:54.709Z" + } + ], + "childCatenaXId": "urn:uuid:7eeeac86-7b69-444d-81e6-655d0f1513bd", + "businessPartner": "BPNL00000003XXQP" + } ] + } ], + "urn:bamm:io.catenax.part_as_specified:2.0.0#PartAsSpecified": [ { + "partTypeInformation": { + "partClassification": [ { + "value": "STEEWHL", + "key": "BMW:PartFamily" + } + ], + "ownerPartId": "22782277-50", + "partVersion": "05", + "itemCategory": "component", + "nameAtOwner": "Steering Wheel", + "partDescription": "The steering wheel is nice and round" + }, + "validityPeriod": { + "validFrom": "2023-02-10T07:17:52.396Z", + "validTo": "2023-02-10T07:17:52.396Z" + }, + "catenaXId": "urn:uuid:ed333e9a-5afa-40b2-99da-bae2fd21501e" + } ], "https://catenax.io/schema/AAS/3.0" : [ { "specificAssetId" : [ { "value" : "OMBSWNHVABEWMQTAV", diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/central/AssetAdministrationShellTestdataCreator.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/central/AssetAdministrationShellTestdataCreator.java index a918eef3d3..c9be8a0c93 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/central/AssetAdministrationShellTestdataCreator.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/central/AssetAdministrationShellTestdataCreator.java @@ -58,6 +58,7 @@ public AssetAdministrationShellDescriptor createDummyAssetAdministrationShellDes } final List submodelDescriptors = new ArrayList<>(); + cxTestData.get() .getSingleLevelBomAsBuilt() .ifPresent(submodel -> submodelDescriptors.add( @@ -69,6 +70,10 @@ public AssetAdministrationShellDescriptor createDummyAssetAdministrationShellDes .getSingleLevelUsageAsBuilt() .ifPresent(submodel -> submodelDescriptors.add( createSingleLevelUsageAsBuiltSubmodelDescriptor(catenaXId))); + cxTestData.get() + .getSingleLevelBomAsSpecified() + .ifPresent(submodel -> submodelDescriptors.add( + createSingleLevelBomAsSpecifiedSubmodelDescriptor(catenaXId))); cxTestData.get() .getSingleLevelBomAsPlanned() .ifPresent(submodel -> submodelDescriptors.add( @@ -90,6 +95,9 @@ public AssetAdministrationShellDescriptor createDummyAssetAdministrationShellDes cxTestData.get() .getPhysicalDimension() .ifPresent(submodel -> submodelDescriptors.add(createPhysicalDimensionSubmodelDescriptor(catenaXId))); + cxTestData.get() + .getPartAsSpecified() + .ifPresent(submodel -> submodelDescriptors.add(createPartAsSpecifiedSubmodelDescriptor(catenaXId))); return AssetAdministrationShellDescriptor.builder() .description(List.of(LangString.builder().build())) @@ -114,6 +122,11 @@ private SubmodelDescriptor createSingleLevelUsageAsBuiltSubmodelDescriptor(final "singleLevelUsageAsBuilt"); } + private SubmodelDescriptor createSingleLevelBomAsSpecifiedSubmodelDescriptor(final String catenaXId) { + return createSubmodelDescriptor(catenaXId, "urn:bamm:io.catenax.single_level_bom_as_specified:1.0.0", + "singleLevelBomAsSpecified"); + } + private SubmodelDescriptor createSerialPartSubmodelDescriptor(final String catenaXId) { return createSubmodelDescriptor(catenaXId, "urn:bamm:io.catenax.serial_part:1.0.0", "serialPart"); } @@ -145,6 +158,11 @@ private SubmodelDescriptor createPhysicalDimensionSubmodelDescriptor(final Strin return createSubmodelDescriptor(catenaXId, "urn:bamm:io.catenax.physical_dimension:1.0.0", "physicalDimension"); } + private SubmodelDescriptor createPartAsSpecifiedSubmodelDescriptor(final String catenaXId) { + return createSubmodelDescriptor(catenaXId, "urn:bamm:io.catenax.part_as_specified:1.0.0", + "partAsSpecified"); + } + private SubmodelDescriptor createSubmodelDescriptor(final String catenaXId, final String submodelUrn, final String submodelName) { final ProtocolInformation protocolInformation = ProtocolInformation.builder() diff --git a/pom.xml b/pom.xml index a979d84d6c..9cc74307ce 100644 --- a/pom.xml +++ b/pom.xml @@ -66,7 +66,7 @@ 3.3.0 3.11.0 3.1.1 - 1.1.0-SNAPSHOT + 1.1.1-SNAPSHOT