Skip to content

Commit

Permalink
Merge pull request #418 from FraunhoferISST/feat/erp_adapter_response…
Browse files Browse the repository at this point in the history
…_interface

Feat: ERP Adapter response interface
  • Loading branch information
tom-rm-meyer-ISST authored May 29, 2024
2 parents c043892 + 3434ff2 commit 8d96e81
Show file tree
Hide file tree
Showing 8 changed files with 586 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.tractusx.puris.backend.common.util.VariablesService;
import org.eclipse.tractusx.puris.backend.erpadapter.domain.model.ErpAdapterRequest;
import org.eclipse.tractusx.puris.backend.erpadapter.logic.service.ErpAdapterRequestService;
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;
Expand All @@ -37,6 +39,7 @@
import org.eclipse.tractusx.puris.backend.stock.domain.model.ReportedMaterialItemStock;
import org.eclipse.tractusx.puris.backend.stock.domain.model.ReportedProductItemStock;
import org.eclipse.tractusx.puris.backend.common.domain.model.measurement.ItemUnitEnumeration;
import org.eclipse.tractusx.puris.backend.stock.logic.dto.itemstocksamm.DirectionCharacteristic;
import org.eclipse.tractusx.puris.backend.stock.logic.service.MaterialItemStockService;
import org.eclipse.tractusx.puris.backend.stock.logic.service.ProductItemStockService;
import org.eclipse.tractusx.puris.backend.stock.logic.service.ReportedMaterialItemStockService;
Expand Down Expand Up @@ -76,6 +79,9 @@ public class DataInjectionCommandLineRunner implements CommandLineRunner {
@Autowired
private VariablesService variablesService;

@Autowired
private ErpAdapterRequestService erpAdapterRequestService;

private ObjectMapper objectMapper;

private final String semiconductorMatNbrCustomer = "MNR-7307-AU340474.002";
Expand Down Expand Up @@ -241,6 +247,19 @@ private void setupCustomerRole() throws JsonProcessingException {
.locationBpna(supplierPartner.getSites().first().getAddresses().first().getBpna())
.build();
reportedProductItemStockService.create(reportedProductItemStock);

// TODO: remove mock
ErpAdapterRequest mockRequest = ErpAdapterRequest
.builder()
.partnerBpnl(supplierPartner.getBpnl())
.requestDate(new Date(System.currentTimeMillis()-3*60*60*1000))
.ownMaterialNumber(semiconductorMaterial.getOwnMaterialNumber())
.directionCharacteristic(DirectionCharacteristic.INBOUND)
.requestType("ItemStock")
.sammVersion("2.0")
.build();
mockRequest = erpAdapterRequestService.create(mockRequest);
log.info("Created mocked ErpAdapterRequest: \n{}", mockRequest);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,20 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.authorizeHttpRequests(
// any request in spring context
(authorizeHttpRequests) -> authorizeHttpRequests
.requestMatchers("/stockView/**", "/partners/**", "/materials/**", "/materialpartnerrelations/**", "/item-stock/**", "/production/**", "/delivery/**", "/demand/**", "/planned-production/**", "/material-demand/**", "/delivery-information/**", "/edc/**", "/parttypeinformation/**")
.requestMatchers("/stockView/**",
"/partners/**",
"/materials/**",
"/materialpartnerrelations/**",
"/item-stock/**",
"/production/**",
"/delivery/**",
"/demand/**",
"/planned-production/**",
"/material-demand/**",
"/delivery-information/**",
"/edc/**",
"/erp-adapter/**",
"/parttypeinformation/**")
.authenticated()
.requestMatchers("/swagger-ui/**", "/v3/api-docs/**", "/health/**").permitAll()
.dispatcherTypeMatchers(DispatcherType.ERROR).permitAll()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/*
* 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.erpadapter.controller;

import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
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.erpadapter.logic.service.ItemStockErpAdapterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.Date;
import java.util.UUID;

import static org.eclipse.tractusx.puris.backend.common.util.PatternStore.BPNL_PATTERN;
import static org.eclipse.tractusx.puris.backend.common.util.PatternStore.NON_EMPTY_NON_VERTICAL_WHITESPACE_PATTERN;

@RestController
@RequestMapping("erp-adapter")
@Slf4j
public class ErpAdapterController {

@Autowired
private ItemStockErpAdapterService itemStockErpAdapterService;

@Operation(description = "This endpoint accepts responses from the ERP adapter. Incoming messages are expected to " +
"carry a SAMM of the previously requested type. \n\nPlease note that this version currently accepts multiple responses " +
"addressing the same request-id for testing purposes. However, in the near future, this will be enforced strictly. " +
"I.e. only the first response for a given request-id will be accepted. All later responses addressing the same request-id" +
" will be rejected (status code 409)\n\n" +
"Currently supported: \n\n" +
"| response-type | samm-version |\n" +
"|---------------|--------------|\n" +
"| ItemStock | 2.0 |"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "accepted"),
@ApiResponse(responseCode = "400", description = "bad request"),
@ApiResponse(responseCode = "404", description = "unknown request-id"),
@ApiResponse(responseCode = "409", description = "repeated answer for request-id"),
@ApiResponse(responseCode = "500", description = "internal server error"),
@ApiResponse(responseCode = "501", description = "unsupported response-type")
})
@PutMapping
public ResponseEntity<?> putMethod(
@RequestParam("request-id") UUID requestId,
@RequestParam("bpnl") String partnerBpnl,
@RequestParam("response-type") String responseType,
@RequestParam("samm-version") String sammVersion,
@RequestParam(value = "response-timestamp")
@Parameter(example = "2024-05-28T15:00:00")
@DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") Date responseTimestamp,
@io.swagger.v3.oas.annotations.parameters.RequestBody(content = {@Content(examples = {
@ExampleObject(itemStock20Sample)
})})
@RequestBody JsonNode requestBody
) {
boolean valid = BPNL_PATTERN.matcher(partnerBpnl).matches();
valid = valid && NON_EMPTY_NON_VERTICAL_WHITESPACE_PATTERN.matcher(responseType).matches();
valid = valid && NON_EMPTY_NON_VERTICAL_WHITESPACE_PATTERN.matcher(sammVersion).matches();
if (!valid) {
return ResponseEntity.badRequest().build();
}
Dto dto = new Dto(requestId, partnerBpnl, responseType, sammVersion, responseTimestamp, requestBody);
int responseCode = 501;
switch (responseType) {
case "ItemStock" -> responseCode = itemStockErpAdapterService.receiveItemStockUpdate(dto);
default -> {
return ResponseEntity.status(responseCode).body("Unsupported response type: " + responseType);
}
}
return ResponseEntity.status(responseCode).build();
}

public record Dto(UUID requestId, String partnerBpnl, String responseType, String sammVersion,
Date responseTimeStamp, JsonNode body){}

private final static String itemStock20Sample = "{\n" +
" \"materialGlobalAssetId\": null,\n" +
" \"positions\": [\n" +
" {\n" +
" \"orderPositionReference\": {\n" +
" \"supplierOrderId\": \"M-Nbr-4711\",\n" +
" \"customerOrderId\": \"C-Nbr-4711\",\n" +
" \"customerOrderPositionId\": \"PositionId-01\"\n" +
" },\n" +
" \"allocatedStocks\": [\n" +
" {\n" +
" \"isBlocked\": false,\n" +
" \"stockLocationBPNA\": \"BPNA4444444444AA\",\n" +
" \"lastUpdatedOnDateTime\": \"2023-04-28T14:23:00.123456+14:00\",\n" +
" \"quantityOnAllocatedStock\": {\n" +
" \"value\": 22.0,\n" +
" \"unit\": \"unit:piece\"\n" +
" },\n" +
" \"stockLocationBPNS\": \"BPNS4444444444XX\"\n" +
" }\n" +
" ]\n" +
" },\n" +
" {\n" +
" \"orderPositionReference\": {\n" +
" \"supplierOrderId\": \"M-Nbr-4711\",\n" +
" \"customerOrderId\": \"C-Nbr-4711\",\n" +
" \"customerOrderPositionId\": \"PositionId-03\"\n" +
" },\n" +
" \"allocatedStocks\": [\n" +
" {\n" +
" \"isBlocked\": false,\n" +
" \"stockLocationBPNA\": \"BPNA4444444444AA\",\n" +
" \"lastUpdatedOnDateTime\": \"2023-04-28T14:23:00.123456+14:00\",\n" +
" \"quantityOnAllocatedStock\": {\n" +
" \"value\": 66.0,\n" +
" \"unit\": \"unit:piece\"\n" +
" },\n" +
" \"stockLocationBPNS\": \"BPNS4444444444XX\"\n" +
" }\n" +
" ]\n" +
" },\n" +
" {\n" +
" \"orderPositionReference\": {\n" +
" \"supplierOrderId\": \"M-Nbr-4711\",\n" +
" \"customerOrderId\": \"C-Nbr-4711\",\n" +
" \"customerOrderPositionId\": \"PositionId-02\"\n" +
" },\n" +
" \"allocatedStocks\": [\n" +
" {\n" +
" \"isBlocked\": true,\n" +
" \"stockLocationBPNA\": \"BPNA4444444444AA\",\n" +
" \"lastUpdatedOnDateTime\": \"2023-04-28T14:23:00.123456+14:00\",\n" +
" \"quantityOnAllocatedStock\": {\n" +
" \"value\": 44.0,\n" +
" \"unit\": \"unit:piece\"\n" +
" },\n" +
" \"stockLocationBPNS\": \"BPNS4444444444XX\"\n" +
" }\n" +
" ]\n" +
" }\n" +
" ],\n" +
" \"direction\": \"INBOUND\"\n" +
"}";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* 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.erpadapter.domain.model;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import lombok.*;
import org.eclipse.tractusx.puris.backend.common.util.PatternStore;
import org.eclipse.tractusx.puris.backend.stock.logic.dto.itemstocksamm.DirectionCharacteristic;

import java.util.Date;
import java.util.UUID;

@Entity
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class ErpAdapterRequest {
@GeneratedValue
@Id
private UUID id;

@Pattern(regexp = PatternStore.BPNL_STRING)
@NotNull
private String partnerBpnl;

@Pattern(regexp = PatternStore.NON_EMPTY_NON_VERTICAL_WHITESPACE_STRING)
@NotNull
private String requestType;

@Pattern(regexp = PatternStore.NON_EMPTY_NON_VERTICAL_WHITESPACE_STRING)
@NotNull
private String sammVersion;

@NotNull
private Date requestDate;

private Date responseReceivedDate;

@Pattern(regexp = PatternStore.NON_EMPTY_NON_VERTICAL_WHITESPACE_STRING)
@NotNull
private String ownMaterialNumber;

private DirectionCharacteristic directionCharacteristic;
}
Original file line number Diff line number Diff line change
@@ -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.erpadapter.domain.repository;

import org.eclipse.tractusx.puris.backend.erpadapter.domain.model.ErpAdapterRequest;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.UUID;

@Repository
public interface ErpAdapterRequestRepository extends JpaRepository<ErpAdapterRequest, UUID> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* 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.erpadapter.logic.service;

import org.eclipse.tractusx.puris.backend.erpadapter.domain.model.ErpAdapterRequest;
import org.eclipse.tractusx.puris.backend.erpadapter.domain.repository.ErpAdapterRequestRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.UUID;

@Service
public class ErpAdapterRequestService {

@Autowired
private ErpAdapterRequestRepository repository;

public ErpAdapterRequest create(ErpAdapterRequest erpAdapterRequest) {
if (erpAdapterRequest.getId() != null && repository.existsById(erpAdapterRequest.getId())) {
return null;
}
return repository.save(erpAdapterRequest);
}

public ErpAdapterRequest get(UUID id) {
// TODO: Remove when mock is removed
return repository.findById(id).orElse(repository.findAll().getFirst());
// return repository.findById(id).orElse(null);
}

public ErpAdapterRequest update(ErpAdapterRequest erpAdapterRequest) {
if (repository.existsById(erpAdapterRequest.getId())) {
return repository.save(erpAdapterRequest);
}
return null;
}

public void delete(UUID id) {
repository.deleteById(id);
}
}
Loading

0 comments on commit 8d96e81

Please sign in to comment.