Skip to content
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ The **need for configuration updates** is **marked bold**.

### Added

- /
- Added improved error messages for refresh materials ([#995](https://github.com/eclipse-tractusx/puris/pull/995))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update to latest changelog version (changed meanwhile) and consider this a major version.

Please also update:

  • frontend/package.json
  • frontend/package-lock.json
  • backend/pom.xml
  • charts/Chart.yaml
  • charts/README.md
  • docs/admin/Migration_Guide

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please merge main / bump to major version


### Changed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,22 @@
import org.eclipse.tractusx.puris.backend.common.edc.logic.service.EdcAdapterService;
import org.eclipse.tractusx.puris.backend.delivery.domain.model.DeliveryResponsibilityEnumeration;
import org.eclipse.tractusx.puris.backend.delivery.domain.model.OwnDelivery;
import org.eclipse.tractusx.puris.backend.delivery.domain.model.ReportedDelivery;
import org.eclipse.tractusx.puris.backend.delivery.logic.adapter.DeliveryInformationSammMapper;
import org.eclipse.tractusx.puris.backend.delivery.logic.dto.deliverysamm.DeliveryInformation;
import org.eclipse.tractusx.puris.backend.masterdata.domain.model.Material;
import org.eclipse.tractusx.puris.backend.masterdata.domain.model.MaterialPartnerRelation;
import org.eclipse.tractusx.puris.backend.masterdata.domain.model.Partner;
import org.eclipse.tractusx.puris.backend.masterdata.domain.model.RefreshError;
import org.eclipse.tractusx.puris.backend.masterdata.domain.model.RefreshResult;
import org.eclipse.tractusx.puris.backend.masterdata.logic.service.MaterialPartnerRelationService;
import org.eclipse.tractusx.puris.backend.masterdata.logic.service.MaterialService;
import org.eclipse.tractusx.puris.backend.masterdata.logic.service.PartnerService;
import org.eclipse.tractusx.puris.backend.stock.logic.dto.itemstocksamm.DirectionCharacteristic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
Expand Down Expand Up @@ -144,7 +148,8 @@ public DeliveryInformation handleDeliverySubmodelRequest(String bpnl, String mat
return sammMapper.ownDeliveryToSamm(currentDeliveries, partner, material);
}

public void doReportedDeliveryRequest(Partner partner, Material material) {
public RefreshResult doReportedDeliveryRequest(Partner partner, Material material) {
List<RefreshError> errors = new ArrayList<>();
try {
var mpr = mprService.find(material, partner);
if (mpr.getPartnerCXNumber() == null) {
Expand All @@ -159,10 +164,22 @@ public void doReportedDeliveryRequest(Partner partner, Material material) {
var deliveryPartner = delivery.getPartner();
var deliveryMaterial = delivery.getMaterial();
if (!partner.equals(deliveryPartner) || !material.equals(deliveryMaterial)) {
log.warn("Received inconsistent data from " + partner.getBpnl() + "\n" + deliveries);
return;
errors.add(new RefreshError(List.of("Received inconsistent data from " + partner.getBpnl())));
continue;
}

List<String> validationErrors = reportedDeliveryService.validateWithDetails(delivery);
if (!validationErrors.isEmpty()) {
errors.add(new RefreshError(validationErrors));
}
}

if (!errors.isEmpty()) {
log.warn("Validation errors found for ReportedDelivery request from partner {} for material {}: {}",
partner.getBpnl(), material.getOwnMaterialNumber(), errors);
return new RefreshResult("Validation failed for reported deliveries", errors);
}

// delete older data:
var oldDeliveries = reportedDeliveryService.findAllByFilters(Optional.of(material.getOwnMaterialNumber()), Optional.empty(), Optional.of(partner.getBpnl()), Optional.empty(), Optional.empty());
for (var oldDelivery : oldDeliveries) {
Expand All @@ -171,11 +188,14 @@ public void doReportedDeliveryRequest(Partner partner, Material material) {
for (var newDelivery : deliveries) {
reportedDeliveryService.create(newDelivery);
}
log.info("Updated Reported Deliveries for " + material.getOwnMaterialNumber() + " and partner " + partner.getBpnl());

log.info("Successfully updated ReportedDelivery for {} and partner {}",
material.getOwnMaterialNumber(), partner.getBpnl());
materialService.updateTimestamp(material.getOwnMaterialNumber());
return new RefreshResult("Successfully processed all reported deliveries", errors);
} catch (Exception e) {
log.error("Error in Reported Deliveries Request for " + material.getOwnMaterialNumber() + " and partner " + partner.getBpnl(), e);
errors.add(new RefreshError(List.of("System error: " + e.getMessage())));
return new RefreshResult("System error occurred during processing", errors);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

package org.eclipse.tractusx.puris.backend.delivery.logic.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
Expand Down Expand Up @@ -76,60 +77,133 @@ public final List<ReportedDelivery> createAll(List<ReportedDelivery> deliveries)
}

public boolean validate(ReportedDelivery delivery) {
return
delivery.getQuantity() >= 0 &&
delivery.getMeasurementUnit() != null &&
delivery.getMaterial() != null &&
delivery.getPartner() != null &&
validateResponsibility(delivery) &&
validateTransitEvent(delivery) &&
((
delivery.getCustomerOrderNumber() != null &&
delivery.getCustomerOrderPositionNumber() != null
) || (
delivery.getCustomerOrderNumber() == null &&
delivery.getCustomerOrderPositionNumber() == null &&
delivery.getSupplierOrderNumber() == null
));
return validateWithDetails(delivery).isEmpty();
}

private boolean validateTransitEvent(ReportedDelivery delivery) {
public List<String> validateWithDetails(ReportedDelivery delivery) {
List<String> errors = new ArrayList<>();

if (delivery.getQuantity() < 0) {
errors.add("Quantity must be greater than or equal to 0.");
}
if (delivery.getMeasurementUnit() == null) {
errors.add("Missing measurement unit.");
}
if (delivery.getLastUpdatedOnDateTime() == null) {
errors.add("Missing lastUpdatedOnTime.");
} else if (delivery.getLastUpdatedOnDateTime().after(new Date())) {
errors.add("lastUpdatedOnDateTime cannot be in the future.");
}
if (delivery.getMaterial() == null) {
errors.add("Missing material.");
}
if (delivery.getPartner() == null) {
errors.add("Missing partner.");
}
errors.addAll(validateResponsibility(delivery));
errors.addAll(validateTransitEvent(delivery));
if (!((delivery.getCustomerOrderNumber() != null && delivery.getCustomerOrderPositionNumber() != null) ||
(delivery.getCustomerOrderNumber() == null && delivery.getCustomerOrderPositionNumber() == null && delivery.getSupplierOrderNumber() == null))) {
errors.add("If an order position reference is given, customer order number and customer order position number must be set.");
}

return errors;
}

private List<String> validateTransitEvent(ReportedDelivery delivery) {
List<String> errors = new ArrayList<>();
var now = new Date().getTime();
return
delivery.getDepartureType() != null &&
(delivery.getDepartureType() == EventTypeEnumeration.ESTIMATED_DEPARTURE || delivery.getDepartureType() == EventTypeEnumeration.ACTUAL_DEPARTURE) &&
delivery.getArrivalType() != null &&
(delivery.getArrivalType() == EventTypeEnumeration.ESTIMATED_ARRIVAL || delivery.getArrivalType() == EventTypeEnumeration.ACTUAL_ARRIVAL) &&
!(delivery.getDepartureType() == EventTypeEnumeration.ESTIMATED_DEPARTURE && delivery.getArrivalType() == EventTypeEnumeration.ACTUAL_ARRIVAL) &&
delivery.getDateOfDeparture().getTime() < delivery.getDateOfArrival().getTime() &&
(delivery.getArrivalType() != EventTypeEnumeration.ACTUAL_ARRIVAL || delivery.getDateOfArrival().getTime() < now) &&
(delivery.getDepartureType() != EventTypeEnumeration.ACTUAL_DEPARTURE || delivery.getDateOfDeparture().getTime() < now);

if (delivery.getDepartureType() == null) {
errors.add("Missing departure type.");
} else if (!(delivery.getDepartureType() == EventTypeEnumeration.ESTIMATED_DEPARTURE || delivery.getDepartureType() == EventTypeEnumeration.ACTUAL_DEPARTURE)) {
errors.add("Invalid departure type.");
}
if (delivery.getArrivalType() == null) {
errors.add("Missing arrival type.");
} else if (!(delivery.getArrivalType() == EventTypeEnumeration.ESTIMATED_ARRIVAL || delivery.getArrivalType() == EventTypeEnumeration.ACTUAL_ARRIVAL)) {
errors.add("Invalid arrival type.");
}
if (delivery.getDepartureType() == EventTypeEnumeration.ESTIMATED_DEPARTURE && delivery.getArrivalType() == EventTypeEnumeration.ACTUAL_ARRIVAL) {
errors.add("Estimated departure cannot have actual arrival.");
}
if (delivery.getDateOfDeparture() == null) {
errors.add("Missing date of departure.");
}
if (delivery.getDateOfArrival() == null) {
errors.add("Missing date of arrival.");
}
if (delivery.getDateOfArrival() != null && delivery.getDateOfDeparture() != null &&
delivery.getDateOfDeparture().getTime() >= delivery.getDateOfArrival().getTime()) {
errors.add("Date of departure must be before date of arrival.");
}
if (delivery.getDateOfArrival() != null &&
delivery.getArrivalType() == EventTypeEnumeration.ACTUAL_ARRIVAL && delivery.getDateOfArrival().getTime() >= now) {
errors.add("Actual arrival date must be in the past.");
}
if (delivery.getDateOfDeparture() != null &&
delivery.getDepartureType() == EventTypeEnumeration.ACTUAL_DEPARTURE && delivery.getDateOfDeparture().getTime() >= now) {
errors.add("Actual departure date must be in the past.");
}

return errors;
}

private boolean validateResponsibility(ReportedDelivery delivery) {
private List<String> validateResponsibility(ReportedDelivery delivery) {
List<String> errors = new ArrayList<>();
if (ownPartnerEntity == null) {
ownPartnerEntity = partnerService.getOwnPartnerEntity();
}
return delivery.getIncoterm() != null && switch (delivery.getIncoterm().getResponsibility()) {
case CUSTOMER ->
delivery.getMaterial().isProductFlag() &&
ownPartnerEntity.getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getOriginBpns())) &&
delivery.getPartner().getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getDestinationBpns()));
case SUPPLIER ->
delivery.getMaterial().isMaterialFlag() &&
delivery.getPartner().getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getOriginBpns())) &&
ownPartnerEntity.getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getDestinationBpns()));
case PARTIAL ->
(
delivery.getMaterial().isMaterialFlag() &&
ownPartnerEntity.getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getDestinationBpns())) &&
delivery.getPartner().getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getOriginBpns()))

) || (
delivery.getMaterial().isProductFlag() &&
delivery.getPartner().getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getDestinationBpns())) &&
ownPartnerEntity.getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getOriginBpns()))
);
};

