orm entities and daos unified

This commit is contained in:
Michał Michaluk
2017-12-09 21:43:50 +01:00
parent c9e5c01e4c
commit 04970f2caa
39 changed files with 190 additions and 126 deletions

View File

@@ -98,6 +98,15 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>

View File

@@ -4,6 +4,7 @@ import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
import pl.com.bottega.factory.delivery.planning.definition.DeliveryPlannerDefinitionDao;
import pl.com.bottega.factory.delivery.planning.definition.DeliveryPlannerDefinitionEntity;
import pl.com.bottega.factory.product.management.RefNoId;
import java.util.Collections;
@@ -17,7 +18,7 @@ public class DeliveryAutoPlannerRepository {
public DeliveryAutoPlanner get(String refNo) {
return new DeliveryAutoPlanner(refNo,
ofNullable(dao.findOne(refNo))
ofNullable(dao.findByRefNo(refNo))
.map(DeliveryPlannerDefinitionEntity::getDefinition)
.map(x -> x.map(DeliveriesSuggestion::timesAndFractions))
.orElse(Collections.emptyMap()));

View File

@@ -1,12 +1,15 @@
package pl.com.bottega.factory.delivery.planning.definition;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.stereotype.Repository;
@Repository
@RepositoryRestResource(
path = "delivery/planning/definitions",
collectionResourceRel = "definitions for auto delivery planning")
public interface DeliveryPlannerDefinitionDao extends JpaRepository<DeliveryPlannerDefinitionEntity, String> {
path = "delivery-definitions", collectionResourceRel = "delivery-definitions")
public interface DeliveryPlannerDefinitionDao extends CrudRepository<DeliveryPlannerDefinitionEntity, Long> {
@RestResource(path = "refNos", rel = "refNos")
DeliveryPlannerDefinitionEntity findByRefNo(@Param("refNo") String refNo);
}

View File

@@ -5,21 +5,20 @@ import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import pl.com.bottega.tools.JsonConverter;
import javax.persistence.Column;
import javax.persistence.Convert;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.*;
import java.io.Serializable;
@Entity(name = "DeliveryPlannerDefinition")
@Data
@NoArgsConstructor
@EqualsAndHashCode(of = "refNo")
public class DeliveryPlannerDefinitionEntity {
public class DeliveryPlannerDefinitionEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column
private String refNo;
@Column
@Convert(converter = DescriptionAsJson.class)
private DeliveryPlannerDefinition definition;

View File

@@ -10,11 +10,10 @@ import java.time.LocalDate;
import java.util.List;
@Repository
@RepositoryRestResource(
path = "delivery/planning/forecasts",
collectionResourceRel = "forecast of deliveries")
@RepositoryRestResource(path = "delivery-forecasts", collectionResourceRel = "delivery-forecasts")
public interface DeliveryForecastDao extends ProjectionDao<DeliveryForecastEntity, Long> {
@RestResource(exported = false)
List<DeliveryForecastEntity> findByRefNoAndDateGreaterThanEqual(String refNo, Instant instant);
@RestResource(exported = false)

View File

@@ -5,6 +5,7 @@ import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
@@ -12,7 +13,8 @@ import java.time.LocalDateTime;
@Getter
@NoArgsConstructor
@EqualsAndHashCode(of = "id")
public class DeliveryForecastEntity {
public class DeliveryForecastEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

View File

@@ -24,7 +24,7 @@ public class DeliveryForecastProjection implements DemandEvents {
@Override
public void emit(DemandedLevelsChanged event) {
DeliveryAutoPlanner planner = planners.get(event.getRefNo());
DeliveryAutoPlanner planner = planners.get(event.getRefNo().getRefNo());
event.getResults().keySet()
.forEach(daily -> forecastDao.deleteByRefNoAndDate(
daily.getRefNo(),

View File

@@ -5,6 +5,7 @@ import pl.com.bottega.tools.JsonConverter;
import pl.com.bottega.tools.TechnicalId;
import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDate;
import java.util.Optional;
@@ -12,17 +13,15 @@ import java.util.Optional;
@Data
@NoArgsConstructor
@EqualsAndHashCode(of = "id")
public class DemandEntity {
public class DemandEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne
private ProductDemandEntity product;
@Column
private LocalDate date;
@Column
@Convert(converter = DemandAsJson.class)
private DemandValue value;

View File

@@ -4,7 +4,7 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import pl.com.bottega.factory.delivery.planning.projection.DeliveryForecastProjection;
import pl.com.bottega.factory.demand.forecasting.projection.CurrentDemandProjection;
import pl.com.bottega.factory.shortages.prediction.ShortagePredictionMapping;
import pl.com.bottega.factory.shortages.prediction.ShortagePredictionEventsMapping;
@Lazy
@Component
@@ -12,7 +12,7 @@ class DemandEventsMapping implements DemandEvents {
CurrentDemandProjection demands;
DeliveryForecastProjection deliveries;
ShortagePredictionMapping predictions;
ShortagePredictionEventsMapping predictions;
@Override
public void emit(DemandedLevelsChanged event) {

View File

@@ -74,12 +74,9 @@ class DemandORMRepository {
entity = demandDao.getOne(TechnicalId.get(updated.getId()));
} else {
entity = new DemandEntity(root, updated.getId().getDate());
}
entity.set(updated.getDocumented(), updated.getAdjustment());
if (!TechnicalId.isPersisted(updated.getId())) {
demandDao.save(entity);
}
entity.set(updated.getDocumented(), updated.getAdjustment());
}
}
}

View File

@@ -8,12 +8,13 @@ import pl.com.bottega.factory.product.management.RefNoId;
import pl.com.bottega.tools.TechnicalId;
import javax.persistence.*;
import java.io.Serializable;
@Entity(name = "ProductDemand")
@Data
@NoArgsConstructor
@EqualsAndHashCode(of = "id")
public class ProductDemandEntity {
public class ProductDemandEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@@ -28,23 +29,21 @@ public class ProductDemandEntity {
}
ProductDemandEntityId createId() {
return new ProductDemandEntityId(refNo, id, version);
return new ProductDemandEntityId(refNo, id);
}
@Getter
static class ProductDemandEntityId extends RefNoId implements TechnicalId {
Long id;
Long version;
ProductDemandEntityId(String refNo) {
super(refNo);
}
ProductDemandEntityId(String refNo, long id, Long version) {
ProductDemandEntityId(String refNo, long id) {
super(refNo);
this.id = id;
this.version = version;
}
}
}

View File

@@ -13,5 +13,4 @@ import java.util.List;
public interface DemandDao extends JpaRepository<DemandEntity, Long> {
List<DemandEntity> findByProductRefNoAndDateGreaterThanEqual(String refNo, LocalDate now);
}

View File

@@ -9,11 +9,10 @@ import java.time.LocalDate;
import java.util.List;
@Repository
@RepositoryRestResource(
path = "demand/forecasts",
collectionResourceRel = "forecast of customers demands")
@RepositoryRestResource(path = "demand-forecasts", collectionResourceRel = "demand-forecasts")
public interface CurrentDemandDao extends ProjectionDao<CurrentDemandEntity, Long> {
@RestResource(exported = false)
List<CurrentDemandEntity> findByRefNoAndDateGreaterThanEqual(String refNo, LocalDate date);
@RestResource(exported = false)

View File

@@ -6,13 +6,15 @@ import lombok.NoArgsConstructor;
import pl.com.bottega.factory.demand.forecasting.Demand;
import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDate;
@Entity(name = "CurrentDemand")
@Getter
@NoArgsConstructor
@EqualsAndHashCode(of = "id")
public class CurrentDemandEntity {
public class CurrentDemandEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

View File

@@ -5,18 +5,10 @@ import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
@RepositoryRestResource(
path = "product/management/descriptions",
collectionResourceRel = "descriptions of products")
public interface ProductDescriptionDao extends JpaRepository<ProductDescriptionEntity, String> {
@RestResource(exported = false)
default Optional<ProductDescription> description(String refNo) {
return Optional.ofNullable(findOne(refNo))
.map(ProductDescriptionEntity::getDescription);
}
path = "product-descriptions", collectionResourceRel = "product-descriptions")
public interface ProductDescriptionDao extends JpaRepository<ProductDescriptionEntity, Long> {
@RestResource(path = "refNos", rel = "refNos")
ProductDescriptionEntity findByRefNo(String refNo);
}

View File

@@ -5,21 +5,20 @@ import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import pl.com.bottega.tools.JsonConverter;
import javax.persistence.Column;
import javax.persistence.Convert;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.*;
import java.io.Serializable;
@Entity(name = "ProductDescription")
@Data
@NoArgsConstructor
@EqualsAndHashCode(of = "refNo")
public class ProductDescriptionEntity {
public class ProductDescriptionEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column
private String refNo;
@Column
@Convert(converter = DescriptionAsJson.class)
ProductDescription description;

View File

@@ -8,9 +8,7 @@ import java.time.LocalDate;
import java.util.List;
@Repository
@RepositoryRestResource(
path = "production/planning/outputs/daily",
collectionResourceRel = "forecast of production daily outputs")
@RepositoryRestResource(path = "production-outputs-daily", collectionResourceRel = "production-outputs-daily")
public interface ProductionDailyOutputDao extends ProjectionDao<ProductionDailyOutputEntity, Long> {
List<ProductionDailyOutputEntity> findByRefNoAndDateGreaterThanEqual(String refNo, LocalDate date);

View File

@@ -5,13 +5,14 @@ import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDate;
@Entity(name = "ProductionDailyOutput")
@Getter
@NoArgsConstructor
@EqualsAndHashCode(of = "id")
public class ProductionDailyOutputEntity {
@EqualsAndHashCode(of = "refNo")
public class ProductionDailyOutputEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)

View File

@@ -8,9 +8,7 @@ import java.time.Instant;
import java.util.List;
@Repository
@RepositoryRestResource(
path = "production/planning/outputs",
collectionResourceRel = "forecast of production outputs")
@RepositoryRestResource(path = "production-outputs", collectionResourceRel = "production-outputs")
public interface ProductionOutputDao extends ProjectionDao<ProductionOutputEntity, Long> {
List<ProductionOutputEntity> findByRefNoAndStartGreaterThanEqual(String refNo, Instant instant);

View File

@@ -5,14 +5,15 @@ import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.io.Serializable;
import java.time.Duration;
import java.time.LocalDateTime;
@Entity(name = "ProductionOutput")
@Getter
@NoArgsConstructor
@EqualsAndHashCode(of = "id")
public class ProductionOutputEntity {
@EqualsAndHashCode(of = "refNo")
public class ProductionOutputEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)

View File

@@ -7,10 +7,12 @@ import pl.com.bottega.factory.demand.forecasting.DemandEvents;
import pl.com.bottega.factory.shortages.prediction.monitoring.ShortagePredictionProcess;
import pl.com.bottega.factory.shortages.prediction.monitoring.ShortagePredictionProcessRepository;
import java.util.Set;
@Lazy
@Component
@AllArgsConstructor
public class ShortagePredictionMapping implements DemandEvents {
public class ShortagePredictionEventsMapping implements DemandEvents {
private ShortagePredictionProcessRepository repository;

View File

@@ -4,6 +4,7 @@ import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
import pl.com.bottega.factory.delivery.planning.projection.DeliveryForecastDao;
import pl.com.bottega.factory.delivery.planning.projection.DeliveryForecastEntity;
import pl.com.bottega.factory.product.management.RefNoId;
import pl.com.bottega.factory.production.planning.projection.ProductionOutputDao;
import pl.com.bottega.factory.shortages.prediction.calculation.ProductionForecast.Item;
import pl.com.bottega.factory.warehouse.WarehouseService;
@@ -28,13 +29,13 @@ class ForecastORMProvider implements Forecasts {
private Clock clock;
@Override
public Forecast get(String refNo, int daysAhead) {
public Forecast get(RefNoId refNo, int daysAhead) {
CurrentStock stock = stocks.forRefNo(refNo);
Instant now = Instant.now(clock);
LocalDateTime time = now.atZone(clock.getZone()).toLocalDateTime();
Map<LocalDateTime, Long> demands = this.demands
.findByRefNoAndDateGreaterThanEqual(refNo, now).stream()
.findByRefNoAndDateGreaterThanEqual(refNo.getRefNo(), now).stream()
.collect(toMap(
DeliveryForecastEntity::getTime,
DeliveryForecastEntity::getLevel
@@ -44,7 +45,7 @@ class ForecastORMProvider implements Forecasts {
Demands demand = new Demands(demands);
ProductionOutputs outputs = new ProductionForecast(
this.outputs.findByRefNoAndStartGreaterThanEqual(refNo, now).stream()
this.outputs.findByRefNoAndStartGreaterThanEqual(refNo.getRefNo(), now).stream()
.map(e -> new Item(
e.getStart(),
e.getDuration(),
@@ -52,6 +53,6 @@ class ForecastORMProvider implements Forecasts {
.collect(Collectors.toList())
).outputsInTimes(time, demands.keySet());
return new Forecast(refNo, time, times, stock, outputs, demand);
return new Forecast(refNo.getRefNo(), time, times, stock, outputs, demand);
}
}

View File

@@ -2,12 +2,13 @@ package pl.com.bottega.factory.shortages.prediction.monitoring;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
import pl.com.bottega.factory.product.management.RefNoId;
import pl.com.bottega.factory.shortages.prediction.Configuration;
import pl.com.bottega.factory.shortages.prediction.Shortages;
import pl.com.bottega.factory.shortages.prediction.calculation.Forecasts;
import pl.com.bottega.factory.shortages.prediction.notification.NotificationOfShortage;
import pl.com.bottega.tools.TechnicalId;
import static java.util.Optional.ofNullable;
import java.util.Optional;
@Component
@AllArgsConstructor
@@ -20,9 +21,12 @@ class ShortagePredictionProcessORMRepository implements ShortagePredictionProces
private final NotificationOfShortage notifications;
@Override
public ShortagePredictionProcess get(String refNo) {
public ShortagePredictionProcess get(RefNoId refNo) {
Optional<ShortagesEntity> entity = dao.findByRefNo(refNo.getRefNo());
return new ShortagePredictionProcess(
refNo, fetchData(refNo),
entity.map(ShortagesEntity::createId)
.orElseGet(() -> ShortagesEntity.createId(refNo)),
entity.map(ShortagesEntity::getShortages).orElse(null),
policy, forecasts, configuration, new EventsHandler()
);
}
@@ -32,26 +36,29 @@ class ShortagePredictionProcessORMRepository implements ShortagePredictionProces
// persisted after event
}
private Shortages fetchData(String refNo) {
return ofNullable(dao.findOne(refNo))
.map(ShortagesEntity::getShortages).orElse(null);
private void save(NewShortage event) {
RefNoId refNo = event.getRefNo();
ShortagesEntity entity = TechnicalId.findOrDefault(
refNo, dao::findOne,
() -> dao.save(new ShortagesEntity(refNo.getRefNo())));
entity.setShortages(event.getShortages());
notifications.emit(event);
}
private void delete(ShortageSolved event) {
dao.delete(TechnicalId.get(event.getRefNo()));
notifications.emit(event);
}
private class EventsHandler implements ShortageEvents {
@Override
public void emit(NewShortage event) {
String refNo = event.getShortages().getRefNo();
ShortagesEntity entity = ofNullable(dao.findOne(refNo))
.orElseGet(() -> new ShortagesEntity(refNo));
entity.setShortages(event.getShortages());
dao.save(entity);
notifications.emit(event);
save(event);
}
@Override
public void emit(ShortageSolved event) {
dao.delete(event.getRefNo());
notifications.emit(event);
delete(event);
}
}
}

View File

@@ -1,12 +1,16 @@
package pl.com.bottega.factory.shortages.prediction.monitoring;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.stereotype.Repository;
import pl.com.bottega.tools.ProjectionDao;
import java.util.Optional;
@Repository
@RepositoryRestResource(
path = "shortages/prediction/current",
collectionResourceRel = "predicted shortages")
public interface ShortagesDao extends ProjectionDao<ShortagesEntity, String> {
@RepositoryRestResource(path = "shortages", collectionResourceRel = "shortages")
public interface ShortagesDao extends ProjectionDao<ShortagesEntity, Long> {
@RestResource(path = "refNos", rel = "refNos")
Optional<ShortagesEntity> findByRefNo(@Param("refNo") String refNo);
}

View File

@@ -2,36 +2,63 @@ package pl.com.bottega.factory.shortages.prediction.monitoring;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import pl.com.bottega.factory.product.management.RefNoId;
import pl.com.bottega.factory.shortages.prediction.Shortages;
import pl.com.bottega.tools.JsonConverter;
import pl.com.bottega.tools.TechnicalId;
import javax.persistence.Column;
import javax.persistence.Convert;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.*;
import java.io.Serializable;
@Entity(name = "Shortage")
@Data
@NoArgsConstructor
@EqualsAndHashCode(of = "refNo")
class ShortagesEntity {
public class ShortagesEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Version
private Long version;
@Column
private String refNo;
@Column
@Column(length = 1024)
@Convert(converter = ShortagesAsJson.class)
Shortages shortages;
private Shortages shortages;
ShortagesEntity(String refNo) {
this.refNo = refNo;
}
RefNoId createId() {
return new ShortagesEntityId(refNo, id);
}
static RefNoId createId(RefNoId id) {
return id instanceof ShortagesEntityId ? id : new ShortagesEntityId(id.getRefNo());
}
public static class ShortagesAsJson extends JsonConverter<Shortages> {
public ShortagesAsJson() {
super(Shortages.class);
}
}
@Getter
static class ShortagesEntityId extends RefNoId implements TechnicalId {
Long id;
ShortagesEntityId(String refNo) {
super(refNo);
}
ShortagesEntityId(String refNo, long id) {
super(refNo);
this.id = id;
}
}
}

View File

@@ -7,9 +7,10 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import pl.com.bottega.factory.product.management.RefNoId;
@Controller
@RequestMapping("/stock/forecasts")
//@Controller
//@RequestMapping("/stock/forecasts")
@AllArgsConstructor
class StockForecastController {
@@ -18,6 +19,6 @@ class StockForecastController {
@RequestMapping(value = "/{refNo}", method = RequestMethod.GET)
@Transactional(readOnly = true)
ResponseEntity<StockForecast> get(@PathVariable("refNo") String refNo) {
return ResponseEntity.ok(query.get(refNo));
return ResponseEntity.ok(query.get(new RefNoId(refNo)));
}
}

View File

@@ -8,6 +8,7 @@ import pl.com.bottega.factory.demand.forecasting.projection.CurrentDemandEntity;
import pl.com.bottega.factory.product.management.ProductDescription;
import pl.com.bottega.factory.product.management.ProductDescriptionDao;
import pl.com.bottega.factory.product.management.ProductDescriptionEntity;
import pl.com.bottega.factory.product.management.RefNoId;
import pl.com.bottega.factory.production.planning.projection.ProductionDailyOutputDao;
import pl.com.bottega.factory.production.planning.projection.ProductionDailyOutputEntity;
import pl.com.bottega.factory.shortages.prediction.calculation.CurrentStock;
@@ -32,26 +33,26 @@ class StockForecastQuery {
private final ProductDescriptionDao descriptions;
private final Clock clock;
StockForecast get(String refNo) {
StockForecast get(RefNoId refNo) {
CurrentStock stock = stocks.forRefNo(refNo);
LocalDate today = LocalDate.now(clock);
return build(refNo, today, Optional.ofNullable(descriptions.findOne(refNo))
return build(refNo, today, Optional.ofNullable(descriptions.findByRefNo(refNo.getRefNo()))
.map(ProductDescriptionEntity::getDescription).orElse(null), stock,
this.demands
.findByRefNoAndDateGreaterThanEqual(refNo, today).stream()
.findByRefNoAndDateGreaterThanEqual(refNo.getRefNo(), today).stream()
.collect(toMap(
CurrentDemandEntity::getDate,
CurrentDemandEntity::getLevel
)),
this.outputs
.findByRefNoAndDateGreaterThanEqual(refNo, today).stream()
.findByRefNoAndDateGreaterThanEqual(refNo.getRefNo(), today).stream()
.collect(toMap(
ProductionDailyOutputEntity::getDate,
ProductionDailyOutputEntity::getOutput
)));
}
private StockForecast build(String refNo, LocalDate today,
private StockForecast build(RefNoId refNo, LocalDate today,
ProductDescription description, CurrentStock stock,
Map<LocalDate, Long> demands,
Map<LocalDate, Long> outputs) {
@@ -69,7 +70,7 @@ class StockForecastQuery {
));
}
return builder
.refNo(refNo)
.refNo(refNo.getRefNo())
.description(description)
.build();
}

View File

@@ -1,7 +1,8 @@
package pl.com.bottega.factory.warehouse;
import pl.com.bottega.factory.product.management.RefNoId;
import pl.com.bottega.factory.shortages.prediction.calculation.CurrentStock;
public interface WarehouseService {
CurrentStock forRefNo(String refNo);
CurrentStock forRefNo(RefNoId refNo);
}

View File

@@ -1,5 +1,8 @@
package pl.com.bottega.tools;
import java.util.function.Function;
import java.util.function.Supplier;
public interface TechnicalId {
Long getId();
@@ -9,10 +12,18 @@ public interface TechnicalId {
}
static Long get(Object id) {
return (id instanceof TechnicalId) ? ((TechnicalId) id).getId() : null;
return isPersisted(id) ? ((TechnicalId) id).getId() : null;
}
static boolean isPersisted(Object id) {
return (id instanceof TechnicalId) && ((TechnicalId) id).isPersisted();
}
static <T> T findOrDefault(Object id, Function<Long, T> ifPresent, Supplier<T> orElse) {
if (isPersisted(id)) {
return ifPresent.apply(get(id));
} else {
return orElse.get();
}
}
}

View File

@@ -3,6 +3,7 @@ package pl.com.bottega.factory.shortages.prediction.monitoring
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.annotation.Commit
import pl.com.bottega.factory.product.management.RefNoId
import pl.com.bottega.factory.shortages.prediction.Shortages
import pl.com.bottega.factory.shortages.prediction.calculation.Forecasts
import pl.com.bottega.factory.shortages.prediction.notification.NotificationOfShortage
@@ -18,8 +19,8 @@ import static pl.com.bottega.factory.shortages.prediction.monitoring.NewShortage
@Commit
class ShortagePredictionProcessORMRepositoryTest extends Specification {
LocalDateTime now = LocalDateTime.now()
String refNo = "3009000"
def now = LocalDateTime.now()
def refNo = "3009000"
@Autowired
ShortagesDao dao
@@ -93,15 +94,15 @@ class ShortagePredictionProcessORMRepositoryTest extends Specification {
}
Shortages shortagesCurrentlyPersisted() {
dao.findOne(refNo).shortages
dao.findByRefNo(refNo).get().shortages
}
void noShortagesPersisted() {
assert dao.findOne(refNo) == null
assert dao.findByRefNo(refNo) == Optional.empty()
}
ShortagePredictionProcess fetchProcess() {
repository.get(refNo)
repository.get(new RefNoId(refNo))
}
Shortages noShortages() {
@@ -127,10 +128,10 @@ class ShortagePredictionProcessORMRepositoryTest extends Specification {
}
void processEmitsNewShortage(ShortagePredictionProcess process, Shortages shortages) {
process.events.emit(new NewShortage(DemandChanged, shortages))
process.events.emit(new NewShortage(process.refNo, DemandChanged, shortages))
}
void processEmitsShortageSolved(ShortagePredictionProcess process) {
process.events.emit(new ShortageSolved(refNo))
process.events.emit(new ShortageSolved(process.refNo))
}
}

View File

@@ -19,8 +19,8 @@ public interface DemandEvents {
this.results = Collections.unmodifiableMap(results);
}
public String getRefNo() {
return id.getRefNo();
public RefNoId getRefNo() {
return id;
}
@Value

View File

@@ -1,5 +1,7 @@
package pl.com.bottega.factory.shortages.prediction.calculation;
import pl.com.bottega.factory.product.management.RefNoId;
public interface Forecasts {
Forecast get(String refNo, int daysAhead);
Forecast get(RefNoId refNo, int daysAhead);
}

View File

@@ -1,6 +1,7 @@
package pl.com.bottega.factory.shortages.prediction.monitoring;
import lombok.Value;
import pl.com.bottega.factory.product.management.RefNoId;
import pl.com.bottega.factory.shortages.prediction.Shortages;
/**
@@ -11,6 +12,7 @@ public class NewShortage {
public enum After {DemandChanged, PlanChanged, StockChanged, LockedParts}
RefNoId refNo;
After trigger;
Shortages shortages;
}

View File

@@ -1,6 +1,7 @@
package pl.com.bottega.factory.shortages.prediction.monitoring;
import lombok.AllArgsConstructor;
import pl.com.bottega.factory.product.management.RefNoId;
import pl.com.bottega.factory.shortages.prediction.Configuration;
import pl.com.bottega.factory.shortages.prediction.Shortages;
import pl.com.bottega.factory.shortages.prediction.calculation.Forecast;
@@ -15,7 +16,7 @@ import java.util.Optional;
@AllArgsConstructor
public class ShortagePredictionProcess {
private final String refNo;
private final RefNoId refNo;
private Shortages known;
private final ShortageDiffPolicy diffPolicy;
@@ -48,7 +49,7 @@ public class ShortagePredictionProcess {
boolean areDifferent = diffPolicy.areDifferent(this.known, newlyFound.orElse(null));
if (areDifferent && newlyFound.isPresent()) {
this.known = newlyFound.get();
events.emit(new NewShortage(event, newlyFound.get()));
events.emit(new NewShortage(refNo, event, known));
} else if (known != null && !newlyFound.isPresent()) {
this.known = null;
events.emit(new ShortageSolved(refNo));

View File

@@ -1,10 +1,12 @@
package pl.com.bottega.factory.shortages.prediction.monitoring;
import pl.com.bottega.factory.product.management.RefNoId;
/**
* Created by michal on 03.02.2017.
*/
public interface ShortagePredictionProcessRepository {
ShortagePredictionProcess get(String refNo);
ShortagePredictionProcess get(RefNoId refNo);
void save(ShortagePredictionProcess model);
}

View File

@@ -1,8 +1,9 @@
package pl.com.bottega.factory.shortages.prediction.monitoring;
import lombok.Value;
import pl.com.bottega.factory.product.management.RefNoId;
@Value
public class ShortageSolved {
String refNo;
RefNoId refNo;
}

View File

@@ -1,5 +1,6 @@
package pl.com.bottega.factory.shortages.prediction.calculation
import pl.com.bottega.factory.product.management.RefNoId
import pl.com.bottega.factory.shortages.prediction.Shortages
import java.time.Duration
@@ -13,7 +14,7 @@ trait ShortagesCalculationAssemblerTrait {
Forecasts forecastProvider(CurrentStock stock, Demands demands, ProductionOutputs outputs) {
def forecast = forecast(stock, demands, outputs)
return { String refNo, int daysAhead -> forecast } as Forecasts
return { RefNoId refNo, int daysAhead -> forecast } as Forecasts
}
Forecast forecast(CurrentStock stock, Demands demands, ProductionOutputs outputs) {

View File

@@ -1,5 +1,6 @@
package pl.com.bottega.factory.shortages.prediction.monitoring
import pl.com.bottega.factory.product.management.RefNoId
import pl.com.bottega.factory.shortages.prediction.Configuration
import pl.com.bottega.factory.shortages.prediction.Shortages
import pl.com.bottega.factory.shortages.prediction.calculation.Forecasts
@@ -8,11 +9,11 @@ import spock.lang.Specification
import java.time.LocalDateTime
import static pl.com.bottega.factory.shortages.prediction.monitoring.NewShortage.After;
import static pl.com.bottega.factory.shortages.prediction.monitoring.NewShortage.After
class ShortagePredictionProcessSpec extends Specification {
def refNo = "3009000"
def refNo = new RefNoId("3009000")
def now = LocalDateTime.now()
def forecastAssembler = new ShortagesCalculationAssembler(refNo: refNo, now: now)
def events = Mock(ShortageEvents)
@@ -170,7 +171,7 @@ class ShortagePredictionProcessSpec extends Specification {
}
NewShortage newShortage(After after, Map<LocalDateTime, Long> missing) {
new NewShortage(after, forecastAssembler.shortage(missing).get())
new NewShortage(refNo, after, forecastAssembler.shortage(missing).get())
}
ShortageSolved shortageSolved() {

View File

@@ -1,5 +1,6 @@
package pl.com.bottega.factory.shortages.prediction.notification
import pl.com.bottega.factory.product.management.RefNoId
import pl.com.bottega.factory.shortages.prediction.Shortages
import pl.com.bottega.factory.shortages.prediction.monitoring.NewShortage
import pl.com.bottega.factory.shortages.prediction.monitoring.ShortageSolved
@@ -107,7 +108,7 @@ class NotificationOfShortageSpec extends Specification {
def notificator = notificator()
when:
notificator.emit(new ShortageSolved(refNo))
notificator.emit(new ShortageSolved(new RefNoId(refNo)))
then:
0 * tasks.increasePriorityFor(_)
@@ -122,7 +123,7 @@ class NotificationOfShortageSpec extends Specification {
}
NewShortage newShortage(After after, Shortages shortages) {
new NewShortage(after, shortages)
new NewShortage(new RefNoId(refNo), after, shortages)
}
Shortages withShortage(