orm entities and daos unified
This commit is contained in:
@@ -98,6 +98,15 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<compilerArgs>
|
||||
<arg>-parameters</arg>
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import lombok.AllArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
import pl.com.bottega.factory.delivery.planning.definition.DeliveryPlannerDefinitionDao;
|
||||
import pl.com.bottega.factory.delivery.planning.definition.DeliveryPlannerDefinitionEntity;
|
||||
import pl.com.bottega.factory.product.management.RefNoId;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@@ -17,7 +18,7 @@ public class DeliveryAutoPlannerRepository {
|
||||
|
||||
public DeliveryAutoPlanner get(String refNo) {
|
||||
return new DeliveryAutoPlanner(refNo,
|
||||
ofNullable(dao.findOne(refNo))
|
||||
ofNullable(dao.findByRefNo(refNo))
|
||||
.map(DeliveryPlannerDefinitionEntity::getDefinition)
|
||||
.map(x -> x.map(DeliveriesSuggestion::timesAndFractions))
|
||||
.orElse(Collections.emptyMap()));
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
package pl.com.bottega.factory.delivery.planning.definition;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
|
||||
import org.springframework.data.rest.core.annotation.RestResource;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
@RepositoryRestResource(
|
||||
path = "delivery/planning/definitions",
|
||||
collectionResourceRel = "definitions for auto delivery planning")
|
||||
public interface DeliveryPlannerDefinitionDao extends JpaRepository<DeliveryPlannerDefinitionEntity, String> {
|
||||
path = "delivery-definitions", collectionResourceRel = "delivery-definitions")
|
||||
public interface DeliveryPlannerDefinitionDao extends CrudRepository<DeliveryPlannerDefinitionEntity, Long> {
|
||||
@RestResource(path = "refNos", rel = "refNos")
|
||||
DeliveryPlannerDefinitionEntity findByRefNo(@Param("refNo") String refNo);
|
||||
}
|
||||
|
||||
@@ -5,21 +5,20 @@ import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import pl.com.bottega.tools.JsonConverter;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Convert;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Entity(name = "DeliveryPlannerDefinition")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode(of = "refNo")
|
||||
public class DeliveryPlannerDefinitionEntity {
|
||||
public class DeliveryPlannerDefinitionEntity implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
@Column
|
||||
private String refNo;
|
||||
|
||||
@Column
|
||||
@Convert(converter = DescriptionAsJson.class)
|
||||
private DeliveryPlannerDefinition definition;
|
||||
|
||||
@@ -10,11 +10,10 @@ import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
@RepositoryRestResource(
|
||||
path = "delivery/planning/forecasts",
|
||||
collectionResourceRel = "forecast of deliveries")
|
||||
@RepositoryRestResource(path = "delivery-forecasts", collectionResourceRel = "delivery-forecasts")
|
||||
public interface DeliveryForecastDao extends ProjectionDao<DeliveryForecastEntity, Long> {
|
||||
|
||||
@RestResource(exported = false)
|
||||
List<DeliveryForecastEntity> findByRefNoAndDateGreaterThanEqual(String refNo, Instant instant);
|
||||
|
||||
@RestResource(exported = false)
|
||||
|
||||
@@ -5,6 +5,7 @@ import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@@ -12,7 +13,8 @@ import java.time.LocalDateTime;
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode(of = "id")
|
||||
public class DeliveryForecastEntity {
|
||||
public class DeliveryForecastEntity implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@@ -24,7 +24,7 @@ public class DeliveryForecastProjection implements DemandEvents {
|
||||
|
||||
@Override
|
||||
public void emit(DemandedLevelsChanged event) {
|
||||
DeliveryAutoPlanner planner = planners.get(event.getRefNo());
|
||||
DeliveryAutoPlanner planner = planners.get(event.getRefNo().getRefNo());
|
||||
event.getResults().keySet()
|
||||
.forEach(daily -> forecastDao.deleteByRefNoAndDate(
|
||||
daily.getRefNo(),
|
||||
|
||||
@@ -5,6 +5,7 @@ import pl.com.bottega.tools.JsonConverter;
|
||||
import pl.com.bottega.tools.TechnicalId;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -12,17 +13,15 @@ import java.util.Optional;
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode(of = "id")
|
||||
public class DemandEntity {
|
||||
public class DemandEntity implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne
|
||||
private ProductDemandEntity product;
|
||||
@Column
|
||||
private LocalDate date;
|
||||
|
||||
@Column
|
||||
@Convert(converter = DemandAsJson.class)
|
||||
private DemandValue value;
|
||||
|
||||
@@ -4,7 +4,7 @@ import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
import pl.com.bottega.factory.delivery.planning.projection.DeliveryForecastProjection;
|
||||
import pl.com.bottega.factory.demand.forecasting.projection.CurrentDemandProjection;
|
||||
import pl.com.bottega.factory.shortages.prediction.ShortagePredictionMapping;
|
||||
import pl.com.bottega.factory.shortages.prediction.ShortagePredictionEventsMapping;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@@ -12,7 +12,7 @@ class DemandEventsMapping implements DemandEvents {
|
||||
|
||||
CurrentDemandProjection demands;
|
||||
DeliveryForecastProjection deliveries;
|
||||
ShortagePredictionMapping predictions;
|
||||
ShortagePredictionEventsMapping predictions;
|
||||
|
||||
@Override
|
||||
public void emit(DemandedLevelsChanged event) {
|
||||
|
||||
@@ -74,12 +74,9 @@ class DemandORMRepository {
|
||||
entity = demandDao.getOne(TechnicalId.get(updated.getId()));
|
||||
} else {
|
||||
entity = new DemandEntity(root, updated.getId().getDate());
|
||||
}
|
||||
entity.set(updated.getDocumented(), updated.getAdjustment());
|
||||
|
||||
if (!TechnicalId.isPersisted(updated.getId())) {
|
||||
demandDao.save(entity);
|
||||
}
|
||||
entity.set(updated.getDocumented(), updated.getAdjustment());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,13 @@ import pl.com.bottega.factory.product.management.RefNoId;
|
||||
import pl.com.bottega.tools.TechnicalId;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Entity(name = "ProductDemand")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode(of = "id")
|
||||
public class ProductDemandEntity {
|
||||
public class ProductDemandEntity implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
@@ -28,23 +29,21 @@ public class ProductDemandEntity {
|
||||
}
|
||||
|
||||
ProductDemandEntityId createId() {
|
||||
return new ProductDemandEntityId(refNo, id, version);
|
||||
return new ProductDemandEntityId(refNo, id);
|
||||
}
|
||||
|
||||
@Getter
|
||||
static class ProductDemandEntityId extends RefNoId implements TechnicalId {
|
||||
|
||||
Long id;
|
||||
Long version;
|
||||
|
||||
ProductDemandEntityId(String refNo) {
|
||||
super(refNo);
|
||||
}
|
||||
|
||||
ProductDemandEntityId(String refNo, long id, Long version) {
|
||||
ProductDemandEntityId(String refNo, long id) {
|
||||
super(refNo);
|
||||
this.id = id;
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,5 +13,4 @@ import java.util.List;
|
||||
public interface DemandDao extends JpaRepository<DemandEntity, Long> {
|
||||
|
||||
List<DemandEntity> findByProductRefNoAndDateGreaterThanEqual(String refNo, LocalDate now);
|
||||
|
||||
}
|
||||
|
||||
@@ -9,11 +9,10 @@ import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
@RepositoryRestResource(
|
||||
path = "demand/forecasts",
|
||||
collectionResourceRel = "forecast of customers demands")
|
||||
@RepositoryRestResource(path = "demand-forecasts", collectionResourceRel = "demand-forecasts")
|
||||
public interface CurrentDemandDao extends ProjectionDao<CurrentDemandEntity, Long> {
|
||||
|
||||
@RestResource(exported = false)
|
||||
List<CurrentDemandEntity> findByRefNoAndDateGreaterThanEqual(String refNo, LocalDate date);
|
||||
|
||||
@RestResource(exported = false)
|
||||
|
||||
@@ -6,13 +6,15 @@ import lombok.NoArgsConstructor;
|
||||
import pl.com.bottega.factory.demand.forecasting.Demand;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Entity(name = "CurrentDemand")
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode(of = "id")
|
||||
public class CurrentDemandEntity {
|
||||
public class CurrentDemandEntity implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@@ -5,18 +5,10 @@ import org.springframework.data.rest.core.annotation.RepositoryRestResource;
|
||||
import org.springframework.data.rest.core.annotation.RestResource;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
|
||||
@RepositoryRestResource(
|
||||
path = "product/management/descriptions",
|
||||
collectionResourceRel = "descriptions of products")
|
||||
public interface ProductDescriptionDao extends JpaRepository<ProductDescriptionEntity, String> {
|
||||
|
||||
@RestResource(exported = false)
|
||||
default Optional<ProductDescription> description(String refNo) {
|
||||
return Optional.ofNullable(findOne(refNo))
|
||||
.map(ProductDescriptionEntity::getDescription);
|
||||
}
|
||||
path = "product-descriptions", collectionResourceRel = "product-descriptions")
|
||||
public interface ProductDescriptionDao extends JpaRepository<ProductDescriptionEntity, Long> {
|
||||
@RestResource(path = "refNos", rel = "refNos")
|
||||
ProductDescriptionEntity findByRefNo(String refNo);
|
||||
}
|
||||
|
||||
@@ -5,21 +5,20 @@ import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import pl.com.bottega.tools.JsonConverter;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Convert;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Entity(name = "ProductDescription")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode(of = "refNo")
|
||||
public class ProductDescriptionEntity {
|
||||
public class ProductDescriptionEntity implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
@Column
|
||||
private String refNo;
|
||||
|
||||
@Column
|
||||
@Convert(converter = DescriptionAsJson.class)
|
||||
ProductDescription description;
|
||||
|
||||
@@ -8,9 +8,7 @@ import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
@RepositoryRestResource(
|
||||
path = "production/planning/outputs/daily",
|
||||
collectionResourceRel = "forecast of production daily outputs")
|
||||
@RepositoryRestResource(path = "production-outputs-daily", collectionResourceRel = "production-outputs-daily")
|
||||
public interface ProductionDailyOutputDao extends ProjectionDao<ProductionDailyOutputEntity, Long> {
|
||||
|
||||
List<ProductionDailyOutputEntity> findByRefNoAndDateGreaterThanEqual(String refNo, LocalDate date);
|
||||
|
||||
@@ -5,13 +5,14 @@ import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Entity(name = "ProductionDailyOutput")
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode(of = "id")
|
||||
public class ProductionDailyOutputEntity {
|
||||
@EqualsAndHashCode(of = "refNo")
|
||||
public class ProductionDailyOutputEntity implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
|
||||
@@ -8,9 +8,7 @@ import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
@RepositoryRestResource(
|
||||
path = "production/planning/outputs",
|
||||
collectionResourceRel = "forecast of production outputs")
|
||||
@RepositoryRestResource(path = "production-outputs", collectionResourceRel = "production-outputs")
|
||||
public interface ProductionOutputDao extends ProjectionDao<ProductionOutputEntity, Long> {
|
||||
|
||||
List<ProductionOutputEntity> findByRefNoAndStartGreaterThanEqual(String refNo, Instant instant);
|
||||
|
||||
@@ -5,14 +5,15 @@ import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity(name = "ProductionOutput")
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode(of = "id")
|
||||
public class ProductionOutputEntity {
|
||||
@EqualsAndHashCode(of = "refNo")
|
||||
public class ProductionOutputEntity implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
|
||||
@@ -7,10 +7,12 @@ import pl.com.bottega.factory.demand.forecasting.DemandEvents;
|
||||
import pl.com.bottega.factory.shortages.prediction.monitoring.ShortagePredictionProcess;
|
||||
import pl.com.bottega.factory.shortages.prediction.monitoring.ShortagePredictionProcessRepository;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
public class ShortagePredictionMapping implements DemandEvents {
|
||||
public class ShortagePredictionEventsMapping implements DemandEvents {
|
||||
|
||||
private ShortagePredictionProcessRepository repository;
|
||||
|
||||
@@ -4,6 +4,7 @@ import lombok.AllArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
import pl.com.bottega.factory.delivery.planning.projection.DeliveryForecastDao;
|
||||
import pl.com.bottega.factory.delivery.planning.projection.DeliveryForecastEntity;
|
||||
import pl.com.bottega.factory.product.management.RefNoId;
|
||||
import pl.com.bottega.factory.production.planning.projection.ProductionOutputDao;
|
||||
import pl.com.bottega.factory.shortages.prediction.calculation.ProductionForecast.Item;
|
||||
import pl.com.bottega.factory.warehouse.WarehouseService;
|
||||
@@ -28,13 +29,13 @@ class ForecastORMProvider implements Forecasts {
|
||||
private Clock clock;
|
||||
|
||||
@Override
|
||||
public Forecast get(String refNo, int daysAhead) {
|
||||
public Forecast get(RefNoId refNo, int daysAhead) {
|
||||
CurrentStock stock = stocks.forRefNo(refNo);
|
||||
Instant now = Instant.now(clock);
|
||||
LocalDateTime time = now.atZone(clock.getZone()).toLocalDateTime();
|
||||
|
||||
Map<LocalDateTime, Long> demands = this.demands
|
||||
.findByRefNoAndDateGreaterThanEqual(refNo, now).stream()
|
||||
.findByRefNoAndDateGreaterThanEqual(refNo.getRefNo(), now).stream()
|
||||
.collect(toMap(
|
||||
DeliveryForecastEntity::getTime,
|
||||
DeliveryForecastEntity::getLevel
|
||||
@@ -44,7 +45,7 @@ class ForecastORMProvider implements Forecasts {
|
||||
Demands demand = new Demands(demands);
|
||||
|
||||
ProductionOutputs outputs = new ProductionForecast(
|
||||
this.outputs.findByRefNoAndStartGreaterThanEqual(refNo, now).stream()
|
||||
this.outputs.findByRefNoAndStartGreaterThanEqual(refNo.getRefNo(), now).stream()
|
||||
.map(e -> new Item(
|
||||
e.getStart(),
|
||||
e.getDuration(),
|
||||
@@ -52,6 +53,6 @@ class ForecastORMProvider implements Forecasts {
|
||||
.collect(Collectors.toList())
|
||||
).outputsInTimes(time, demands.keySet());
|
||||
|
||||
return new Forecast(refNo, time, times, stock, outputs, demand);
|
||||
return new Forecast(refNo.getRefNo(), time, times, stock, outputs, demand);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,13 @@ package pl.com.bottega.factory.shortages.prediction.monitoring;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
import pl.com.bottega.factory.product.management.RefNoId;
|
||||
import pl.com.bottega.factory.shortages.prediction.Configuration;
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortages;
|
||||
import pl.com.bottega.factory.shortages.prediction.calculation.Forecasts;
|
||||
import pl.com.bottega.factory.shortages.prediction.notification.NotificationOfShortage;
|
||||
import pl.com.bottega.tools.TechnicalId;
|
||||
|
||||
import static java.util.Optional.ofNullable;
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
@@ -20,9 +21,12 @@ class ShortagePredictionProcessORMRepository implements ShortagePredictionProces
|
||||
private final NotificationOfShortage notifications;
|
||||
|
||||
@Override
|
||||
public ShortagePredictionProcess get(String refNo) {
|
||||
public ShortagePredictionProcess get(RefNoId refNo) {
|
||||
Optional<ShortagesEntity> entity = dao.findByRefNo(refNo.getRefNo());
|
||||
return new ShortagePredictionProcess(
|
||||
refNo, fetchData(refNo),
|
||||
entity.map(ShortagesEntity::createId)
|
||||
.orElseGet(() -> ShortagesEntity.createId(refNo)),
|
||||
entity.map(ShortagesEntity::getShortages).orElse(null),
|
||||
policy, forecasts, configuration, new EventsHandler()
|
||||
);
|
||||
}
|
||||
@@ -32,26 +36,29 @@ class ShortagePredictionProcessORMRepository implements ShortagePredictionProces
|
||||
// persisted after event
|
||||
}
|
||||
|
||||
private Shortages fetchData(String refNo) {
|
||||
return ofNullable(dao.findOne(refNo))
|
||||
.map(ShortagesEntity::getShortages).orElse(null);
|
||||
private void save(NewShortage event) {
|
||||
RefNoId refNo = event.getRefNo();
|
||||
ShortagesEntity entity = TechnicalId.findOrDefault(
|
||||
refNo, dao::findOne,
|
||||
() -> dao.save(new ShortagesEntity(refNo.getRefNo())));
|
||||
entity.setShortages(event.getShortages());
|
||||
notifications.emit(event);
|
||||
}
|
||||
|
||||
private void delete(ShortageSolved event) {
|
||||
dao.delete(TechnicalId.get(event.getRefNo()));
|
||||
notifications.emit(event);
|
||||
}
|
||||
|
||||
private class EventsHandler implements ShortageEvents {
|
||||
@Override
|
||||
public void emit(NewShortage event) {
|
||||
String refNo = event.getShortages().getRefNo();
|
||||
ShortagesEntity entity = ofNullable(dao.findOne(refNo))
|
||||
.orElseGet(() -> new ShortagesEntity(refNo));
|
||||
entity.setShortages(event.getShortages());
|
||||
dao.save(entity);
|
||||
notifications.emit(event);
|
||||
save(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emit(ShortageSolved event) {
|
||||
dao.delete(event.getRefNo());
|
||||
notifications.emit(event);
|
||||
delete(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
package pl.com.bottega.factory.shortages.prediction.monitoring;
|
||||
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
|
||||
import org.springframework.data.rest.core.annotation.RestResource;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import pl.com.bottega.tools.ProjectionDao;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
@RepositoryRestResource(
|
||||
path = "shortages/prediction/current",
|
||||
collectionResourceRel = "predicted shortages")
|
||||
public interface ShortagesDao extends ProjectionDao<ShortagesEntity, String> {
|
||||
@RepositoryRestResource(path = "shortages", collectionResourceRel = "shortages")
|
||||
public interface ShortagesDao extends ProjectionDao<ShortagesEntity, Long> {
|
||||
@RestResource(path = "refNos", rel = "refNos")
|
||||
Optional<ShortagesEntity> findByRefNo(@Param("refNo") String refNo);
|
||||
}
|
||||
|
||||
@@ -2,36 +2,63 @@ package pl.com.bottega.factory.shortages.prediction.monitoring;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import pl.com.bottega.factory.product.management.RefNoId;
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortages;
|
||||
import pl.com.bottega.tools.JsonConverter;
|
||||
import pl.com.bottega.tools.TechnicalId;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Convert;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Entity(name = "Shortage")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode(of = "refNo")
|
||||
class ShortagesEntity {
|
||||
public class ShortagesEntity implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
@Version
|
||||
private Long version;
|
||||
@Column
|
||||
private String refNo;
|
||||
|
||||
@Column
|
||||
@Column(length = 1024)
|
||||
@Convert(converter = ShortagesAsJson.class)
|
||||
Shortages shortages;
|
||||
private Shortages shortages;
|
||||
|
||||
ShortagesEntity(String refNo) {
|
||||
this.refNo = refNo;
|
||||
}
|
||||
|
||||
RefNoId createId() {
|
||||
return new ShortagesEntityId(refNo, id);
|
||||
}
|
||||
|
||||
static RefNoId createId(RefNoId id) {
|
||||
return id instanceof ShortagesEntityId ? id : new ShortagesEntityId(id.getRefNo());
|
||||
}
|
||||
|
||||
public static class ShortagesAsJson extends JsonConverter<Shortages> {
|
||||
public ShortagesAsJson() {
|
||||
super(Shortages.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
static class ShortagesEntityId extends RefNoId implements TechnicalId {
|
||||
|
||||
Long id;
|
||||
|
||||
ShortagesEntityId(String refNo) {
|
||||
super(refNo);
|
||||
}
|
||||
|
||||
ShortagesEntityId(String refNo, long id) {
|
||||
super(refNo);
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,10 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import pl.com.bottega.factory.product.management.RefNoId;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/stock/forecasts")
|
||||
//@Controller
|
||||
//@RequestMapping("/stock/forecasts")
|
||||
@AllArgsConstructor
|
||||
class StockForecastController {
|
||||
|
||||
@@ -18,6 +19,6 @@ class StockForecastController {
|
||||
@RequestMapping(value = "/{refNo}", method = RequestMethod.GET)
|
||||
@Transactional(readOnly = true)
|
||||
ResponseEntity<StockForecast> get(@PathVariable("refNo") String refNo) {
|
||||
return ResponseEntity.ok(query.get(refNo));
|
||||
return ResponseEntity.ok(query.get(new RefNoId(refNo)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import pl.com.bottega.factory.demand.forecasting.projection.CurrentDemandEntity;
|
||||
import pl.com.bottega.factory.product.management.ProductDescription;
|
||||
import pl.com.bottega.factory.product.management.ProductDescriptionDao;
|
||||
import pl.com.bottega.factory.product.management.ProductDescriptionEntity;
|
||||
import pl.com.bottega.factory.product.management.RefNoId;
|
||||
import pl.com.bottega.factory.production.planning.projection.ProductionDailyOutputDao;
|
||||
import pl.com.bottega.factory.production.planning.projection.ProductionDailyOutputEntity;
|
||||
import pl.com.bottega.factory.shortages.prediction.calculation.CurrentStock;
|
||||
@@ -32,26 +33,26 @@ class StockForecastQuery {
|
||||
private final ProductDescriptionDao descriptions;
|
||||
private final Clock clock;
|
||||
|
||||
StockForecast get(String refNo) {
|
||||
StockForecast get(RefNoId refNo) {
|
||||
CurrentStock stock = stocks.forRefNo(refNo);
|
||||
LocalDate today = LocalDate.now(clock);
|
||||
return build(refNo, today, Optional.ofNullable(descriptions.findOne(refNo))
|
||||
return build(refNo, today, Optional.ofNullable(descriptions.findByRefNo(refNo.getRefNo()))
|
||||
.map(ProductDescriptionEntity::getDescription).orElse(null), stock,
|
||||
this.demands
|
||||
.findByRefNoAndDateGreaterThanEqual(refNo, today).stream()
|
||||
.findByRefNoAndDateGreaterThanEqual(refNo.getRefNo(), today).stream()
|
||||
.collect(toMap(
|
||||
CurrentDemandEntity::getDate,
|
||||
CurrentDemandEntity::getLevel
|
||||
)),
|
||||
this.outputs
|
||||
.findByRefNoAndDateGreaterThanEqual(refNo, today).stream()
|
||||
.findByRefNoAndDateGreaterThanEqual(refNo.getRefNo(), today).stream()
|
||||
.collect(toMap(
|
||||
ProductionDailyOutputEntity::getDate,
|
||||
ProductionDailyOutputEntity::getOutput
|
||||
)));
|
||||
}
|
||||
|
||||
private StockForecast build(String refNo, LocalDate today,
|
||||
private StockForecast build(RefNoId refNo, LocalDate today,
|
||||
ProductDescription description, CurrentStock stock,
|
||||
Map<LocalDate, Long> demands,
|
||||
Map<LocalDate, Long> outputs) {
|
||||
@@ -69,7 +70,7 @@ class StockForecastQuery {
|
||||
));
|
||||
}
|
||||
return builder
|
||||
.refNo(refNo)
|
||||
.refNo(refNo.getRefNo())
|
||||
.description(description)
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package pl.com.bottega.factory.warehouse;
|
||||
|
||||
import pl.com.bottega.factory.product.management.RefNoId;
|
||||
import pl.com.bottega.factory.shortages.prediction.calculation.CurrentStock;
|
||||
|
||||
public interface WarehouseService {
|
||||
CurrentStock forRefNo(String refNo);
|
||||
CurrentStock forRefNo(RefNoId refNo);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package pl.com.bottega.tools;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public interface TechnicalId {
|
||||
|
||||
Long getId();
|
||||
@@ -9,10 +12,18 @@ public interface TechnicalId {
|
||||
}
|
||||
|
||||
static Long get(Object id) {
|
||||
return (id instanceof TechnicalId) ? ((TechnicalId) id).getId() : null;
|
||||
return isPersisted(id) ? ((TechnicalId) id).getId() : null;
|
||||
}
|
||||
|
||||
static boolean isPersisted(Object id) {
|
||||
return (id instanceof TechnicalId) && ((TechnicalId) id).isPersisted();
|
||||
}
|
||||
|
||||
static <T> T findOrDefault(Object id, Function<Long, T> ifPresent, Supplier<T> orElse) {
|
||||
if (isPersisted(id)) {
|
||||
return ifPresent.apply(get(id));
|
||||
} else {
|
||||
return orElse.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package pl.com.bottega.factory.shortages.prediction.monitoring
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.test.annotation.Commit
|
||||
import pl.com.bottega.factory.product.management.RefNoId
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortages
|
||||
import pl.com.bottega.factory.shortages.prediction.calculation.Forecasts
|
||||
import pl.com.bottega.factory.shortages.prediction.notification.NotificationOfShortage
|
||||
@@ -18,8 +19,8 @@ import static pl.com.bottega.factory.shortages.prediction.monitoring.NewShortage
|
||||
@Commit
|
||||
class ShortagePredictionProcessORMRepositoryTest extends Specification {
|
||||
|
||||
LocalDateTime now = LocalDateTime.now()
|
||||
String refNo = "3009000"
|
||||
def now = LocalDateTime.now()
|
||||
def refNo = "3009000"
|
||||
|
||||
@Autowired
|
||||
ShortagesDao dao
|
||||
@@ -93,15 +94,15 @@ class ShortagePredictionProcessORMRepositoryTest extends Specification {
|
||||
}
|
||||
|
||||
Shortages shortagesCurrentlyPersisted() {
|
||||
dao.findOne(refNo).shortages
|
||||
dao.findByRefNo(refNo).get().shortages
|
||||
}
|
||||
|
||||
void noShortagesPersisted() {
|
||||
assert dao.findOne(refNo) == null
|
||||
assert dao.findByRefNo(refNo) == Optional.empty()
|
||||
}
|
||||
|
||||
ShortagePredictionProcess fetchProcess() {
|
||||
repository.get(refNo)
|
||||
repository.get(new RefNoId(refNo))
|
||||
}
|
||||
|
||||
Shortages noShortages() {
|
||||
@@ -127,10 +128,10 @@ class ShortagePredictionProcessORMRepositoryTest extends Specification {
|
||||
}
|
||||
|
||||
void processEmitsNewShortage(ShortagePredictionProcess process, Shortages shortages) {
|
||||
process.events.emit(new NewShortage(DemandChanged, shortages))
|
||||
process.events.emit(new NewShortage(process.refNo, DemandChanged, shortages))
|
||||
}
|
||||
|
||||
void processEmitsShortageSolved(ShortagePredictionProcess process) {
|
||||
process.events.emit(new ShortageSolved(refNo))
|
||||
process.events.emit(new ShortageSolved(process.refNo))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ public interface DemandEvents {
|
||||
this.results = Collections.unmodifiableMap(results);
|
||||
}
|
||||
|
||||
public String getRefNo() {
|
||||
return id.getRefNo();
|
||||
public RefNoId getRefNo() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Value
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package pl.com.bottega.factory.shortages.prediction.calculation;
|
||||
|
||||
import pl.com.bottega.factory.product.management.RefNoId;
|
||||
|
||||
public interface Forecasts {
|
||||
Forecast get(String refNo, int daysAhead);
|
||||
Forecast get(RefNoId refNo, int daysAhead);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package pl.com.bottega.factory.shortages.prediction.monitoring;
|
||||
|
||||
import lombok.Value;
|
||||
import pl.com.bottega.factory.product.management.RefNoId;
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortages;
|
||||
|
||||
/**
|
||||
@@ -11,6 +12,7 @@ public class NewShortage {
|
||||
|
||||
public enum After {DemandChanged, PlanChanged, StockChanged, LockedParts}
|
||||
|
||||
RefNoId refNo;
|
||||
After trigger;
|
||||
Shortages shortages;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package pl.com.bottega.factory.shortages.prediction.monitoring;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import pl.com.bottega.factory.product.management.RefNoId;
|
||||
import pl.com.bottega.factory.shortages.prediction.Configuration;
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortages;
|
||||
import pl.com.bottega.factory.shortages.prediction.calculation.Forecast;
|
||||
@@ -15,7 +16,7 @@ import java.util.Optional;
|
||||
@AllArgsConstructor
|
||||
public class ShortagePredictionProcess {
|
||||
|
||||
private final String refNo;
|
||||
private final RefNoId refNo;
|
||||
private Shortages known;
|
||||
|
||||
private final ShortageDiffPolicy diffPolicy;
|
||||
@@ -48,7 +49,7 @@ public class ShortagePredictionProcess {
|
||||
boolean areDifferent = diffPolicy.areDifferent(this.known, newlyFound.orElse(null));
|
||||
if (areDifferent && newlyFound.isPresent()) {
|
||||
this.known = newlyFound.get();
|
||||
events.emit(new NewShortage(event, newlyFound.get()));
|
||||
events.emit(new NewShortage(refNo, event, known));
|
||||
} else if (known != null && !newlyFound.isPresent()) {
|
||||
this.known = null;
|
||||
events.emit(new ShortageSolved(refNo));
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package pl.com.bottega.factory.shortages.prediction.monitoring;
|
||||
|
||||
import pl.com.bottega.factory.product.management.RefNoId;
|
||||
|
||||
/**
|
||||
* Created by michal on 03.02.2017.
|
||||
*/
|
||||
public interface ShortagePredictionProcessRepository {
|
||||
ShortagePredictionProcess get(String refNo);
|
||||
ShortagePredictionProcess get(RefNoId refNo);
|
||||
|
||||
void save(ShortagePredictionProcess model);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package pl.com.bottega.factory.shortages.prediction.monitoring;
|
||||
|
||||
import lombok.Value;
|
||||
import pl.com.bottega.factory.product.management.RefNoId;
|
||||
|
||||
@Value
|
||||
public class ShortageSolved {
|
||||
String refNo;
|
||||
RefNoId refNo;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package pl.com.bottega.factory.shortages.prediction.calculation
|
||||
|
||||
import pl.com.bottega.factory.product.management.RefNoId
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortages
|
||||
|
||||
import java.time.Duration
|
||||
@@ -13,7 +14,7 @@ trait ShortagesCalculationAssemblerTrait {
|
||||
|
||||
Forecasts forecastProvider(CurrentStock stock, Demands demands, ProductionOutputs outputs) {
|
||||
def forecast = forecast(stock, demands, outputs)
|
||||
return { String refNo, int daysAhead -> forecast } as Forecasts
|
||||
return { RefNoId refNo, int daysAhead -> forecast } as Forecasts
|
||||
}
|
||||
|
||||
Forecast forecast(CurrentStock stock, Demands demands, ProductionOutputs outputs) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package pl.com.bottega.factory.shortages.prediction.monitoring
|
||||
|
||||
import pl.com.bottega.factory.product.management.RefNoId
|
||||
import pl.com.bottega.factory.shortages.prediction.Configuration
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortages
|
||||
import pl.com.bottega.factory.shortages.prediction.calculation.Forecasts
|
||||
@@ -8,11 +9,11 @@ import spock.lang.Specification
|
||||
|
||||
import java.time.LocalDateTime
|
||||
|
||||
import static pl.com.bottega.factory.shortages.prediction.monitoring.NewShortage.After;
|
||||
import static pl.com.bottega.factory.shortages.prediction.monitoring.NewShortage.After
|
||||
|
||||
class ShortagePredictionProcessSpec extends Specification {
|
||||
|
||||
def refNo = "3009000"
|
||||
def refNo = new RefNoId("3009000")
|
||||
def now = LocalDateTime.now()
|
||||
def forecastAssembler = new ShortagesCalculationAssembler(refNo: refNo, now: now)
|
||||
def events = Mock(ShortageEvents)
|
||||
@@ -170,7 +171,7 @@ class ShortagePredictionProcessSpec extends Specification {
|
||||
}
|
||||
|
||||
NewShortage newShortage(After after, Map<LocalDateTime, Long> missing) {
|
||||
new NewShortage(after, forecastAssembler.shortage(missing).get())
|
||||
new NewShortage(refNo, after, forecastAssembler.shortage(missing).get())
|
||||
}
|
||||
|
||||
ShortageSolved shortageSolved() {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package pl.com.bottega.factory.shortages.prediction.notification
|
||||
|
||||
import pl.com.bottega.factory.product.management.RefNoId
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortages
|
||||
import pl.com.bottega.factory.shortages.prediction.monitoring.NewShortage
|
||||
import pl.com.bottega.factory.shortages.prediction.monitoring.ShortageSolved
|
||||
@@ -107,7 +108,7 @@ class NotificationOfShortageSpec extends Specification {
|
||||
def notificator = notificator()
|
||||
|
||||
when:
|
||||
notificator.emit(new ShortageSolved(refNo))
|
||||
notificator.emit(new ShortageSolved(new RefNoId(refNo)))
|
||||
|
||||
then:
|
||||
0 * tasks.increasePriorityFor(_)
|
||||
@@ -122,7 +123,7 @@ class NotificationOfShortageSpec extends Specification {
|
||||
}
|
||||
|
||||
NewShortage newShortage(After after, Shortages shortages) {
|
||||
new NewShortage(after, shortages)
|
||||
new NewShortage(new RefNoId(refNo), after, shortages)
|
||||
}
|
||||
|
||||
Shortages withShortage(
|
||||
|
||||
Reference in New Issue
Block a user