if (delivery.getIncoterm() == null) {
errors.add("Missing Incoterm.");
} else {
switch (delivery.getIncoterm().getResponsibility()) {
case SUPPLIER:
if (!delivery.getMaterial().isProductFlag()) {
errors.add("Material must have product flag for supplier responsibility.");
}
if (delivery.getPartner().getSites().stream().noneMatch(site -> site.getBpns().equals(delivery.getOriginBpns()))) {
errors.add("Origin BPNA must match one of the partner entity's site' address BPNAs for supplier responsibility.");
}
if (ownPartnerEntity.getSites().stream().noneMatch(site -> site.getBpns().equals(delivery.getDestinationBpns()))) {
errors.add("Destination BPNA must match one of the partner entity's site' address BPNAs for supplier responsibility.");
}

break;
case CUSTOMER:
if (!delivery.getMaterial().isProductFlag()) {
errors.add("Material must have product flag for customer responsibility.");
}
if (ownPartnerEntity.getSites().stream().noneMatch(site -> site.getBpns().equals(delivery.getOriginBpns()))) {
errors.add("Site BPNS must match one of the own partner entity's site BPNS for customer responsibility.");
}
if (delivery.getPartner().getSites().stream().noneMatch(site -> site.getBpns().equals(delivery.getDestinationBpns()))) {
errors.add("Site BPNA must match one of the partner entity's site' address BPNAs for customer responsibility.");
}

break;
case PARTIAL:
if (delivery.getMaterial().isProductFlag()) {
if (delivery.getPartner().getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getDestinationBpns())) &&
ownPartnerEntity.getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getOriginBpns()))
) {
return new ArrayList<>();
}
}
if (delivery.getMaterial().isMaterialFlag()) {
if (ownPartnerEntity.getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getDestinationBpns())) &&
delivery.getPartner().getSites().stream().anyMatch(site -> site.getBpns().equals(delivery.getOriginBpns()))) {
return new ArrayList<>();
}
}
errors.add("Responsibility conditions for partial responsibility are not met.");
break;
default:
errors.add("Invalid incoterm responsibility.");
break;
}
}
return errors;
}
}
Loading
Loading