domain and design in readme
This commit is contained in:
30
README.md
30
README.md
@@ -1,4 +1,4 @@
|
||||
# Missing complete example of Domain-Driven Design enterprise application
|
||||
# The missing, complete example of Domain-Driven Design enterprise application
|
||||
|
||||
## Command Query CRUD Responsibility Segregation
|
||||
Not every piece of software is equally important...
|
||||
@@ -63,22 +63,28 @@ Making useful application from the Domain Model and the technology.
|
||||
In most projects the biggest risk is lack of domain knowledge among developers. We all known Java,
|
||||
databases and bunch of handy frameworks, but what about: Investment Banking, Automotive Manufacturing or even e-Commerce.
|
||||
|
||||
Lets face those risk at first, maintain and explore domain knowledge
|
||||
Let's face the risk at first, maintain and explore domain knowledge
|
||||
with **Model Exploration Whirlpool** and build **Ubiquitous Language** with your executable **Domain Model**,
|
||||
**Domain Stories** and **Specification by Examples** from day one.
|
||||
Adding infrastructure and technology later is easy thanks to Hexagonal Architecture.
|
||||
|
||||
Starting from ZERO business knowledge through initial domain and opportunity exploration with **Big Picture Event Storming**:
|
||||
<big-picture-es>
|
||||
Simply starting from ZERO business knowledge through initial domain and opportunity exploration with **Big Picture Event Storming**:
|
||||

|
||||
|
||||
Looking for system boundaries, impacted and required actors and there interactions with system under design:
|
||||
<actors-and-boundaries>
|
||||
after cleaning and trimming initial model to most valuable and needed areas:
|
||||

|
||||
|
||||
Estimating depth of domain model and Command Query CRUD segregation:
|
||||
<command-query-crud>
|
||||
Deep dive in **Demand Forecasting** sub-domain with **Design Level Event Storming**:
|
||||

