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

Days of supply #15

Merged
merged 11 commits into from
Jun 11, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@
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.delivery.domain.model.EventTypeEnumeration;
import org.eclipse.tractusx.puris.backend.delivery.domain.model.IncotermEnumeration;
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.service.OwnDeliveryService;
import org.eclipse.tractusx.puris.backend.delivery.logic.service.ReportedDeliveryService;
import org.eclipse.tractusx.puris.backend.demand.domain.model.DemandCategoryEnumeration;
import org.eclipse.tractusx.puris.backend.demand.domain.model.OwnDemand;
import org.eclipse.tractusx.puris.backend.demand.logic.services.OwnDemandService;
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;
Expand All @@ -48,8 +57,13 @@
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

@Component
@Slf4j
Expand Down Expand Up @@ -79,6 +93,13 @@ public class DataInjectionCommandLineRunner implements CommandLineRunner {
@Autowired
private VariablesService variablesService;

@Autowired
private OwnDemandService demandService;

@Autowired
private OwnDeliveryService ownDeliveryService;
@Autowired
private ReportedDeliveryService reportedDeliveryService;
@Autowired
private ErpAdapterRequestService erpAdapterRequestService;

Expand All @@ -93,6 +114,8 @@ public class DataInjectionCommandLineRunner implements CommandLineRunner {

private final String supplierSiteLaBpns = "BPNS2222222222SS";

private final String CHARACTERS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

public DataInjectionCommandLineRunner(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
Expand Down Expand Up @@ -226,6 +249,86 @@ private void setupCustomerRole() throws JsonProcessingException {
reportedMaterialItemStock = reportedMaterialItemStockService.create(reportedMaterialItemStock);
log.info("Created ReportedMaterialItemStock: \n" + reportedMaterialItemStock);

// #region Days of supply
Random random = new Random();
// double[] demands = {40, 60, 50, 50, 60, 50}; to test the example from the docs
// double[] deliveries = {0, 60, 100, 0, 0, 40}; to test the example from the docs
LocalDate date = LocalDate.now();
var siteBpns = mySelf.getSites().first().getBpns();

for (int i = 0; i < 28; i++) {
OwnDemand demand = OwnDemand.builder()
.material(semiconductorMaterial)
.partner(supplierPartner)
.quantity((random.nextInt(11) + 1) * 10)
.measurementUnit(ItemUnitEnumeration.UNIT_PIECE)
.day(Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant()))
.demandLocationBpns(siteBpns)
.supplierLocationBpns(null)
.demandCategoryCode(DemandCategoryEnumeration.DEMAND_DEFAULT)
.build();
demand = demandService.create(demand);

EventTypeCombination eventTypeCombination = generateRandomEventTypeCombination(random);
var departureDate = generateRandomDate(random);
LocalDate arrivalDate = LocalDate.now();
Date arrivalDateAsDate = new Date();

if (eventTypeCombination.arrivalType == EventTypeEnumeration.ACTUAL_ARRIVAL) {
arrivalDate = arrivalDate.minusDays(random.nextInt((4 - 1) + 1) + 1);

arrivalDateAsDate = Date.from(arrivalDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
} else {
arrivalDate = arrivalDate.plusDays(random.nextInt((14 - 1) + 1) + 1);

arrivalDateAsDate = Date.from(arrivalDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
}

OwnDelivery ownDelivery = OwnDelivery.builder()
.material(semiconductorMaterial)
.partner(supplierPartner)
.quantity(random.nextInt(11) * 10)
.measurementUnit(ItemUnitEnumeration.UNIT_PIECE)
.trackingNumber(generateRandomString(random, 12))
.incoterm(IncotermEnumeration.CFR)
.supplierOrderNumber("M-Nbr-4711")
.customerOrderNumber("C-Nbr-4711")
.customerOrderPositionNumber("PositionId-" + i)
.destinationBpna(null)
.destinationBpns(siteBpns)
.originBpna(null)
.originBpns(supplierPartner.getSites().first().getBpns())
.dateOfDeparture(departureDate)
.dateOfArrival(arrivalDateAsDate)
.departureType(eventTypeCombination.departureType)
.arrivalType(eventTypeCombination.arrivalType)
.build();
ownDeliveryService.create(ownDelivery);

ReportedDelivery reportedDelivery = ReportedDelivery.builder()
.material(semiconductorMaterial)
.partner(supplierPartner)
.quantity(random.nextInt(11) * 10)
.measurementUnit(ItemUnitEnumeration.UNIT_PIECE)
.trackingNumber(generateRandomString(random, 12))
.incoterm(IncotermEnumeration.CFR)
.supplierOrderNumber("M-Nbr-4711")
.customerOrderNumber("C-Nbr-4711")
.customerOrderPositionNumber("PositionId-" + i)
.destinationBpna(null)
.destinationBpns(siteBpns)
.originBpna(null)
.originBpns(supplierPartner.getSites().first().getBpns())
.dateOfDeparture(departureDate)
.dateOfArrival(arrivalDateAsDate)
.departureType(eventTypeCombination.departureType)
.arrivalType(eventTypeCombination.arrivalType)
.build();
reportedDeliveryService.create(reportedDelivery);

date = date.plusDays(1);
}
// #endregion
ProductItemStock productItemStock = ProductItemStock.builder()
.partner(supplierPartner)
.material(semiconductorMaterial)
Expand Down Expand Up @@ -491,4 +594,55 @@ private Material getNewCentralControlUnitMaterial() {
return material;
}

private static Date generateRandomDate(Random random) {
int daysOffset = random.nextInt((30 - 6) + 1) + 6;
LocalDate currentDate = LocalDate.now();
LocalDate randomLocalDate = currentDate.minusDays(daysOffset);
return Date.from(randomLocalDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
}

private static EventTypeCombination generateRandomEventTypeCombination(Random random) {
EventTypeEnumeration departureType;
EventTypeEnumeration arrivalType;

do {
departureType = getRandomDepartureType(random);
arrivalType = getRandomArrivalType(random);
} while (departureType == EventTypeEnumeration.ESTIMATED_DEPARTURE &&
arrivalType == EventTypeEnumeration.ACTUAL_ARRIVAL);

return new EventTypeCombination(departureType, arrivalType);
}

private static EventTypeEnumeration getRandomDepartureType(Random random) {
List<EventTypeEnumeration> departureTypes = Arrays.stream(EventTypeEnumeration.values())
.filter(e -> e == EventTypeEnumeration.ESTIMATED_DEPARTURE || e == EventTypeEnumeration.ACTUAL_DEPARTURE)
.collect(Collectors.toList());
return departureTypes.get(random.nextInt(departureTypes.size()));
}

private static EventTypeEnumeration getRandomArrivalType(Random random) {
List<EventTypeEnumeration> arrivalTypes = Arrays.stream(EventTypeEnumeration.values())
.filter(e -> e == EventTypeEnumeration.ESTIMATED_ARRIVAL || e == EventTypeEnumeration.ACTUAL_ARRIVAL)
.collect(Collectors.toList());
return arrivalTypes.get(random.nextInt(arrivalTypes.size()));
}

private String generateRandomString(Random random, int length) {
StringBuilder sb = new StringBuilder(length);
for (int i = 0; i < length; i++) {
sb.append(CHARACTERS.charAt(random.nextInt(CHARACTERS.length())));
}
return sb.toString();
}

public static class EventTypeCombination {
public EventTypeEnumeration departureType;
public EventTypeEnumeration arrivalType;

public EventTypeCombination(EventTypeEnumeration departureType, EventTypeEnumeration arrivalType) {
this.departureType = departureType;
this.arrivalType = arrivalType;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
"/planned-production/**",
"/material-demand/**",
"/delivery-information/**",
"/supply/**",
"/edc/**",
"/erp-adapter/**",
"/parttypeinformation/**"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ public List<DeliveryDto> getAllDeliveries(String ownMaterialNumber, Optional<Str
if (material == null) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Material does not exist.");
}
var reportedDeliveries = reportedDeliveryService.findAllByFilters(Optional.of(ownMaterialNumber), bpns, bpnl)
var reportedDeliveries = reportedDeliveryService.findAllByFilters(Optional.of(ownMaterialNumber), bpns, bpnl, Optional.empty(), Optional.empty())
.stream().map(this::convertToDto).collect(Collectors.toList());
var ownDeliveries = ownDeliveryService.findAllByFilters(Optional.of(ownMaterialNumber), bpns, bpnl)
var ownDeliveries = ownDeliveryService.findAllByFilters(Optional.of(ownMaterialNumber), bpns, bpnl, Optional.empty(), Optional.empty())
.stream().map(this::convertToDto).collect(Collectors.toList());
return List.of(reportedDeliveries, ownDeliveries).stream().flatMap(List::stream).toList();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@
import org.eclipse.tractusx.puris.backend.delivery.domain.model.OwnDelivery;
import org.springframework.data.jpa.repository.JpaRepository;

public interface DeliveryRepository extends JpaRepository<OwnDelivery, UUID> {
public interface OwnDeliveryRepository extends JpaRepository<OwnDelivery, UUID> {

}
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public DeliveryInformation handleDeliverySubmodelRequest(String bpnl, String mat
return null;
}

var currentDeliveries = ownDeliveryService.findAllByFilters(Optional.of(material.getOwnMaterialNumber()), Optional.empty(), Optional.of(partner.getBpnl()));
var currentDeliveries = ownDeliveryService.findAllByFilters(Optional.of(material.getOwnMaterialNumber()), Optional.empty(), Optional.of(partner.getBpnl()), Optional.empty(), Optional.empty());
return sammMapper.ownDeliveryToSamm(currentDeliveries, partner, material);
}

Expand All @@ -114,7 +114,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());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@

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;
Expand All @@ -31,22 +36,23 @@

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.eclipse.tractusx.puris.backend.stock.logic.dto.itemstocksamm.DirectionCharacteristic;
import org.springframework.stereotype.Service;

@Service
public class OwnDeliveryService {
public final DeliveryRepository repository;
private final OwnDeliveryRepository repository;

private final PartnerService partnerService;

protected final Function<OwnDelivery, Boolean> validator;

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;
Expand All @@ -66,24 +72,74 @@ public final List<OwnDelivery> findAllByOwnMaterialNumber(String ownMaterialNumb
.toList();
}

public final List<OwnDelivery> findAllByFilters(Optional<String> ownMaterialNumber, Optional<String> bpns, Optional<String> bpnl) {
public final List<OwnDelivery> findAllByFilters(
Optional<String> ownMaterialNumber,
Optional<String> bpns,
Optional<String> bpnl,
Optional<Date> day,
Optional<DirectionCharacteristic> direction) {
Stream<OwnDelivery> 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 (direction.isPresent()) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

The direction filter should be independent of the BPNS filter. For incoming you should filter all deliveries where the Destination is one of the user's sites for outgoing where it's not.

if (direction.get() == DirectionCharacteristic.INBOUND) {
stream = stream.filter(delivery -> delivery.getDestinationBpns().equals(bpns.get()));
} else {
stream = stream.filter(delivery -> delivery.getOriginBpns().equals(bpns.get()));
}
} else {
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();
});
}
return stream.toList();
}

public final OwnDelivery findById(UUID id) {
return repository.findById(id).orElse(null);
}

public final double getSumOfQuantities(List<OwnDelivery> deliveries) {
double sum = 0;
for (OwnDelivery delivery : deliveries) {
sum += delivery.getQuantity();
}
return sum;
}

public final List<Double> getQuantityForDays(String material, String partnerBpnl, String siteBpns, DirectionCharacteristic direction, int numberOfDays) {
List<Double> deliveryQtys = new ArrayList<>();
LocalDate localDate = LocalDate.now();

for (int i = 0; i < numberOfDays; i++) {
Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
List<OwnDelivery> deliveries = findAllByFilters(Optional.of(material), Optional.of(siteBpns), Optional.of(partnerBpnl), Optional.of(date), Optional.of(direction));
double deliveryQuantity = getSumOfQuantities(deliveries);
deliveryQtys.add(deliveryQuantity);

localDate = localDate.plusDays(1);
}
return deliveryQtys;
}

public final OwnDelivery create(OwnDelivery delivery) {
if (!validator.apply(delivery)) {
throw new IllegalArgumentException("Invalid delivery");
Expand Down Expand Up @@ -121,7 +177,7 @@ public boolean validate(OwnDelivery delivery) {
ownPartnerEntity = partnerService.getOwnPartnerEntity();
}
return
delivery.getQuantity() > 0 &&
delivery.getQuantity() >= 0 &&
delivery.getMeasurementUnit() != null &&
delivery.getMaterial() != null &&
delivery.getPartner() != null &&
Expand Down
Loading