modular monolith, context maps left in app-monolith

This commit is contained in:
Michał Michaluk
2017-12-16 19:49:41 +01:00
parent 84b3f63c00
commit a3682be9b8
82 changed files with 698 additions and 344 deletions

54
adapter-commons/pom.xml Normal file
View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>pl.com.bottega</groupId>
<artifactId>adapter-commons</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.8.5</version>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -2,11 +2,9 @@ package pl.com.bottega.tools;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.stereotype.Repository;
import java.io.Serializable;
@Repository
public interface CommandRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {
@Override

View File

@@ -2,11 +2,9 @@ package pl.com.bottega.tools;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.stereotype.Repository;
import java.io.Serializable;
@Repository
public interface ProjectionRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {
@Override

View File

@@ -17,19 +17,37 @@
<dependencies>
<dependency>
<groupId>pl.com.bottega</groupId>
<artifactId>shared-kernel-model</artifactId>
<artifactId>demand-forecasting-adapters</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>pl.com.bottega</groupId>
<artifactId>demand-forecasting-model</artifactId>
<artifactId>shortages-prediction-adapters</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>pl.com.bottega</groupId>
<artifactId>shortages-prediction-model</artifactId>
<artifactId>product-management-adapters</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>pl.com.bottega</groupId>
<artifactId>production-planning-adapters</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>pl.com.bottega</groupId>
<artifactId>adapter-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>pl.com.bottega</groupId>
<artifactId>adapter-commons</artifactId>
<version>1.0-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
@@ -53,11 +71,6 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-rest-hal-browser</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.8.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>

View File

@@ -1,7 +1,9 @@
package pl.com.bottega.factory.delivery.planning.definition;
import lombok.AllArgsConstructor;
import org.springframework.data.rest.core.annotation.*;
import org.springframework.data.rest.core.annotation.HandleAfterCreate;
import org.springframework.data.rest.core.annotation.HandleAfterSave;
import org.springframework.data.rest.core.annotation.RepositoryEventHandler;
import org.springframework.stereotype.Component;
import pl.com.bottega.factory.delivery.planning.projection.DeliveryForecastProjection;

View File

@@ -1,76 +0,0 @@
package pl.com.bottega.factory.demand.forecasting;
import lombok.*;
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;
@Entity(name = "Demand")
@Data
@NoArgsConstructor
@EqualsAndHashCode(of = "id")
@ToString(exclude = "product")
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;
DemandEntity(ProductDemandEntity product, LocalDate date) {
this.product = product;
this.date = date;
}
DemandEntityId createId() {
return new DemandEntityId(product.getRefNo(), date, id);
}
void set(Demand demand, Adjustment adjustment) {
value = new DemandValue(demand, adjustment);
}
DemandValue get() {
return Optional.ofNullable(value)
.orElse(DemandValue.NO_VAL);
}
@Value
static class DemandValue {
public static final DemandValue NO_VAL = new DemandValue(null, null);
Demand documented;
Adjustment adjustment;
}
public static class DemandAsJson extends JsonConverter<DemandValue> {
public DemandAsJson() {
super(DemandValue.class);
}
}
@Getter
static class DemandEntityId extends DailyId implements TechnicalId {
Long id;
DemandEntityId(String refNo, LocalDate date) {
super(refNo, date);
}
DemandEntityId(String refNo, LocalDate date, Long id) {
super(refNo, date);
this.id = id;
}
}
}

View File

@@ -7,7 +7,7 @@ import pl.com.bottega.factory.delivery.planning.projection.DeliveryForecastProje
import pl.com.bottega.factory.demand.forecasting.command.DemandReviewDao;
import pl.com.bottega.factory.demand.forecasting.command.DemandReviewEntity;
import pl.com.bottega.factory.demand.forecasting.projection.CurrentDemandProjection;
import pl.com.bottega.factory.shortages.prediction.ShortagePredictionEventsMapping;
import pl.com.bottega.factory.shortages.prediction.monitoring.ShortagePredictionService;
import java.time.Clock;
import java.time.Instant;
@@ -18,23 +18,24 @@ import java.util.stream.Collectors;
@AllArgsConstructor
class DemandEventsMapping implements DemandEvents {
private final CurrentDemandProjection demands;
private final DeliveryForecastProjection deliveries;
private final ShortagePredictionEventsMapping predictions;
private final DemandReviewDao reviews;
private final CurrentDemandProjection demandProjection;
private final DeliveryForecastProjection deliveryProjection;
private final ShortagePredictionService shortagePrediction;
private final DemandReviewDao demandReviews;
private final Clock clock;
@Override
public void emit(DemandedLevelsChanged event) {
demands.persistCurrentDemands(event);
deliveries.persistDeliveryForecasts(event);
predictions.predictShortages(event);
demandProjection.persistCurrentDemands(event);
deliveryProjection.persistDeliveryForecasts(event);
shortagePrediction.predictShortages(event);
}
@Override
public void emit(ReviewRequested event) {
reviews.save(event.getReviews().stream()
.map(review -> new DemandReviewEntity(Instant.now(clock), review))
Instant timestamp = Instant.now(clock);
demandReviews.save(event.getReviews().stream()
.map(r -> new DemandReviewEntity(timestamp, r))
.collect(Collectors.toList())
);
}

View File

@@ -2,17 +2,23 @@ package pl.com.bottega.factory.product.management;
import lombok.AllArgsConstructor;
import org.springframework.data.rest.core.annotation.HandleAfterCreate;
import org.springframework.data.rest.core.annotation.HandleAfterSave;
import org.springframework.data.rest.core.annotation.RepositoryEventHandler;
import org.springframework.stereotype.Component;
import pl.com.bottega.factory.demand.forecasting.DemandService;
import pl.com.bottega.factory.stock.forecast.ressource.StockForecastDao;
import pl.com.bottega.factory.stock.forecast.ressource.StockForecastEntity;
@Component
@AllArgsConstructor
@RepositoryEventHandler
public class ProductDescriptionEventsMapping {
@HandleAfterSave
private final DemandService demandService;
private final StockForecastDao stockForecasts;
@HandleAfterCreate
public void handle(ProductDescriptionEntity entity) {
demandService.init(entity.getRefNo());
stockForecasts.save(new StockForecastEntity(entity.getRefNo()));
}
}

View File

@@ -10,8 +10,8 @@ import pl.com.bottega.factory.shortages.prediction.calculation.ProductionForecas
import pl.com.bottega.factory.warehouse.WarehouseService;
import java.time.Clock;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
@@ -21,7 +21,7 @@ import static java.util.stream.Collectors.toMap;
@Component
@AllArgsConstructor
class ForecastORMProvider implements Forecasts {
class ForecastORMRepository implements Forecasts {
private final WarehouseService stocks;
private final DeliveryForecastDao deliveries;
@@ -31,21 +31,21 @@ class ForecastORMProvider implements Forecasts {
@Override
public Forecast get(RefNoId refNo, int daysAhead) {
Stock stock = stocks.forRefNo(refNo);
Instant now = Instant.now(clock);
LocalDateTime time = now.atZone(clock.getZone()).toLocalDateTime();
LocalDateTime time = LocalDateTime.now(clock);
LocalDateTime max = time.plusDays(daysAhead).truncatedTo(ChronoUnit.DAYS);
Map<LocalDateTime, Long> deliveries = this.deliveries
.findByRefNoAndTimeGreaterThanEqual(refNo.getRefNo(), time).stream()
.findByRefNoAndTimeBetween(refNo.getRefNo(), time, max).stream()
.collect(toMap(
DeliveryForecastEntity::getTime,
DeliveryForecastEntity::getLevel
));
SortedSet<LocalDateTime> deliveryTimes = new TreeSet<>(deliveries.keySet());
Deliveries demand = new Deliveries(deliveries);
DeliveriesForecast demand = new DeliveriesForecast(deliveries);
ProductionOutputs outputs = new ProductionForecast(
this.outputs.findByRefNoAndStartGreaterThanEqual(refNo.getRefNo(), time).stream()
this.outputs.findByRefNoAndEndGreaterThanAndStartLessThan(refNo.getRefNo(), time, max).stream()
.map(e -> new Item(
e.getStart(),
e.getDuration(),

View File

@@ -0,0 +1,24 @@
package pl.com.bottega.factory.shortages.prediction.monitoring;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import pl.com.bottega.factory.shortages.prediction.notification.NotificationOfShortage;
@Lazy
@Component
@AllArgsConstructor
class ShortageEventsMapping implements ShortageEvents {
private final NotificationOfShortage notification;
@Override
public void emit(NewShortage event) {
notification.notifyAbout(event);
}
@Override
public void emit(ShortageSolved event) {
}
}

View File

@@ -11,7 +11,6 @@ import java.util.List;
@Builder
public class StockForecast {
String refNo;
@Singular
List<DailyForecast> forecasts;

View File

@@ -53,8 +53,7 @@ public class StockForecastQuery {
Map<LocalDate, Long> outputs) {
LocalDate stopAtDay = today.plusDays(15);
long level = stock.getLevel();
StockForecastBuilder builder = StockForecast.builder()
.refNo(refNo.getRefNo());
StockForecastBuilder builder = StockForecast.builder();
for (LocalDate date = today; date.isBefore(stopAtDay); date = date.plusDays(1)) {
long withLocked = level + stock.getLocked();
long demand = demands.getOrDefault(date, 0L);

View File

@@ -1,36 +1,39 @@
package pl.com.bottega.factory.stock.forecast.ressource;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.data.rest.core.config.Projection;
import pl.com.bottega.factory.product.management.ProductDescriptionEntity;
import pl.com.bottega.factory.stock.forecast.StockForecast;
import javax.persistence.*;
import java.io.Serializable;
@Entity(name = "StockForecast")
@Data
@Getter
@NoArgsConstructor
@EqualsAndHashCode(of = "id")
@ToString(exclude = "product")
@ToString
public class StockForecastEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne
private ProductDescriptionEntity product;
@Column
private String refNo;
public StockForecastEntity(String refNo) {
this.refNo = refNo;
}
public StockForecast getStockForecast() {
return StaticAccess.calculateQuery(product.getRefNo());
return StaticAccess.calculateQuery(refNo);
}
@Projection(types = {StockForecastEntity.class})
interface CollectionItem {
ProductDescriptionEntity getProduct();
String getRefNo();
}
}

View File

@@ -2,15 +2,15 @@
curl http://localhost:8080
curl -X POST -H "Content-Type: application/json" \
-d @app-monolith/src/test/resources/pl.com.bottega.factory.product.management/product-descriptions.json \
-d @app-monolith/src/test/resources/examples/product-descriptions.json \
http://localhost:8080/product-descriptions
curl -X POST -H "Content-Type: application/json" \
-d @app-monolith/src/test/resources/pl.com.bottega.factory.delivery.planning/delivery-definitions.json \
-d @app-monolith/src/test/resources/examples/delivery-definitions.json \
http://localhost:8080/delivery-definitions
curl -X POST -H "Content-Type: application/json" \
-d @app-monolith/src/test/resources/pl.com.bottega.factory.demand.forecasting.command/demand-adjustments.json \
-d @app-monolith/src/test/resources/examples/demand-adjustments.json \
http://localhost:8080/demand-adjustments
curl http://localhost:8080/demand-forecasts

View File

@@ -4,19 +4,26 @@
"adjustment": {
"refNo": "3009000",
"adjustments": {
"2017-12-15": {
"2017-12-17": {
"demand": {
"level": 1000,
"level": 2000,
"schema": "AtDayStart"
},
"strong": true
},
"2017-12-16": {
"2017-12-22": {
"demand": {
"level": 1000,
"schema": "AtDayStart"
},
"strong": false
},
"2017-12-23": {
"demand": {
"level": 300,
"schema": "AtDayStart"
},
"strong": false
}
}
}

View File

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>pl.com.bottega</groupId>
<artifactId>demand-forecasting-adapters</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>pl.com.bottega</groupId>
<artifactId>demand-forecasting-model</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>pl.com.bottega</groupId>
<artifactId>adapter-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.1.4</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.1-groovy-2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-spring</artifactId>
<version>1.1-groovy-2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.7.9</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,7 +1,7 @@
package pl.com.bottega.factory.delivery.planning.definition;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import pl.com.bottega.tools.JsonConverter;
@@ -9,7 +9,7 @@ import javax.persistence.*;
import java.io.Serializable;
@Entity(name = "DeliveryPlannerDefinition")
@Data
@Getter
@NoArgsConstructor
@EqualsAndHashCode(of = "refNo")
public class DeliveryPlannerDefinitionEntity implements Serializable {

View File

@@ -16,7 +16,7 @@ import java.util.List;
public interface DeliveryForecastDao extends ProjectionRepository<DeliveryForecastEntity, Long> {
@RestResource(path = "refNos", rel = "refNos")
List<DeliveryForecastEntity> findByRefNoAndTimeGreaterThanEqual(String refNo, LocalDateTime from);
List<DeliveryForecastEntity> findByRefNoAndTimeBetween(String refNo, LocalDateTime from, LocalDateTime to);
@RestResource(exported = false)
void deleteByRefNoAndDate(String refNo, LocalDate date);

View File

@@ -3,9 +3,11 @@ package pl.com.bottega.factory.demand.forecasting;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
import pl.com.bottega.factory.demand.forecasting.DailyDemand.DemandUpdated;
import pl.com.bottega.factory.demand.forecasting.DemandEntity.DemandEntityId;
import pl.com.bottega.factory.demand.forecasting.persistence.DemandDao;
import pl.com.bottega.factory.demand.forecasting.persistence.DemandEntity;
import pl.com.bottega.factory.demand.forecasting.persistence.DemandEntity.DemandEntityId;
import pl.com.bottega.factory.demand.forecasting.persistence.ProductDemandDao;
import pl.com.bottega.factory.demand.forecasting.persistence.ProductDemandEntity;
import pl.com.bottega.factory.product.management.RefNoId;
import pl.com.bottega.tools.TechnicalId;
@@ -24,7 +26,7 @@ import static java.util.stream.Collectors.toMap;
class DemandORMRepository {
private final Clock clock;
private final DemandEventsMapping events;
private final DemandEvents events;
private final ReviewPolicy reviewPolicy = ReviewPolicy.BASIC;
private final EntityManager em;
private final ProductDemandDao rootDao;
@@ -55,8 +57,8 @@ class DemandORMRepository {
entity.createId(),
unitOfWork,
reviewPolicy,
entity.get().getDocumented(),
entity.get().getAdjustment()))
entity.getValue().getDocumented(),
entity.getValue().getAdjustment()))
.orElseGet(() -> new DailyDemand(
new DemandEntityId(refNo, date),
unitOfWork,
@@ -76,13 +78,22 @@ class DemandORMRepository {
if (TechnicalId.isPersisted(updated.getId())) {
entity = demandDao.getOne(TechnicalId.get(updated.getId()));
} else {
entity = new DemandEntity(root, updated.getId().getDate());
entity = new DemandEntity(
updated.getId().getRefNo(),
updated.getId().getDate()
);
demandDao.save(entity);
}
entity.set(
entity.setValue(new DemandValue(
updated.getDocumented().nullIfNone(),
updated.getAdjustment()
);
));
}
}
void initDemandsFor(String refNo) {
if (rootDao.findByRefNo(refNo) == null) {
rootDao.save(new ProductDemandEntity(refNo));
}
}
}

View File

@@ -13,6 +13,10 @@ public class DemandService {
private final DemandORMRepository repository;
public void init(String refNo) {
repository.initDemandsFor(refNo);
}
public void process(Document document) {
ProductDemand model = repository.get(document.getRefNo());
model.process(document);

View File

@@ -0,0 +1,9 @@
package pl.com.bottega.factory.demand.forecasting;
import lombok.Value;
@Value
public class DemandValue {
Demand documented;
Adjustment adjustment;
}

View File

@@ -4,8 +4,8 @@ import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import pl.com.bottega.factory.demand.forecasting.ReviewRequested.ReviewNeeded;
import pl.com.bottega.factory.demand.forecasting.ReviewDecision;
import pl.com.bottega.factory.demand.forecasting.ReviewRequested.ReviewNeeded;
import pl.com.bottega.tools.JsonConverter;
import javax.persistence.*;

View File

@@ -3,7 +3,6 @@ package pl.com.bottega.factory.demand.forecasting.persistence;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.stereotype.Repository;
import pl.com.bottega.factory.demand.forecasting.DemandEntity;
import java.time.LocalDate;
import java.util.List;

View File

@@ -0,0 +1,62 @@
package pl.com.bottega.factory.demand.forecasting.persistence;
import lombok.*;
import pl.com.bottega.factory.demand.forecasting.DailyId;
import pl.com.bottega.factory.demand.forecasting.DemandValue;
import pl.com.bottega.tools.JsonConverter;
import pl.com.bottega.tools.TechnicalId;
import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDate;
@Entity(name = "Demand")
@Getter
@NoArgsConstructor
@EqualsAndHashCode(of = "id")
@ToString
public class DemandEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column
String refNo;
@Column
private LocalDate date;
@Column
@Convert(converter = DemandAsJson.class)
@Setter
private DemandValue value;
public DemandEntity(String refNo, LocalDate date) {
this.refNo = refNo;
this.date = date;
this.value = new DemandValue(null, null);
}
public DemandEntityId createId() {
return new DemandEntityId(refNo, date, id);
}
public static class DemandAsJson extends JsonConverter<DemandValue> {
public DemandAsJson() {
super(DemandValue.class);
}
}
@Getter
public static class DemandEntityId extends DailyId implements TechnicalId {
private Long id;
public DemandEntityId(String refNo, LocalDate date) {
super(refNo, date);
}
DemandEntityId(String refNo, LocalDate date, Long id) {
super(refNo, date);
this.id = id;
}
}
}

View File

@@ -3,7 +3,6 @@ package pl.com.bottega.factory.demand.forecasting.persistence;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.stereotype.Repository;
import pl.com.bottega.factory.demand.forecasting.ProductDemandEntity;
@Repository
@RestResource(exported = false)

View File

@@ -1,6 +1,5 @@
package pl.com.bottega.factory.demand.forecasting;
package pl.com.bottega.factory.demand.forecasting.persistence;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
@@ -11,7 +10,6 @@ import javax.persistence.*;
import java.io.Serializable;
@Entity(name = "ProductDemand")
@Data
@NoArgsConstructor
@EqualsAndHashCode(of = "id")
public class ProductDemandEntity implements Serializable {
@@ -22,13 +20,13 @@ public class ProductDemandEntity implements Serializable {
@Version
private Long version;
@Column
private String refNo;
String refNo;
public ProductDemandEntity(String refNo) {
this.refNo = refNo;
}
ProductDemandEntityId createId() {
public ProductDemandEntityId createId() {
return new ProductDemandEntityId(refNo, id);
}

View File

@@ -25,6 +25,7 @@ public class CurrentDemandEntity implements Serializable {
@Column
private long level;
@Column
@Enumerated(EnumType.STRING)
private Demand.Schema schema;
CurrentDemandEntity(String refNo, LocalDate date, long level, Demand.Schema schema) {

View File

@@ -4,7 +4,9 @@ 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.demand.forecasting.persistence.DemandDao
import pl.com.bottega.factory.demand.forecasting.persistence.DemandEntity
import pl.com.bottega.factory.demand.forecasting.persistence.ProductDemandDao
import pl.com.bottega.factory.demand.forecasting.persistence.ProductDemandEntity
import spock.lang.Specification
import javax.persistence.EntityManager
@@ -20,7 +22,7 @@ import java.time.ZoneId
class DemandORMRepositoryTest extends Specification {
def clock = Clock.fixed(Instant.now(), ZoneId.systemDefault())
def events = Mock(DemandEventsMapping)
def events = Mock(DemandEvents)
@Autowired
EntityManager em
@Autowired
@@ -89,7 +91,7 @@ class DemandORMRepositoryTest extends Specification {
def root = rootDao.save(new ProductDemandEntity(refNo))
demands.each { date, level ->
def demand = new DemandEntity(root, date)
demand.set(Demand.of(level), null)
demand.setValue(new DemandValue(Demand.of(level), null))
demandDao.save(demand)
}
}

View File

@@ -9,6 +9,26 @@
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>pl.com.bottega</groupId>
<artifactId>shared-kernel-model</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.1-groovy-2.4</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
@@ -46,48 +66,4 @@
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>pl.com.bottega</groupId>
<artifactId>shared-kernel-model</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.8.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-java</artifactId>
<version>1.2.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-core</artifactId>
<version>1.2.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.1-groovy-2.4</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -15,6 +15,7 @@ class DailyDemand {
private final Events events;
private final ReviewPolicy policy;
interface Events {
void emit(LevelChanged event);

View File

@@ -4,5 +4,4 @@ public interface DemandEvents {
void emit(DemandedLevelsChanged event);
void emit(ReviewRequested event);
}

View File

@@ -11,10 +11,14 @@
<modules>
<module>app-monolith</module>
<module>adapter-commons</module>
<module>shared-kernel-model</module>
<module>demand-forecasting-model</module>
<module>demand-forecasting-adapters</module>
<module>shortages-prediction-model</module>
<!--<module>playground-model</module>-->
<module>shortages-prediction-adapters</module>
<module>product-management-adapters</module>
<module>production-planning-adapters</module>
</modules>
</project>

View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>pl.com.bottega</groupId>
<artifactId>product-management-adapters</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>pl.com.bottega</groupId>
<artifactId>adapter-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.1.4</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.1-groovy-2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-spring</artifactId>
<version>1.1-groovy-2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.7.9</version>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,7 +1,7 @@
package pl.com.bottega.factory.product.management;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import pl.com.bottega.tools.JsonConverter;
@@ -9,7 +9,7 @@ import javax.persistence.*;
import java.io.Serializable;
@Entity(name = "ProductDescription")
@Data
@Getter
@NoArgsConstructor
@EqualsAndHashCode(of = "refNo")
public class ProductDescriptionEntity implements Serializable {

View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>pl.com.bottega</groupId>
<artifactId>production-planning-adapters</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>pl.com.bottega</groupId>
<artifactId>adapter-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.1.4</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.1-groovy-2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-spring</artifactId>
<version>1.1-groovy-2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.7.9</version>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -14,5 +14,5 @@ import java.util.List;
itemResourceRel = "production-output")
public interface ProductionOutputDao extends ProjectionRepository<ProductionOutputEntity, Long> {
@RestResource(path = "refNos", rel = "refNos")
List<ProductionOutputEntity> findByRefNoAndStartGreaterThanEqual(String refNo, LocalDateTime from);
List<ProductionOutputEntity> findByRefNoAndEndGreaterThanAndStartLessThan(String refNo, LocalDateTime from, LocalDateTime to);
}

View File

@@ -25,6 +25,8 @@ public class ProductionOutputEntity implements Serializable {
@Column
private Duration duration;
@Column
private LocalDateTime end;
@Column
private int partsPerMinute;
@Column
private long total;
@@ -36,6 +38,7 @@ public class ProductionOutputEntity implements Serializable {
this.refNo = refNo;
this.start = start;
this.duration = duration;
this.end = start.plus(duration);
this.partsPerMinute = partsPerMinute;
this.total = total;
}

View File

@@ -9,6 +9,21 @@
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.1-groovy-2.4</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
@@ -47,36 +62,4 @@
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.8.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-java</artifactId>
<version>1.2.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-core</artifactId>
<version>1.2.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.1-groovy-2.4</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -21,7 +21,7 @@ public class Demand {
return new Demand(level, schema);
}
public static Demand nothingDemanded() {
static Demand nothingDemanded() {
return NONE;
}

View File

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>pl.com.bottega</groupId>
<artifactId>shortages-prediction-adapters</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>pl.com.bottega</groupId>
<artifactId>shortages-prediction-model</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>pl.com.bottega</groupId>
<artifactId>adapter-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.1.4</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.1-groovy-2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-spring</artifactId>
<version>1.1-groovy-2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.7.9</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -5,23 +5,23 @@ 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.calculation.Forecasts;
import pl.com.bottega.factory.shortages.prediction.notification.NotificationOfShortage;
import pl.com.bottega.factory.shortages.prediction.monitoring.persistence.ShortagesDao;
import pl.com.bottega.factory.shortages.prediction.monitoring.persistence.ShortagesEntity;
import pl.com.bottega.tools.TechnicalId;
import java.util.Optional;
@Component
@AllArgsConstructor
class ShortagePredictionProcessORMRepository implements ShortagePredictionProcessRepository {
class ShortagePredictionProcessORMRepository {
private final ShortagesDao dao;
private final ShortageDiffPolicy policy = ShortageDiffPolicy.ValuesAreNotSame;
private final Forecasts forecasts;
private final Configuration configuration = () -> 14;
private final NotificationOfShortage notifications;
private final ShortageEvents events;
@Override
public ShortagePredictionProcess get(RefNoId refNo) {
ShortagePredictionProcess get(RefNoId refNo) {
Optional<ShortagesEntity> entity = dao.findByRefNo(refNo.getRefNo());
return new ShortagePredictionProcess(
entity.map(ShortagesEntity::createId)
@@ -31,8 +31,7 @@ class ShortagePredictionProcessORMRepository implements ShortagePredictionProces
);
}
@Override
public void save(ShortagePredictionProcess model) {
void save(ShortagePredictionProcess model) {
// persisted after event
}
@@ -42,12 +41,12 @@ class ShortagePredictionProcessORMRepository implements ShortagePredictionProces
refNo, dao::findOne,
() -> dao.save(new ShortagesEntity(refNo.getRefNo())));
entity.setShortages(event.getShortages());
notifications.emit(event);
events.emit(event);
}
private void delete(ShortageSolved event) {
dao.delete(TechnicalId.get(event.getRefNo()));
notifications.emit(event);
events.emit(event);
}
private class EventsHandler implements ShortageEvents {

View File

@@ -1,18 +1,17 @@
package pl.com.bottega.factory.shortages.prediction;
package pl.com.bottega.factory.shortages.prediction.monitoring;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import pl.com.bottega.factory.demand.forecasting.DemandedLevelsChanged;
import pl.com.bottega.factory.shortages.prediction.monitoring.ShortagePredictionProcess;
import pl.com.bottega.factory.shortages.prediction.monitoring.ShortagePredictionProcessRepository;
@Lazy
@Component
import javax.transaction.Transactional;
@Service
@Transactional
@AllArgsConstructor
public class ShortagePredictionEventsMapping {
public class ShortagePredictionService {
private final ShortagePredictionProcessRepository repository;
private final ShortagePredictionProcessORMRepository repository;
public void predictShortages(DemandedLevelsChanged event) {
ShortagePredictionProcess model = repository.get(event.getRefNo());

View File

@@ -1,4 +1,4 @@
package pl.com.bottega.factory.shortages.prediction.monitoring;
package pl.com.bottega.factory.shortages.prediction.monitoring.persistence;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.data.rest.core.annotation.RestResource;

View File

@@ -1,9 +1,9 @@
package pl.com.bottega.factory.shortages.prediction.monitoring;
package pl.com.bottega.factory.shortages.prediction.monitoring.persistence;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import pl.com.bottega.factory.product.management.RefNoId;
import pl.com.bottega.factory.shortages.prediction.Shortages;
import pl.com.bottega.tools.JsonConverter;
@@ -13,7 +13,7 @@ import javax.persistence.*;
import java.io.Serializable;
@Entity(name = "Shortage")
@Data
@Getter
@NoArgsConstructor
@EqualsAndHashCode(of = "refNo")
public class ShortagesEntity implements Serializable {
@@ -27,17 +27,18 @@ public class ShortagesEntity implements Serializable {
private String refNo;
@Column(length = 1024)
@Convert(converter = ShortagesAsJson.class)
@Setter
private Shortages shortages;
ShortagesEntity(String refNo) {
public ShortagesEntity(String refNo) {
this.refNo = refNo;
}
RefNoId createId() {
public RefNoId createId() {
return new ShortagesEntityId(refNo, id);
}
static RefNoId createId(RefNoId id) {
public static RefNoId createId(RefNoId id) {
return id instanceof ShortagesEntityId ? id : new ShortagesEntityId(id.getRefNo());
}

View File

@@ -6,6 +6,8 @@ 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.monitoring.persistence.ShortagesDao
import pl.com.bottega.factory.shortages.prediction.monitoring.persistence.ShortagesEntity
import pl.com.bottega.factory.shortages.prediction.notification.NotificationOfShortage
import spock.lang.Specification

View File

@@ -9,6 +9,26 @@
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>pl.com.bottega</groupId>
<artifactId>shared-kernel-model</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.1-groovy-2.4</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
@@ -47,41 +67,4 @@
</plugins>
</build>
<dependencies>
<dependency>
<groupId>pl.com.bottega</groupId>
<artifactId>shared-kernel-model</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.8.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-java</artifactId>
<version>1.2.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-core</artifactId>
<version>1.2.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.1-groovy-2.4</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -6,7 +6,7 @@ import java.time.LocalDateTime;
import java.util.Map;
@AllArgsConstructor
class Deliveries {
class DeliveriesForecast {
private final Map<LocalDateTime, Long> forecast;

View File

@@ -15,7 +15,7 @@ public class Forecast {
private final SortedSet<LocalDateTime> deliveryTimes;
private final Stock stock;
private final ProductionOutputs outputs;
private final Deliveries deliveries;
private final DeliveriesForecast deliveries;
public Optional<Shortages> findShortages() {
long level = stock.getLevel();

View File

@@ -14,7 +14,7 @@ import java.util.Optional;
* Created by michal on 02.02.2017.
*/
@AllArgsConstructor
public class ShortagePredictionProcess {
class ShortagePredictionProcess {
private final RefNoId refNo;
private Shortages known;
@@ -24,19 +24,19 @@ public class ShortagePredictionProcess {
private final Configuration configuration;
private final ShortageEvents events;
public void onDemandChanged() {
void onDemandChanged() {
predict(After.DemandChanged);
}
public void onPlanChanged() {
void onPlanChanged() {
predict(After.PlanChanged);
}
public void onStockChanged() {
void onStockChanged() {
predict(After.StockChanged);
}
public void onLockedParts() {
void onLockedParts() {
predict(After.LockedParts);
}

View File

@@ -1,12 +0,0 @@
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(RefNoId refNo);
void save(ShortagePredictionProcess model);
}

View File

@@ -7,15 +7,13 @@ import lombok.Value;
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.NewShortage.After;
import pl.com.bottega.factory.shortages.prediction.monitoring.ShortageEvents;
import pl.com.bottega.factory.shortages.prediction.monitoring.ShortageSolved;
import java.time.Clock;
import java.time.LocalDateTime;
import java.util.Map;
@AllArgsConstructor
public class NotificationOfShortage implements ShortageEvents {
public class NotificationOfShortage {
private final QualityTasks qualityTasks;
private final Clock clock;
@@ -33,8 +31,7 @@ public class NotificationOfShortage implements ShortageEvents {
.build();
}
@Override
public void emit(NewShortage event) {
public void notifyAbout(NewShortage event) {
Shortages shortage = event.getShortages();
rules.wayOfNotificationAfter(event.getTrigger())
.notifyAbout(event.getShortages());
@@ -44,11 +41,6 @@ public class NotificationOfShortage implements ShortageEvents {
}
}
@Override
public void emit(ShortageSolved event) {
}
@Value
@Builder
static class NotificationRules {

View File

@@ -12,12 +12,12 @@ trait ShortagesCalculationAssemblerTrait {
String refNo = "3009000"
SortedSet<LocalDateTime> times
Forecasts forecastProvider(Stock stock, Deliveries demands, ProductionOutputs outputs) {
Forecasts forecastProvider(Stock stock, DeliveriesForecast demands, ProductionOutputs outputs) {
def forecast = forecast(stock, demands, outputs)
return { RefNoId refNo, int daysAhead -> forecast } as Forecasts
}
Forecast forecast(Stock stock, Deliveries demands, ProductionOutputs outputs) {
Forecast forecast(Stock stock, DeliveriesForecast demands, ProductionOutputs outputs) {
new Forecast(refNo, now, times, stock, outputs, demands)
}
@@ -35,14 +35,14 @@ trait ShortagesCalculationAssemblerTrait {
new ProductionForecast.Item(start, duration, partsPerMinute)
}
Deliveries noDeliveries() {
DeliveriesForecast noDeliveries() {
times = Collections.emptySortedSet()
new Deliveries([:])
new DeliveriesForecast([:])
}
Deliveries deliveries(Map<LocalDateTime, Long> demands) {
DeliveriesForecast deliveries(Map<LocalDateTime, Long> demands) {
times = new TreeSet<>(demands.keySet())
new Deliveries(demands)
new DeliveriesForecast(demands)
}
Stock stock(long levels) {

View File

@@ -3,7 +3,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
import spock.lang.Specification
import java.time.*
@@ -25,7 +24,7 @@ class NotificationOfShortageSpec extends Specification {
def notificator = notificator()
when:
notificator.emit(newShortage(After.DemandChanged, withShortage()))
notificator.notifyAbout(newShortage(After.DemandChanged, withShortage()))
then:
1 * notifications.alertPlanner(withShortage())
@@ -36,7 +35,7 @@ class NotificationOfShortageSpec extends Specification {
def notificator = notificator()
when:
notificator.emit(newShortage(After.LockedParts, withShortage()))
notificator.notifyAbout(newShortage(After.LockedParts, withShortage()))
then:
1 * notifications.softNotifyPlanner(withShortage())
@@ -47,7 +46,7 @@ class NotificationOfShortageSpec extends Specification {
def notificator = notificator()
when:
notificator.emit(newShortage(After.PlanChanged, withShortage()))
notificator.notifyAbout(newShortage(After.PlanChanged, withShortage()))
then:
1 * notifications.markOnPlan(withShortage())
@@ -58,7 +57,7 @@ class NotificationOfShortageSpec extends Specification {
def notificator = notificator()
when:
notificator.emit(newShortage(After.StockChanged, withShortage()))
notificator.notifyAbout(newShortage(After.StockChanged, withShortage()))
then:
1 * notifications.alertPlanner(withShortage())
@@ -69,7 +68,7 @@ class NotificationOfShortageSpec extends Specification {
def notificator = notificator()
when:
notificator.emit(newShortage(After.StockChanged,
notificator.notifyAbout(newShortage(After.StockChanged,
withShortage(Duration.ofDays(1), 500))
)
@@ -82,7 +81,7 @@ class NotificationOfShortageSpec extends Specification {
def notificator = notificator()
when:
notificator.emit(newShortage(After.StockChanged,
notificator.notifyAbout(newShortage(After.StockChanged,
withShortage(Duration.ofDays(1), 0))
)
@@ -95,7 +94,7 @@ class NotificationOfShortageSpec extends Specification {
def notificator = notificator()
when:
notificator.emit(newShortage(After.StockChanged,
notificator.notifyAbout(newShortage(After.StockChanged,
withShortage(Duration.ofDays(10), 500))
)
@@ -103,18 +102,6 @@ class NotificationOfShortageSpec extends Specification {
0 * tasks.increasePriorityFor(_)
}
def "No notification after shortage solved specified for now"() {
given:
def notificator = notificator()
when:
notificator.emit(new ShortageSolved(new RefNoId(refNo)))
then:
0 * tasks.increasePriorityFor(_)
0 * notifications._(_)
}
def notificator() {
new NotificationOfShortage(
tasks, clock, policy,