|
||||
|
||||
Design level Event Storming with Domain Stories and Specification by Examples:
|
||||
<demand-forecasting-design-es>
|
||||
<adjust-demand.feature>
|
||||
is excellent canvas to cooperative exploration of:
|
||||
- impacted and required actors,
|
||||
- initial / desired system boundaries,
|
||||
- actors interactions with system under design.
|
||||
|
||||
<shortage-prediction-design-es>
|
||||
With use of **Domain Stories** and **Specification by Examples** it is easy to find:
|
||||
- business rules and invariants,
|
||||
- acceptance criteria,
|
||||
- estimation of Domain Model depth,
|
||||
- CRUD-suspected activities,
|
||||
- missing parts.
|
||||
|
||||
@@ -32,7 +32,7 @@ class DemandEventsMapping implements DemandEvents {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emit(ReviewRequested event) {
|
||||
public void emit(ReviewRequired event) {
|
||||
Instant timestamp = Instant.now(clock);
|
||||
demandReviews.save(event.getReviews().stream()
|
||||
.map(r -> new DemandReviewEntity(timestamp, r))
|
||||
|
||||
@@ -21,7 +21,7 @@ import static java.util.stream.Collectors.toMap;
|
||||
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
class ForecastORMRepository implements Forecasts {
|
||||
class ForecastORMRepository implements ShortageForecasts {
|
||||
|
||||
private final WarehouseService stocks;
|
||||
private final DeliveryForecastDao deliveries;
|
||||
@@ -29,7 +29,7 @@ class ForecastORMRepository implements Forecasts {
|
||||
private final Clock clock;
|
||||
|
||||
@Override
|
||||
public Forecast get(RefNoId refNo, int daysAhead) {
|
||||
public ShortageForecast get(RefNoId refNo, int daysAhead) {
|
||||
Stock stock = stocks.forRefNo(refNo);
|
||||
LocalDateTime time = LocalDateTime.now(clock);
|
||||
LocalDateTime max = time.plusDays(daysAhead).truncatedTo(ChronoUnit.DAYS);
|
||||
@@ -53,6 +53,6 @@ class ForecastORMRepository implements Forecasts {
|
||||
.collect(Collectors.toList())
|
||||
).outputsInTimes(time, deliveryTimes);
|
||||
|
||||
return new Forecast(refNo.getRefNo(), time, deliveryTimes, stock, outputs, demand);
|
||||
return new ShortageForecast(refNo.getRefNo(), time, deliveryTimes, stock, outputs, demand);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package pl.com.bottega.factory.demand.forecasting;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import pl.com.bottega.factory.demand.forecasting.ReviewRequested.ReviewNeeded;
|
||||
import pl.com.bottega.factory.demand.forecasting.ReviewRequired.ToReview;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
@@ -29,7 +29,7 @@ public class DemandService {
|
||||
repository.save(model);
|
||||
}
|
||||
|
||||
public void review(ReviewNeeded review, ReviewDecision decision) {
|
||||
public void review(ToReview review, ReviewDecision decision) {
|
||||
ProductDemand model = repository.get(review.getRefNo());
|
||||
model.review(review, decision);
|
||||
repository.save(model);
|
||||
|
||||
@@ -4,7 +4,7 @@ import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import pl.com.bottega.factory.demand.forecasting.ReviewDecision;
|
||||
import pl.com.bottega.factory.demand.forecasting.ReviewRequested.ReviewNeeded;
|
||||
import pl.com.bottega.factory.demand.forecasting.ReviewRequired.ToReview;
|
||||
import pl.com.bottega.tools.JsonConverter;
|
||||
|
||||
import javax.persistence.*;
|
||||
@@ -25,14 +25,14 @@ public class DemandReviewEntity implements Serializable {
|
||||
private LocalDate date;
|
||||
private Instant timestamp;
|
||||
@Convert(converter = ReviewAsJson.class)
|
||||
private ReviewNeeded review;
|
||||
private ToReview review;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private ReviewDecision decision;
|
||||
@Setter
|
||||
private LocalDate cleanAfter;
|
||||
|
||||
public DemandReviewEntity(Instant timestamp, ReviewNeeded review) {
|
||||
public DemandReviewEntity(Instant timestamp, ToReview review) {
|
||||
this.timestamp = timestamp;
|
||||
this.refNo = review.getId().getRefNo();
|
||||
this.date = review.getId().getDate();
|
||||
@@ -43,9 +43,9 @@ public class DemandReviewEntity implements Serializable {
|
||||
return decision != null;
|
||||
}
|
||||
|
||||
public static class ReviewAsJson extends JsonConverter<ReviewNeeded> {
|
||||
public static class ReviewAsJson extends JsonConverter<ToReview> {
|
||||
public ReviewAsJson() {
|
||||
super(ReviewNeeded.class);
|
||||
super(ToReview.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import org.springframework.data.jpa.convert.threeten.Jsr310JpaConverters;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import pl.com.bottega.factory.demand.forecasting.DemandEvents;
|
||||
import pl.com.bottega.factory.demand.forecasting.DemandedLevelsChanged;
|
||||
import pl.com.bottega.factory.demand.forecasting.ReviewRequested;
|
||||
import pl.com.bottega.factory.demand.forecasting.ReviewRequired;
|
||||
|
||||
import java.time.Clock;
|
||||
|
||||
@@ -34,7 +34,7 @@ public class Configuration {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emit(ReviewRequested event) {
|
||||
public void emit(ReviewRequired event) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package pl.com.bottega.factory.demand.forecasting;
|
||||
|
||||
import lombok.Value;
|
||||
import pl.com.bottega.factory.demand.forecasting.DemandedLevelsChanged.Change;
|
||||
import pl.com.bottega.factory.demand.forecasting.ReviewRequested.ReviewNeeded;
|
||||
import pl.com.bottega.factory.demand.forecasting.ReviewRequired.ToReview;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
@@ -19,7 +19,7 @@ class DailyDemand {
|
||||
interface Events {
|
||||
void emit(LevelChanged event);
|
||||
|
||||
void emit(ReviewNeeded event);
|
||||
void emit(ToReview event);
|
||||
|
||||
void emit(DemandUpdated event);
|
||||
}
|
||||
@@ -49,7 +49,7 @@ class DailyDemand {
|
||||
void update(Demand documented) {
|
||||
State state = state();
|
||||
if (policy.reviewNeeded(this.documented, this.adjustment, documented)) {
|
||||
events.emit(new ReviewNeeded(id,
|
||||
events.emit(new ToReview(id,
|
||||
this.documented,
|
||||
this.adjustment.getDemand(),
|
||||
documented)
|
||||
|
||||
@@ -3,5 +3,5 @@ package pl.com.bottega.factory.demand.forecasting;
|
||||
public interface DemandEvents {
|
||||
void emit(DemandedLevelsChanged event);
|
||||
|
||||
void emit(ReviewRequested event);
|
||||
void emit(ReviewRequired event);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package pl.com.bottega.factory.demand.forecasting;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import pl.com.bottega.factory.demand.forecasting.ReviewRequested.ReviewNeeded;
|
||||
import pl.com.bottega.factory.demand.forecasting.ReviewRequired.ToReview;
|
||||
import pl.com.bottega.factory.product.management.RefNoId;
|
||||
|
||||
import java.time.Clock;
|
||||
@@ -40,11 +40,11 @@ class ProductDemand {
|
||||
events.emit(new DemandedLevelsChanged(id, unit.changes()));
|
||||
}
|
||||
if (unit.anyReviews()) {
|
||||
events.emit(new ReviewRequested(id, unit.reviews()));
|
||||
events.emit(new ReviewRequired(id, unit.reviews()));
|
||||
}
|
||||
}
|
||||
|
||||
void review(ReviewNeeded review, ReviewDecision decision) {
|
||||
void review(ToReview review, ReviewDecision decision) {
|
||||
if (decision.requireAdjustment()) {
|
||||
adjust(decision.toAdjustment(review));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package pl.com.bottega.factory.demand.forecasting;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import pl.com.bottega.factory.demand.forecasting.ReviewRequested.ReviewNeeded;
|
||||
import pl.com.bottega.factory.demand.forecasting.ReviewRequired.ToReview;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.function.Function;
|
||||
@@ -9,13 +9,13 @@ import java.util.function.Function;
|
||||
@AllArgsConstructor
|
||||
public enum ReviewDecision {
|
||||
IGNORE(r -> null),
|
||||
PICK_PREVIOUS(ReviewNeeded::getPreviousDocumented),
|
||||
MAKE_ADJUSTMENT_WEAK(ReviewNeeded::getAdjustment),
|
||||
PICK_NEW(ReviewNeeded::getNewDocumented);
|
||||
PICK_PREVIOUS(ToReview::getPreviousDocumented),
|
||||
MAKE_ADJUSTMENT_WEAK(ToReview::getAdjustment),
|
||||
PICK_NEW(ToReview::getNewDocumented);
|
||||
|
||||
private final Function<ReviewNeeded, Demand> pick;
|
||||
private final Function<ToReview, Demand> pick;
|
||||
|
||||
public AdjustDemand toAdjustment(ReviewNeeded review) {
|
||||
public AdjustDemand toAdjustment(ToReview review) {
|
||||
if (this == IGNORE) {
|
||||
throw new IllegalStateException("can't convert " + this + " to adjustment");
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package pl.com.bottega.factory.demand.forecasting;
|
||||
|
||||
import pl.com.bottega.factory.demand.forecasting.ReviewRequested.ReviewNeeded;
|
||||
import pl.com.bottega.factory.demand.forecasting.ReviewRequired.ToReview;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -9,7 +9,7 @@ import static java.util.Collections.unmodifiableList;
|
||||
class UnitOfWork implements DailyDemand.Events {
|
||||
|
||||
Map<DailyId, DemandedLevelsChanged.Change> changes = new HashMap<>();
|
||||
List<ReviewNeeded> reviews = new LinkedList<>();
|
||||
List<ToReview> reviews = new LinkedList<>();
|
||||
List<DailyDemand.DemandUpdated> updates = new LinkedList<>();
|
||||
|
||||
boolean anyChanges() {
|
||||
@@ -24,7 +24,7 @@ class UnitOfWork implements DailyDemand.Events {
|
||||
return !reviews.isEmpty();
|
||||
}
|
||||
|
||||
List<ReviewNeeded> reviews() {
|
||||
List<ToReview> reviews() {
|
||||
return Collections.unmodifiableList(reviews);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ class UnitOfWork implements DailyDemand.Events {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emit(ReviewNeeded event) {
|
||||
public void emit(ToReview event) {
|
||||
reviews.add(event);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import java.time.LocalDate
|
||||
import java.time.ZoneId
|
||||
|
||||
import static DemandedLevelsChanged.Change
|
||||
import static ReviewRequested.ReviewNeeded
|
||||
import static pl.com.bottega.factory.demand.forecasting.ReviewRequired.ToReview
|
||||
|
||||
class DailyDemandBuilder {
|
||||
|
||||
@@ -92,8 +92,8 @@ class DailyDemandBuilder {
|
||||
)
|
||||
}
|
||||
|
||||
ReviewNeeded reviewRequest(long previousDocumented, long adjustment, long newDocumented) {
|
||||
new ReviewNeeded(
|
||||
ToReview reviewRequest(long previousDocumented, long adjustment, long newDocumented) {
|
||||
new ToReview(
|
||||
new DailyId(refNo, date),
|
||||
Demand.of(previousDocumented),
|
||||
Demand.of(adjustment),
|
||||
|
||||
@@ -5,7 +5,7 @@ import pl.com.bottega.factory.product.management.RefNoId
|
||||
import java.time.*
|
||||
|
||||
import static DemandedLevelsChanged.Change
|
||||
import static ReviewRequested.ReviewNeeded
|
||||
import static pl.com.bottega.factory.demand.forecasting.ReviewRequired.ToReview
|
||||
|
||||
class ProductDemandBuilder {
|
||||
|
||||
@@ -74,15 +74,15 @@ class ProductDemandBuilder {
|
||||
new DemandedLevelsChanged(new RefNoId(refNo), results)
|
||||
}
|
||||
|
||||
ReviewRequested reviewRequest(ReviewNeeded... reviews) {
|
||||
new ReviewRequested(new RefNoId(refNo), reviews as List)
|
||||
ReviewRequired reviewRequest(ToReview... reviews) {
|
||||
new ReviewRequired(new RefNoId(refNo), reviews as List)
|
||||
}
|
||||
|
||||
ReviewNeeded review(LocalDate date,
|
||||
long previousDocumented,
|
||||
long strongAdjustment,
|
||||
long newDocumented) {
|
||||
new ReviewNeeded(
|
||||
ToReview review(LocalDate date,
|
||||
long previousDocumented,
|
||||
long strongAdjustment,
|
||||
long newDocumented) {
|
||||
new ToReview(
|
||||
new DailyId(refNo, date),
|
||||
Demand.of(previousDocumented),
|
||||
Demand.of(strongAdjustment),
|
||||
|
||||
@@ -2,7 +2,7 @@ package pl.com.bottega.factory.demand.forecasting
|
||||
|
||||
import java.time.LocalDate
|
||||
|
||||
import static ReviewRequested.ReviewNeeded
|
||||
import static pl.com.bottega.factory.demand.forecasting.ReviewRequired.ToReview
|
||||
|
||||
trait ProductDemandTrait {
|
||||
|
||||
@@ -32,11 +32,11 @@ trait ProductDemandTrait {
|
||||
[]
|
||||
}
|
||||
|
||||
ReviewRequested reviewRequest(ReviewNeeded... reviews) {
|
||||
ReviewRequired reviewRequest(ToReview... reviews) {
|
||||
builder.reviewRequest(reviews)
|
||||
}
|
||||
|
||||
ReviewNeeded review(
|
||||
ToReview review(
|
||||
LocalDate date,
|
||||
long previousDocumented,
|
||||
long strongAdjustment,
|
||||
|
||||
@@ -1,25 +1,29 @@
|
||||
Feature: manual adjustments of demand
|
||||
|
||||
sub domain: demand forecasting
|
||||
Sub Domain: demand forecasting
|
||||
keeps track of current and future customer needs for our products
|
||||
|
||||
Domain story:
|
||||
Adjust demand at day to amount, delivered.
|
||||
>> demand.adjust(productRefNo, atDay, amount)
|
||||
We can change only Demands for today and future.
|
||||
|
||||
New demand is stored for further reference
|
||||
Data from call-off document should be preserved (DON’T OVERRIDE THEM).
|
||||
Data from call-off document should be preserved.
|
||||
Adjust demand should be possible even
|
||||
if there was no call-off document for that product.
|
||||
In standard case future call-off documents should be stronger (overrides) adjustment,
|
||||
but if customer warn us about opposite case import of call-off document should not remove previous adjustments.
|
||||
if there was no document for that product.
|
||||
In standard case future call-off documents should override adjustment,
|
||||
but if customer warn us about opposite case
|
||||
import of document should not remove previous adjustments.
|
||||
Logistician note should be kept with adjustment.
|
||||
|
||||
emit domain event demand changed
|
||||
Domain event: demanded levels changed
|
||||
[context boundary]
|
||||
|
||||
Logistician note should be kept along with adjustment.
|
||||
Sub Domain: shortage prediction
|
||||
continuously monitors demands, production plan and stock levels
|
||||
predicts potential shortage based on forecasts
|
||||
notifies personal about potential shortages
|
||||
|
||||
outside of context boundary:
|
||||
If new demand is not fulfilled by
|
||||
current product stock and production forecast
|
||||
there is a shortage in particular days and we need to rise an alert.
|
||||
|
||||
BIN
es-big-picture-cleaned.jpg
Normal file
BIN
es-big-picture-cleaned.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 258 KiB |
BIN
es-big-picture-original.jpg
Normal file
BIN
es-big-picture-original.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 119 KiB |
BIN
es-design-demand-forecasting.jpg
Normal file
BIN
es-design-demand-forecasting.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 340 KiB |
@@ -8,17 +8,17 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Value
|
||||
public class ReviewRequested {
|
||||
public class ReviewRequired {
|
||||
RefNoId refNo;
|
||||
List<ReviewNeeded> reviews;
|
||||
List<ToReview> reviews;
|
||||
|
||||
public ReviewRequested(RefNoId refNo, List<ReviewNeeded> reviews) {
|
||||
public ReviewRequired(RefNoId refNo, List<ToReview> reviews) {
|
||||
this.refNo = refNo;
|
||||
this.reviews = Collections.unmodifiableList(reviews);
|
||||
}
|
||||
|
||||
@Value
|
||||
public static class ReviewNeeded {
|
||||
public static class ToReview {
|
||||
DailyId id;
|
||||
Demand previousDocumented;
|
||||
Demand adjustment;
|
||||
@@ -4,7 +4,7 @@ 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.calculation.Forecasts;
|
||||
import pl.com.bottega.factory.shortages.prediction.calculation.ShortageForecasts;
|
||||
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;
|
||||
@@ -17,7 +17,7 @@ class ShortagePredictionProcessORMRepository {
|
||||
|
||||
private final ShortagesDao dao;
|
||||
private final ShortageDiffPolicy policy = ShortageDiffPolicy.ValuesAreNotSame;
|
||||
private final Forecasts forecasts;
|
||||
private final ShortageForecasts forecasts;
|
||||
private final Configuration configuration = () -> 14;
|
||||
private final ShortageEvents events;
|
||||
|
||||
@@ -40,7 +40,7 @@ class ShortagePredictionProcessORMRepository {
|
||||
ShortagesEntity entity = TechnicalId.findOrDefault(
|
||||
refNo, dao::findOne,
|
||||
() -> dao.save(new ShortagesEntity(refNo.getRefNo())));
|
||||
entity.setShortages(event.getShortages());
|
||||
entity.setShortages(event.getShortage());
|
||||
events.emit(event);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ 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.factory.shortages.prediction.Shortage;
|
||||
import pl.com.bottega.tools.JsonConverter;
|
||||
import pl.com.bottega.tools.TechnicalId;
|
||||
|
||||
@@ -25,7 +25,7 @@ public class ShortagesEntity implements Serializable {
|
||||
private String refNo;
|
||||
@Setter
|
||||
@Convert(converter = ShortagesAsJson.class)
|
||||
private Shortages shortages;
|
||||
private Shortage shortages;
|
||||
|
||||
public ShortagesEntity(String refNo) {
|
||||
this.refNo = refNo;
|
||||
@@ -39,9 +39,9 @@ public class ShortagesEntity implements Serializable {
|
||||
return id instanceof ShortagesEntityId ? id : new ShortagesEntityId(id.getRefNo());
|
||||
}
|
||||
|
||||
public static class ShortagesAsJson extends JsonConverter<Shortages> {
|
||||
public static class ShortagesAsJson extends JsonConverter<Shortage> {
|
||||
public ShortagesAsJson() {
|
||||
super(Shortages.class);
|
||||
super(Shortage.class);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package pl.com.bottega.factory.shortages.prediction.notification;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortages;
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortage;
|
||||
|
||||
import java.time.Clock;
|
||||
|
||||
@@ -27,17 +27,17 @@ public class NotificationConfiguration {
|
||||
|
||||
private static class MockedPlannerPushNotifications implements Notifications {
|
||||
@Override
|
||||
public void alertPlanner(Shortages shortage) {
|
||||
public void alertPlanner(Shortage shortage) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void softNotifyPlanner(Shortages shortage) {
|
||||
public void softNotifyPlanner(Shortage shortage) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markOnPlan(Shortages shortage) {
|
||||
public void markOnPlan(Shortage shortage) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.jpa.convert.threeten.Jsr310JpaConverters;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import pl.com.bottega.factory.product.management.RefNoId;
|
||||
import pl.com.bottega.factory.shortages.prediction.calculation.Forecast;
|
||||
import pl.com.bottega.factory.shortages.prediction.calculation.Forecasts;
|
||||
import pl.com.bottega.factory.shortages.prediction.calculation.ShortageForecast;
|
||||
import pl.com.bottega.factory.shortages.prediction.calculation.ShortageForecasts;
|
||||
import pl.com.bottega.factory.shortages.prediction.monitoring.NewShortage;
|
||||
import pl.com.bottega.factory.shortages.prediction.monitoring.ShortageEvents;
|
||||
import pl.com.bottega.factory.shortages.prediction.monitoring.ShortageSolved;
|
||||
@@ -26,8 +26,8 @@ public class Configuration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Forecasts forecasts() {
|
||||
return new ForecastsFake();
|
||||
public ShortageForecasts forecasts() {
|
||||
return new ShortageForecastsFake();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -47,9 +47,9 @@ public class Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
private class ForecastsFake implements Forecasts {
|
||||
private class ShortageForecastsFake implements ShortageForecasts {
|
||||
@Override
|
||||
public Forecast get(RefNoId refNo, int daysAhead) {
|
||||
public ShortageForecast get(RefNoId refNo, int daysAhead) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ 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.Shortage
|
||||
import pl.com.bottega.factory.shortages.prediction.calculation.ShortageForecasts
|
||||
import pl.com.bottega.factory.shortages.prediction.monitoring.persistence.ShortagesDao
|
||||
import pl.com.bottega.factory.shortages.prediction.monitoring.persistence.ShortagesEntity
|
||||
import spock.lang.Specification
|
||||
@@ -25,7 +25,7 @@ class ShortagePredictionProcessORMRepositoryTest extends Specification {
|
||||
|
||||
@Autowired
|
||||
ShortagesDao dao
|
||||
def forecasts = Mock(Forecasts)
|
||||
def forecasts = Mock(ShortageForecasts)
|
||||
def notifications = Mock(ShortageEvents)
|
||||
ShortagePredictionProcessORMRepository repository
|
||||
|
||||
@@ -88,13 +88,13 @@ class ShortagePredictionProcessORMRepositoryTest extends Specification {
|
||||
noShortagesPersisted()
|
||||
}
|
||||
|
||||
def persistedShortage(Shortages shortages) {
|
||||
def persistedShortage(Shortage shortages) {
|
||||
def entity = new ShortagesEntity(refNo)
|
||||
entity.setShortages(shortages)
|
||||
dao.save(entity)
|
||||
}
|
||||
|
||||
Shortages shortagesCurrentlyPersisted() {
|
||||
Shortage shortagesCurrentlyPersisted() {
|
||||
dao.findByRefNo(refNo).get().shortages
|
||||
}
|
||||
|
||||
@@ -106,29 +106,29 @@ class ShortagePredictionProcessORMRepositoryTest extends Specification {
|
||||
repository.get(new RefNoId(refNo))
|
||||
}
|
||||
|
||||
Shortages noShortages() {
|
||||
Shortage noShortages() {
|
||||
null
|
||||
}
|
||||
|
||||
Shortages someShortages() {
|
||||
Shortages.builder(refNo, 0, now)
|
||||
Shortage someShortages() {
|
||||
Shortage.builder(refNo, 0, now)
|
||||
.missing(now.plusDays(1), 500)
|
||||
.build()
|
||||
.orElse(null)
|
||||
}
|
||||
|
||||
Shortages someOldShortages() {
|
||||
Shortages.builder(refNo, 0, now.minusDays(1))
|
||||
Shortage someOldShortages() {
|
||||
Shortage.builder(refNo, 0, now.minusDays(1))
|
||||
.missing(now.plusDays(2), 2500)
|
||||
.build()
|
||||
.orElse(null)
|
||||
}
|
||||
|
||||
Shortages shortagesCurrentlyKnownBy(ShortagePredictionProcess process) {
|
||||
Shortage shortagesCurrentlyKnownBy(ShortagePredictionProcess process) {
|
||||
process.known
|
||||
}
|
||||
|
||||
void processEmitsNewShortage(ShortagePredictionProcess process, Shortages shortages) {
|
||||
void processEmitsNewShortage(ShortagePredictionProcess process, Shortage shortages) {
|
||||
process.events.emit(new NewShortage(process.refNo, DemandChanged, shortages))
|
||||
}
|
||||
|
||||
|
||||
@@ -15,22 +15,22 @@ import java.util.TreeMap;
|
||||
* Created by michal on 22.10.2015.
|
||||
*/
|
||||
@Value
|
||||
public class Shortages {
|
||||
public class Shortage {
|
||||
|
||||
private final String refNo;
|
||||
private final long lockedParts;
|
||||
private final LocalDateTime found;
|
||||
private final SortedMap<LocalDateTime, Long> shortages;
|
||||
|
||||
public static Shortages.Builder builder(String refNo, long locked, LocalDateTime found) {
|
||||
public static Shortage.Builder builder(String refNo, long locked, LocalDateTime found) {
|
||||
return new Builder(refNo, locked, found);
|
||||
}
|
||||
|
||||
public static boolean areNotSame(Shortages first, Shortages second) {
|
||||
public static boolean areNotSame(Shortage first, Shortage second) {
|
||||
return !areSame(first, second);
|
||||
}
|
||||
|
||||
public static boolean areSame(Shortages first, Shortages second) {
|
||||
public static boolean areSame(Shortage first, Shortage second) {
|
||||
boolean noShortages = first == null && second == null;
|
||||
boolean onlyOne = first == null && second != null || first != null && second == null;
|
||||
if (noShortages || onlyOne) return false;
|
||||
@@ -55,11 +55,11 @@ public class Shortages {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Optional<Shortages> build() {
|
||||
public Optional<Shortage> build() {
|
||||
if (gaps.isEmpty()) {
|
||||
return Optional.empty();
|
||||
} else {
|
||||
return Optional.of(new Shortages(refNo, locked, found,
|
||||
return Optional.of(new Shortage(refNo, locked, found,
|
||||
Collections.unmodifiableSortedMap(gaps)));
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
package pl.com.bottega.factory.shortages.prediction.calculation;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortages;
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortage;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Optional;
|
||||
import java.util.SortedSet;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class Forecast {
|
||||
public class ShortageForecast {
|
||||
|
||||
private final String refNo;
|
||||
private final LocalDateTime created;
|
||||
@@ -17,10 +17,10 @@ public class Forecast {
|
||||
private final ProductionOutputs outputs;
|
||||
private final DeliveriesForecast deliveries;
|
||||
|
||||
public Optional<Shortages> findShortages() {
|
||||
public Optional<Shortage> findShortages() {
|
||||
long level = stock.getLevel();
|
||||
|
||||
Shortages.Builder found = Shortages.builder(refNo, stock.getLocked(), created);
|
||||
Shortage.Builder found = Shortage.builder(refNo, stock.getLocked(), created);
|
||||
LocalDateTime lastTime = created;
|
||||
for (LocalDateTime time : deliveryTimes) {
|
||||
long demand = deliveries.get(time);
|
||||
@@ -2,6 +2,6 @@ package pl.com.bottega.factory.shortages.prediction.calculation;
|
||||
|
||||
import pl.com.bottega.factory.product.management.RefNoId;
|
||||
|
||||
public interface Forecasts {
|
||||
Forecast get(RefNoId refNo, int daysAhead);
|
||||
public interface ShortageForecasts {
|
||||
ShortageForecast get(RefNoId refNo, int daysAhead);
|
||||
}
|
||||
@@ -2,7 +2,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;
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortage;
|
||||
|
||||
/**
|
||||
* Created by michal on 03.02.2017.
|
||||
@@ -14,5 +14,5 @@ public class NewShortage {
|
||||
|
||||
RefNoId refNo;
|
||||
After trigger;
|
||||
Shortages shortages;
|
||||
Shortage shortage;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package pl.com.bottega.factory.shortages.prediction.monitoring;
|
||||
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortages;
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortage;
|
||||
|
||||
interface ShortageDiffPolicy {
|
||||
|
||||
ShortageDiffPolicy ValuesAreNotSame = Shortages::areNotSame;
|
||||
ShortageDiffPolicy ValuesAreNotSame = Shortage::areNotSame;
|
||||
|
||||
boolean areDifferent(Shortages previous, Shortages found);
|
||||
boolean areDifferent(Shortage previous, Shortage found);
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@ 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;
|
||||
import pl.com.bottega.factory.shortages.prediction.calculation.Forecasts;
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortage;
|
||||
import pl.com.bottega.factory.shortages.prediction.calculation.ShortageForecast;
|
||||
import pl.com.bottega.factory.shortages.prediction.calculation.ShortageForecasts;
|
||||
import pl.com.bottega.factory.shortages.prediction.monitoring.NewShortage.After;
|
||||
|
||||
import java.util.Optional;
|
||||
@@ -17,10 +17,10 @@ import java.util.Optional;
|
||||
class ShortagePredictionProcess {
|
||||
|
||||
private final RefNoId refNo;
|
||||
private Shortages known;
|
||||
private Shortage known;
|
||||
|
||||
private final ShortageDiffPolicy diffPolicy;
|
||||
private final Forecasts forecasts;
|
||||
private final ShortageForecasts forecasts;
|
||||
private final Configuration configuration;
|
||||
private final ShortageEvents events;
|
||||
|
||||
@@ -41,10 +41,10 @@ class ShortagePredictionProcess {
|
||||
}
|
||||
|
||||
private void predict(After event) {
|
||||
Forecast forecast = forecasts.get(refNo,
|
||||
ShortageForecast forecast = forecasts.get(refNo,
|
||||
configuration.shortagePredictionDaysAhead());
|
||||
|
||||
Optional<Shortages> newlyFound = forecast.findShortages();
|
||||
Optional<Shortage> newlyFound = forecast.findShortages();
|
||||
|
||||
boolean areDifferent = diffPolicy.areDifferent(this.known, newlyFound.orElse(null));
|
||||
if (areDifferent && newlyFound.isPresent()) {
|
||||
|
||||
@@ -4,7 +4,7 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Singular;
|
||||
import lombok.Value;
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortages;
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortage;
|
||||
import pl.com.bottega.factory.shortages.prediction.monitoring.NewShortage;
|
||||
import pl.com.bottega.factory.shortages.prediction.monitoring.NewShortage.After;
|
||||
|
||||
@@ -32,9 +32,9 @@ public class NotificationOfShortage {
|
||||
}
|
||||
|
||||
public void notifyAbout(NewShortage event) {
|
||||
Shortages shortage = event.getShortages();
|
||||
Shortage shortage = event.getShortage();
|
||||
rules.wayOfNotificationAfter(event.getTrigger())
|
||||
.notifyAbout(event.getShortages());
|
||||
.notifyAbout(event.getShortage());
|
||||
|
||||
if (policy.shouldIncreasePriority(LocalDateTime.now(clock), shortage)) {
|
||||
qualityTasks.increasePriorityFor(shortage.getRefNo());
|
||||
@@ -54,6 +54,6 @@ public class NotificationOfShortage {
|
||||
}
|
||||
|
||||
interface Notificator {
|
||||
void notifyAbout(Shortages shortages);
|
||||
void notifyAbout(Shortage shortage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package pl.com.bottega.factory.shortages.prediction.notification;
|
||||
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortages;
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortage;
|
||||
|
||||
/**
|
||||
* Created by michal on 02.02.2017.
|
||||
*/
|
||||
public interface Notifications {
|
||||
void alertPlanner(Shortages shortage);
|
||||
void alertPlanner(Shortage shortage);
|
||||
|
||||
void softNotifyPlanner(Shortages shortage);
|
||||
void softNotifyPlanner(Shortage shortage);
|
||||
|
||||
void markOnPlan(Shortages shortage);
|
||||
void markOnPlan(Shortage shortage);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package pl.com.bottega.factory.shortages.prediction.notification;
|
||||
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortages;
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortage;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.time.LocalDateTime;
|
||||
public interface RecoveryTaskPriorityChangePolicy {
|
||||
|
||||
static RecoveryTaskPriorityChangePolicy never() {
|
||||
return (LocalDateTime now, Shortages shortage) -> false;
|
||||
return (LocalDateTime now, Shortage shortage) -> false;
|
||||
}
|
||||
|
||||
static RecoveryTaskPriorityChangePolicy onlyIn1DaysAhead() {
|
||||
@@ -18,10 +18,10 @@ public interface RecoveryTaskPriorityChangePolicy {
|
||||
}
|
||||
|
||||
static RecoveryTaskPriorityChangePolicy shortageInDays(long shortageInXDays) {
|
||||
return (LocalDateTime now, Shortages shortage) ->
|
||||
return (LocalDateTime now, Shortage shortage) ->
|
||||
shortage.getLockedParts() > 0 && shortage.anyBefore(
|
||||
now.plusDays(shortageInXDays));
|
||||
}
|
||||
|
||||
boolean shouldIncreasePriority(LocalDateTime now, Shortages shortage);
|
||||
boolean shouldIncreasePriority(LocalDateTime now, Shortage shortage);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package pl.com.bottega.factory.shortages.prediction.calculation
|
||||
|
||||
import spock.lang.Specification
|
||||
|
||||
class ShortagesCalculationAlgorithmSpec extends Specification
|
||||
class ShortageCalculationAlgorithmSpec extends Specification
|
||||
implements ShortagesCalculationAssemblerTrait {
|
||||
|
||||
void setup() {
|
||||
@@ -2,7 +2,7 @@ package pl.com.bottega.factory.shortages.prediction.calculation
|
||||
|
||||
import spock.lang.Specification
|
||||
|
||||
class ShortagesCalculationExamplesSpec extends Specification
|
||||
class ShortageCalculationExamplesSpec extends Specification
|
||||
implements ShortagesCalculationAssemblerTrait {
|
||||
|
||||
void setup() {
|
||||
@@ -1,7 +1,7 @@
|
||||
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 pl.com.bottega.factory.shortages.prediction.Shortage
|
||||
|
||||
import java.time.Duration
|
||||
import java.time.LocalDateTime
|
||||
@@ -12,13 +12,13 @@ trait ShortagesCalculationAssemblerTrait {
|
||||
String refNo = "3009000"
|
||||
SortedSet<LocalDateTime> times
|
||||
|
||||
Forecasts forecastProvider(Stock stock, DeliveriesForecast demands, ProductionOutputs outputs) {
|
||||
ShortageForecasts forecastProvider(Stock stock, DeliveriesForecast demands, ProductionOutputs outputs) {
|
||||
def forecast = forecast(stock, demands, outputs)
|
||||
return { RefNoId refNo, int daysAhead -> forecast } as Forecasts
|
||||
return { RefNoId refNo, int daysAhead -> forecast } as ShortageForecasts
|
||||
}
|
||||
|
||||
Forecast forecast(Stock stock, DeliveriesForecast demands, ProductionOutputs outputs) {
|
||||
new Forecast(refNo, now, times, stock, outputs, demands)
|
||||
ShortageForecast forecast(Stock stock, DeliveriesForecast demands, ProductionOutputs outputs) {
|
||||
new ShortageForecast(refNo, now, times, stock, outputs, demands)
|
||||
}
|
||||
|
||||
ProductionOutputs noProductions() {
|
||||
@@ -53,12 +53,12 @@ trait ShortagesCalculationAssemblerTrait {
|
||||
new Stock(level, locked)
|
||||
}
|
||||
|
||||
Optional<Shortages> noShortages() {
|
||||
Optional<Shortage> noShortages() {
|
||||
Optional.empty()
|
||||
}
|
||||
|
||||
Optional<Shortages> shortage(Map<LocalDateTime, Long> missing, long locked = 0) {
|
||||
def shortages = Shortages.builder(refNo, locked, now)
|
||||
Optional<Shortage> shortage(Map<LocalDateTime, Long> missing, long locked = 0) {
|
||||
def shortages = Shortage.builder(refNo, locked, now)
|
||||
|
||||
missing.each { time, level -> shortages.missing(time, level) }
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package pl.com.bottega.factory.shortages.prediction.monitoring
|
||||
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortages
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortage
|
||||
import pl.com.bottega.factory.shortages.prediction.calculation.TimeGrammar
|
||||
import spock.lang.Specification
|
||||
|
||||
@@ -18,11 +18,11 @@ class ShortageDiffPolicySpec extends Specification {
|
||||
given:
|
||||
def policy = ShortageDiffPolicy.ValuesAreNotSame
|
||||
|
||||
Shortages one = Shortages.builder("3009000", 0, now)
|
||||
Shortage one = Shortage.builder("3009000", 0, now)
|
||||
.missing(now + 1.day, 500L)
|
||||
.build().orElse(null)
|
||||
|
||||
Shortages another = Shortages.builder("3009000", 0, now + 5.min)
|
||||
Shortage another = Shortage.builder("3009000", 0, now + 5.min)
|
||||
.missing(now + 1.day, 500L)
|
||||
.build().orElse(null)
|
||||
|
||||
@@ -34,11 +34,11 @@ class ShortageDiffPolicySpec extends Specification {
|
||||
given:
|
||||
def policy = ShortageDiffPolicy.ValuesAreNotSame
|
||||
|
||||
Shortages one = Shortages.builder("3009000", 0, now)
|
||||
Shortage one = Shortage.builder("3009000", 0, now)
|
||||
.missing(now + 1.day, 500L)
|
||||
.build().orElse(null)
|
||||
|
||||
Shortages another = Shortages.builder("3009000", 1000, now)
|
||||
Shortage another = Shortage.builder("3009000", 1000, now)
|
||||
.missing(now + 1.day, 500L)
|
||||
.build().orElse(null)
|
||||
|
||||
@@ -50,11 +50,11 @@ class ShortageDiffPolicySpec extends Specification {
|
||||
given:
|
||||
def policy = ShortageDiffPolicy.ValuesAreNotSame
|
||||
|
||||
Shortages one = Shortages.builder("3009000XXX", 0, now)
|
||||
Shortage one = Shortage.builder("3009000XXX", 0, now)
|
||||
.missing(now + 1.day, 500L)
|
||||
.build().orElse(null)
|
||||
|
||||
Shortages another = Shortages.builder("3009000", 0, now)
|
||||
Shortage another = Shortage.builder("3009000", 0, now)
|
||||
.missing(now + 1.day, 500L)
|
||||
.build().orElse(null)
|
||||
|
||||
@@ -66,11 +66,11 @@ class ShortageDiffPolicySpec extends Specification {
|
||||
given:
|
||||
def policy = ShortageDiffPolicy.ValuesAreNotSame
|
||||
|
||||
Shortages one = Shortages.builder("3009000", 0, now)
|
||||
Shortage one = Shortage.builder("3009000", 0, now)
|
||||
.missing(now + 1.day, 500L)
|
||||
.build().orElse(null)
|
||||
|
||||
Shortages another = Shortages.builder("3009000", 0, now)
|
||||
Shortage another = Shortage.builder("3009000", 0, now)
|
||||
.missing(now + 1.day, 1500L)
|
||||
.build().orElse(null)
|
||||
|
||||
@@ -82,11 +82,11 @@ class ShortageDiffPolicySpec extends Specification {
|
||||
given:
|
||||
def policy = ShortageDiffPolicy.ValuesAreNotSame
|
||||
|
||||
Shortages one = Shortages.builder("3009000", 0, now)
|
||||
Shortage one = Shortage.builder("3009000", 0, now)
|
||||
.missing(now + 1.day, 500L)
|
||||
.build().orElse(null)
|
||||
|
||||
Shortages another = Shortages.builder("3009000", 0, now)
|
||||
Shortage another = Shortage.builder("3009000", 0, now)
|
||||
.missing(now + 1.day, 499L)
|
||||
.build().orElse(null)
|
||||
|
||||
@@ -98,11 +98,11 @@ class ShortageDiffPolicySpec extends Specification {
|
||||
given:
|
||||
def policy = ShortageDiffPolicy.ValuesAreNotSame
|
||||
|
||||
Shortages one = Shortages.builder("3009000", 0, now)
|
||||
Shortage one = Shortage.builder("3009000", 0, now)
|
||||
.missing(now + 1.day, 500L)
|
||||
.build().orElse(null)
|
||||
|
||||
Shortages another = Shortages.builder("3009000", 0, now)
|
||||
Shortage another = Shortage.builder("3009000", 0, now)
|
||||
.missing(now + 2.day, 500L)
|
||||
.build().orElse(null)
|
||||
|
||||
@@ -114,11 +114,11 @@ class ShortageDiffPolicySpec extends Specification {
|
||||
given:
|
||||
def policy = ShortageDiffPolicy.ValuesAreNotSame
|
||||
|
||||
Shortages one = Shortages.builder("3009000", 0, now)
|
||||
Shortage one = Shortage.builder("3009000", 0, now)
|
||||
.missing(now + 1.day, 500L)
|
||||
.build().orElse(null)
|
||||
|
||||
Shortages another = Shortages.builder("3009000", 0, now)
|
||||
Shortage another = Shortage.builder("3009000", 0, now)
|
||||
.missing(now + 1.day + 1.min, 500L)
|
||||
.build().orElse(null)
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ 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
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortage
|
||||
import pl.com.bottega.factory.shortages.prediction.calculation.ShortageForecasts
|
||||
import pl.com.bottega.factory.shortages.prediction.calculation.ShortagesCalculationAssembler
|
||||
import spock.lang.Specification
|
||||
|
||||
@@ -119,8 +119,8 @@ class ShortagePredictionProcessSpec extends Specification {
|
||||
}
|
||||
|
||||
ShortagePredictionProcess predictionProcess(
|
||||
Shortages previouslyFound,
|
||||
Forecasts forecastThatWillFindShortages) {
|
||||
Shortage previouslyFound,
|
||||
ShortageForecasts forecastThatWillFindShortages) {
|
||||
|
||||
new ShortagePredictionProcess(
|
||||
refNo,
|
||||
@@ -142,15 +142,15 @@ class ShortagePredictionProcessSpec extends Specification {
|
||||
(now.plusDays(1)) : 900L]
|
||||
}
|
||||
|
||||
Shortages noShortagesWasPreviouslyFound() {
|
||||
Shortage noShortagesWasPreviouslyFound() {
|
||||
null
|
||||
}
|
||||
|
||||
Shortages wasPreviouslyFound(Map<LocalDateTime, Long> shortages) {
|
||||
Shortage wasPreviouslyFound(Map<LocalDateTime, Long> shortages) {
|
||||
forecastAssembler.shortage(shortages).orElse(null)
|
||||
}
|
||||
|
||||
Forecasts noShortagesWillBeFound() {
|
||||
ShortageForecasts noShortagesWillBeFound() {
|
||||
forecastAssembler.forecastProvider(
|
||||
forecastAssembler.stock(1000),
|
||||
forecastAssembler.noDeliveries(),
|
||||
@@ -158,7 +158,7 @@ class ShortagePredictionProcessSpec extends Specification {
|
||||
)
|
||||
}
|
||||
|
||||
Forecasts willFindShortages(Map<LocalDateTime, Long> shortages) {
|
||||
ShortageForecasts willFindShortages(Map<LocalDateTime, Long> shortages) {
|
||||
forecastAssembler.forecastProvider(
|
||||
forecastAssembler.stock(0),
|
||||
forecastAssembler.deliveries(shortages),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
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.Shortage
|
||||
import pl.com.bottega.factory.shortages.prediction.monitoring.NewShortage
|
||||
import spock.lang.Specification
|
||||
|
||||
@@ -109,14 +109,14 @@ class NotificationOfShortageSpec extends Specification {
|
||||
)
|
||||
}
|
||||
|
||||
NewShortage newShortage(After after, Shortages shortages) {
|
||||
NewShortage newShortage(After after, Shortage shortages) {
|
||||
new NewShortage(new RefNoId(refNo), after, shortages)
|
||||
}
|
||||
|
||||
Shortages withShortage(
|
||||
Shortage withShortage(
|
||||
Duration firstShortageIn = Duration.ofDays(4),
|
||||
long lockedStock = 0) {
|
||||
Shortages.builder(refNo, lockedStock, now)
|
||||
Shortage.builder(refNo, lockedStock, now)
|
||||
.missing(now.plus(firstShortageIn), 500L)
|
||||
.build().get()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package pl.com.bottega.factory.shortages.prediction.notification
|
||||
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortages
|
||||
import pl.com.bottega.factory.shortages.prediction.Shortage
|
||||
import spock.lang.Specification
|
||||
|
||||
import java.time.Duration
|
||||
@@ -10,8 +10,8 @@ class RecoveryTaskPriorityChangePolicySpec extends Specification {
|
||||
|
||||
def now = LocalDateTime.now()
|
||||
|
||||
Shortages foundShortage(Duration firstShortageIn, long lockedStock) {
|
||||
Shortages.builder("3009000", lockedStock, now)
|
||||
Shortage foundShortage(Duration firstShortageIn, long lockedStock) {
|
||||
Shortage.builder("3009000", lockedStock, now)
|
||||
.missing(now.plus(firstShortageIn), 500L)
|
||||
.build().get()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user