From 56f4ec0dda006c0bc21cff5a850be7e35200c1c2 Mon Sep 17 00:00:00 2001 From: CodeSteak Date: Fri, 12 Jun 2020 19:22:36 +0200 Subject: [PATCH 1/3] Implement Arrival of Supplier Order. --- .../warehouse/StoreSupplierOrderAction.java | 7 -- .../warehouse/SupplierOrderArrivedAction.java | 103 +++++++++++++++++ .../suppliers/SupplierOrderController.java | 104 +++++++++++++----- .../hso/ecommerce/entities/shop/Article.java | 2 +- .../repos/shop/ArticleRepository.java | 26 +++-- 5 files changed, 198 insertions(+), 44 deletions(-) delete mode 100644 prototype/src/main/java/org/hso/ecommerce/action/warehouse/StoreSupplierOrderAction.java create mode 100644 prototype/src/main/java/org/hso/ecommerce/action/warehouse/SupplierOrderArrivedAction.java diff --git a/prototype/src/main/java/org/hso/ecommerce/action/warehouse/StoreSupplierOrderAction.java b/prototype/src/main/java/org/hso/ecommerce/action/warehouse/StoreSupplierOrderAction.java deleted file mode 100644 index 9bc413d..0000000 --- a/prototype/src/main/java/org/hso/ecommerce/action/warehouse/StoreSupplierOrderAction.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.hso.ecommerce.action.warehouse; - -public class StoreSupplierOrderAction { - - //TODO add delivery date and warehouse booking - -} diff --git a/prototype/src/main/java/org/hso/ecommerce/action/warehouse/SupplierOrderArrivedAction.java b/prototype/src/main/java/org/hso/ecommerce/action/warehouse/SupplierOrderArrivedAction.java new file mode 100644 index 0000000..6dbd2d9 --- /dev/null +++ b/prototype/src/main/java/org/hso/ecommerce/action/warehouse/SupplierOrderArrivedAction.java @@ -0,0 +1,103 @@ +package org.hso.ecommerce.action.warehouse; + +import org.hso.ecommerce.entities.booking.BookingReason; +import org.hso.ecommerce.entities.shop.Article; +import org.hso.ecommerce.entities.supplier.SupplierOrder; +import org.hso.ecommerce.entities.warehouse.WarehouseBooking; +import org.hso.ecommerce.entities.warehouse.WarehouseBookingPosition; +import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +public class SupplierOrderArrivedAction { + + private final Article article; + private final ArrayList warehouseCandidates; + private final SupplierOrder order; + + public SupplierOrderArrivedAction(List warehouseCandidates, SupplierOrder order, Article article) { + this.warehouseCandidates = new ArrayList<>(warehouseCandidates); + this.order = order; + this.article = article; + } + + public Result finish() throws NoSpaceInWarehouseException { + // Sort for most filled slot first; + warehouseCandidates.sort((b, a) -> Integer.compare(a.newSumSlot, b.newSumSlot)); + + int needed = order.numberOfUnits; + + WarehouseBooking booking = new WarehouseBooking(); + booking.created = new Timestamp(new Date().getTime()); + booking.reason = new BookingReason(order); + + for (WarehouseBookingPositionSlotEntry entry : warehouseCandidates) { + int canBeAdded = article.warehouseUnitsPerSlot - entry.newSumSlot; + + if (canBeAdded == 0) { + // this slot is full, skip + continue; + } + + int willBeAdded = Math.min(canBeAdded, needed); + needed -= willBeAdded; + + WarehouseBookingPosition bookingPosition = new WarehouseBookingPosition(); + + bookingPosition.article = article; + bookingPosition.amount = willBeAdded; + bookingPosition.slotEntry = entry.copyAddAmount(willBeAdded); + bookingPosition.booking = booking; + + booking.positions.add(bookingPosition); + + if (needed == 0) { + break; + } + } + + if (needed > 0) { + throw new NoSpaceInWarehouseException(article); + } + + order.delivered = new Timestamp(new Date().getTime()); + return new Result(order, booking); + } + + public static class Result extends Exception { + + private final SupplierOrder order; + private final WarehouseBooking booking; + + public Result(SupplierOrder order, WarehouseBooking booking) { + this.order = order; + this.booking = booking; + } + + public SupplierOrder getOrder() { + return order; + } + + public WarehouseBooking getBooking() { + return booking; + } + } + + + public static class NoSpaceInWarehouseException extends Exception { + private Article article; + + public NoSpaceInWarehouseException(Article article) { + super("The quantity of article '" + article.title + "' does not fit in warehouse."); + this.article = article; + } + + public Article getArticle() { + return article; + } + } + +} diff --git a/prototype/src/main/java/org/hso/ecommerce/controller/intern/suppliers/SupplierOrderController.java b/prototype/src/main/java/org/hso/ecommerce/controller/intern/suppliers/SupplierOrderController.java index 1485c92..da67f9d 100644 --- a/prototype/src/main/java/org/hso/ecommerce/controller/intern/suppliers/SupplierOrderController.java +++ b/prototype/src/main/java/org/hso/ecommerce/controller/intern/suppliers/SupplierOrderController.java @@ -1,13 +1,14 @@ package org.hso.ecommerce.controller.intern.suppliers; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Optional; - +import org.hso.ecommerce.action.warehouse.SupplierOrderArrivedAction; +import org.hso.ecommerce.entities.shop.Article; import org.hso.ecommerce.entities.supplier.SupplierOrder; +import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry; +import org.hso.ecommerce.repos.shop.ArticleRepository; import org.hso.ecommerce.repos.supplier.SupplierOrderRepository; +import org.hso.ecommerce.repos.warehouse.SlotRepository; +import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository; +import org.hso.ecommerce.repos.warehouse.WarehouseBookingRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; @@ -15,7 +16,13 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.servlet.view.RedirectView; + +import javax.servlet.http.HttpServletResponse; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; @Controller @RequestMapping("/intern/") @@ -24,13 +31,26 @@ public class SupplierOrderController { @Autowired private final SupplierOrderRepository supplierOrderRepository = null; + @Autowired + private final ArticleRepository articleRepository = null; + + @Autowired + private final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null; + + @Autowired + private final WarehouseBookingRepository warehouseBookingRepository = null; + + @Autowired + private final SlotRepository slotRepository = null; + @GetMapping("supplierOrders") public String listSuppliers(Model model) { List totals = new ArrayList(); - for (SupplierOrder orders : supplierOrderRepository.findAll()) { - totals.add(new UImodelSupplierOrder(orders)); + for (SupplierOrder order : supplierOrderRepository.findAll()) { + final Article article = articleRepository.findArticleByArticleOffer(order.ordered).orElse(null); + totals.add(new UImodelSupplierOrder(order, article)); } model.addAttribute("orders", totals); @@ -39,20 +59,50 @@ public class SupplierOrderController { } @PostMapping("/supplierOrders/store/{id}") - public RedirectView storeOrder(@PathVariable(required = true) String id) { - - long supplierOrderID = Long.parseLong(id); - - Optional order = supplierOrderRepository.findById(supplierOrderID); - - if (order.isPresent()) { - // TODO call action - - System.out.println("Order is present\n"); - + public String storeOrder(@PathVariable("id") Long supplierOrderID, Model model, HttpServletResponse response) { + SupplierOrder order = supplierOrderRepository.findById(supplierOrderID).orElse(null); + if (order == null) { + model.addAttribute("error", "Die ausgewählte Lieferung konnte nicht gefunden werden."); + response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED); + return listSuppliers(model); + } + if (order.wasDelivered()) { + model.addAttribute("error", "Die ausgewählte Lieferung wurde schon zugestellt."); + response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED); + return listSuppliers(model); } - return new RedirectView("../../supplierOrders/"); + + final Article article = articleRepository.findArticleByArticleOffer(order.ordered).orElse(null); + if (order == null) { + model.addAttribute("error", "Der bestellte Artikel wurde nicht angelegt, er hätte nicht bestellt werden dürfen."); + response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED); + return listSuppliers(model); + } + + // Hard to do efficiently, this should be fine. + List candidates = slotRepository + .findAll() + .stream() + .map(slot -> + warehouseBookingPositionSlotEntryRepository.getBySlotNum(slot.slotNum).orElseGet(() -> + WarehouseBookingPositionSlotEntry.empty(article, slot) + ) + ) + .filter(entry -> entry.article.id == article.id) + .collect(Collectors.toList()); + + SupplierOrderArrivedAction action = new SupplierOrderArrivedAction(candidates, order, article); + + try { + SupplierOrderArrivedAction.Result result = action.finish(); + supplierOrderRepository.save(result.getOrder()); + warehouseBookingRepository.save(result.getBooking()); + } catch (SupplierOrderArrivedAction.NoSpaceInWarehouseException e) { + e.printStackTrace(); + } + + return "redirect:/intern/warehouse/todo"; } public class UImodelSupplierOrder { @@ -66,11 +116,11 @@ public class SupplierOrderController { public String priceTotal; public boolean arrived; - public UImodelSupplierOrder(SupplierOrder order) { + public UImodelSupplierOrder(SupplierOrder order, Article article) { this.id = order.id; this.supplierName = order.supplier.name; - this.articleName = order.ordered.title; - this.articleId = order.ordered.id; + this.articleName = article != null ? article.title : "error"; + this.articleId = article != null ? article.id : 0; this.priceNet = String.format("%.2f", ((float) order.pricePerUnitNetCent / 100)); this.quantity = String.valueOf(order.numberOfUnits); this.priceTotal = String.format("%.2f", ((float) order.totalPriceNet / 100)); @@ -79,11 +129,7 @@ public class SupplierOrderController { date.setTime(order.created.getTime()); this.dateOrder = new SimpleDateFormat("dd.MM.yyyy").format(date); - if (order.delivered != null) { - arrived = true; - } else { - arrived = false; - } + arrived = order.delivered != null; } } } diff --git a/prototype/src/main/java/org/hso/ecommerce/entities/shop/Article.java b/prototype/src/main/java/org/hso/ecommerce/entities/shop/Article.java index 355b5f9..d9fe69a 100644 --- a/prototype/src/main/java/org/hso/ecommerce/entities/shop/Article.java +++ b/prototype/src/main/java/org/hso/ecommerce/entities/shop/Article.java @@ -16,7 +16,7 @@ public class Article { @Basic public long id; - @ManyToOne(optional = false) + @OneToOne(optional = false) public ArticleOffer related; public int shopPricePerUnitNetCent; diff --git a/prototype/src/main/java/org/hso/ecommerce/repos/shop/ArticleRepository.java b/prototype/src/main/java/org/hso/ecommerce/repos/shop/ArticleRepository.java index a7f7597..0925ea0 100644 --- a/prototype/src/main/java/org/hso/ecommerce/repos/shop/ArticleRepository.java +++ b/prototype/src/main/java/org/hso/ecommerce/repos/shop/ArticleRepository.java @@ -1,6 +1,7 @@ package org.hso.ecommerce.repos.shop; import org.hso.ecommerce.entities.shop.Article; +import org.hso.ecommerce.entities.supplier.ArticleOffer; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @@ -12,24 +13,35 @@ import java.util.Optional; @Repository public interface ArticleRepository extends JpaRepository { - @Query("SELECT a FROM Article a WHERE a.id = :articleId") - Article findArticleById(@Param("articleId") long articleId); + /*** + * use findById instead. + */ + @Deprecated + @Query("SELECT a FROM Article a WHERE a.id = :articleId") + Article findArticleById(@Param("articleId") long articleId); - @Query("SELECT a FROM Article a") - List
findAll(); + @Query("SELECT a FROM Article a") + List
findAll(); @Query(value = "Select a.* from articles as a, article_offers as ao, warehouse_booking_position_entries as wbpe where a.related_id = ao.id and wbpe.article_id = a.id and ao.should_be_advertised = true group by wbpe.slot_id having max(wbpe.id) and wbpe.new_sum_slot != 0", nativeQuery = true) List
getAdvertisedArticles(); - @Query("SELECT a FROM CustomerOrderPosition cop JOIN cop.order co JOIN co.customer c JOIN cop.article a ORDER BY co.id DESC") - List
getOrderedArticles(); + @Query("SELECT a FROM CustomerOrderPosition cop JOIN cop.order co JOIN co.customer c JOIN cop.article a ORDER BY co.id DESC") + List
getOrderedArticles(); @Query("SELECT a FROM CustomerOrderPosition cop JOIN cop.order co JOIN co.customer c JOIN cop.article a WHERE c.id = :customerId ORDER BY co.id DESC") List
getOrderedArticles(long customerId); + /*** + * use type safe findArticleByArticleOffer instead. + */ + @Deprecated @Query(value = "SELECT a.id FROM articles a WHERE a.related_id = :relatedId", nativeQuery = true) Optional findArticleIDByRelatedID(@Param("relatedId") long relatedId); - + + @Query(value = "SELECT a FROM Article a Where a.related = :related") + Optional
findArticleByArticleOffer(ArticleOffer related); + @Query(value = "Select a.* from articles as a, warehouse_booking_position_entries as wbpe where wbpe.article_id = a.id and a.title LIKE %:term% group by wbpe.slot_id having max(wbpe.id) and wbpe.new_sum_slot != 0", nativeQuery = true) List
getArticlesByTermInTitle(String term); -- 2.47.1 From a664b42853b44e87d8130c977843510af7f4d8a0 Mon Sep 17 00:00:00 2001 From: CodeSteak Date: Fri, 12 Jun 2020 19:48:21 +0200 Subject: [PATCH 2/3] Allow reuse of empty warehouse slots. Also fixes #59 --- .../org/hso/ecommerce/action/shop/CreateOrderAction.java | 2 +- .../action/warehouse/CreateManuelBookingAction.java | 6 +++--- .../action/warehouse/SupplierOrderArrivedAction.java | 2 +- .../intern/suppliers/SupplierOrderController.java | 2 +- .../warehouse/WarehouseBookingPositionSlotEntry.java | 7 ++++++- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/prototype/src/main/java/org/hso/ecommerce/action/shop/CreateOrderAction.java b/prototype/src/main/java/org/hso/ecommerce/action/shop/CreateOrderAction.java index 8b35be8..8ff31ce 100644 --- a/prototype/src/main/java/org/hso/ecommerce/action/shop/CreateOrderAction.java +++ b/prototype/src/main/java/org/hso/ecommerce/action/shop/CreateOrderAction.java @@ -103,7 +103,7 @@ public class CreateOrderAction { bookingPosition.article = item.article; bookingPosition.amount = -remove; - bookingPosition.slotEntry = slot.copyAddAmount(-remove); + bookingPosition.slotEntry = slot.copyAddAmount(-remove, item.article); bookingPosition.booking = booking; booking.positions.add(bookingPosition); diff --git a/prototype/src/main/java/org/hso/ecommerce/action/warehouse/CreateManuelBookingAction.java b/prototype/src/main/java/org/hso/ecommerce/action/warehouse/CreateManuelBookingAction.java index 4d35e63..0a148b2 100644 --- a/prototype/src/main/java/org/hso/ecommerce/action/warehouse/CreateManuelBookingAction.java +++ b/prototype/src/main/java/org/hso/ecommerce/action/warehouse/CreateManuelBookingAction.java @@ -42,7 +42,7 @@ public class CreateManuelBookingAction { bookingPosition.article = article; bookingPosition.amount = -amount; - bookingPosition.slotEntry = source.get().copyAddAmount(-amount); + bookingPosition.slotEntry = source.get().copyAddAmount(-amount, article); if (bookingPosition.slotEntry.newSumSlot < 0 || bookingPosition.slotEntry.newSumSlot > article.warehouseUnitsPerSlot) { throw new ArticleSlotConstraintFailedException("The quantity of article can only be set in bounds."); @@ -53,7 +53,7 @@ public class CreateManuelBookingAction { if (destination.isPresent()) { - if (destination.get().article.id != article.id) { + if (destination.get().article.id != article.id && destination.get().newSumSlot > 0) { throw new ArticleSlotConstraintArticleTypeFailedException(); } @@ -62,7 +62,7 @@ public class CreateManuelBookingAction { bookingPosition.article = article; bookingPosition.amount = amount; - bookingPosition.slotEntry = destination.get().copyAddAmount(amount); + bookingPosition.slotEntry = destination.get().copyAddAmount(amount, article); if (bookingPosition.slotEntry.newSumSlot < 0 || bookingPosition.slotEntry.newSumSlot > article.warehouseUnitsPerSlot) { throw new ArticleSlotConstraintFailedException("The quantity of article can only be set in bounds."); diff --git a/prototype/src/main/java/org/hso/ecommerce/action/warehouse/SupplierOrderArrivedAction.java b/prototype/src/main/java/org/hso/ecommerce/action/warehouse/SupplierOrderArrivedAction.java index 6dbd2d9..dc361b0 100644 --- a/prototype/src/main/java/org/hso/ecommerce/action/warehouse/SupplierOrderArrivedAction.java +++ b/prototype/src/main/java/org/hso/ecommerce/action/warehouse/SupplierOrderArrivedAction.java @@ -49,7 +49,7 @@ public class SupplierOrderArrivedAction { bookingPosition.article = article; bookingPosition.amount = willBeAdded; - bookingPosition.slotEntry = entry.copyAddAmount(willBeAdded); + bookingPosition.slotEntry = entry.copyAddAmount(willBeAdded, article); bookingPosition.booking = booking; booking.positions.add(bookingPosition); diff --git a/prototype/src/main/java/org/hso/ecommerce/controller/intern/suppliers/SupplierOrderController.java b/prototype/src/main/java/org/hso/ecommerce/controller/intern/suppliers/SupplierOrderController.java index da67f9d..952427b 100644 --- a/prototype/src/main/java/org/hso/ecommerce/controller/intern/suppliers/SupplierOrderController.java +++ b/prototype/src/main/java/org/hso/ecommerce/controller/intern/suppliers/SupplierOrderController.java @@ -89,7 +89,7 @@ public class SupplierOrderController { WarehouseBookingPositionSlotEntry.empty(article, slot) ) ) - .filter(entry -> entry.article.id == article.id) + .filter(entry -> entry.article.id == article.id || entry.newSumSlot == 0) .collect(Collectors.toList()); SupplierOrderArrivedAction action = new SupplierOrderArrivedAction(candidates, order, article); diff --git a/prototype/src/main/java/org/hso/ecommerce/entities/warehouse/WarehouseBookingPositionSlotEntry.java b/prototype/src/main/java/org/hso/ecommerce/entities/warehouse/WarehouseBookingPositionSlotEntry.java index 5c7d909..15233df 100644 --- a/prototype/src/main/java/org/hso/ecommerce/entities/warehouse/WarehouseBookingPositionSlotEntry.java +++ b/prototype/src/main/java/org/hso/ecommerce/entities/warehouse/WarehouseBookingPositionSlotEntry.java @@ -25,7 +25,12 @@ public class WarehouseBookingPositionSlotEntry { @ManyToOne public Slot slot; - public WarehouseBookingPositionSlotEntry copyAddAmount(int amount) { + public WarehouseBookingPositionSlotEntry copyAddAmount(int amount, Article article) { + // Article can be changed if newSumSlot == 0. + if (this.newSumSlot != 0 && this.article.id != article.id) { + throw new IllegalArgumentException("Article does not match."); + } + WarehouseBookingPositionSlotEntry e = new WarehouseBookingPositionSlotEntry(); e.article = article; -- 2.47.1 From 7397698929892092e0a2f7546aceabaf36b82698 Mon Sep 17 00:00:00 2001 From: CodeSteak Date: Sat, 13 Jun 2020 11:54:25 +0200 Subject: [PATCH 3/3] fix check for missing article --- .../controller/intern/suppliers/SupplierOrderController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prototype/src/main/java/org/hso/ecommerce/controller/intern/suppliers/SupplierOrderController.java b/prototype/src/main/java/org/hso/ecommerce/controller/intern/suppliers/SupplierOrderController.java index 952427b..3259a17 100644 --- a/prototype/src/main/java/org/hso/ecommerce/controller/intern/suppliers/SupplierOrderController.java +++ b/prototype/src/main/java/org/hso/ecommerce/controller/intern/suppliers/SupplierOrderController.java @@ -74,7 +74,7 @@ public class SupplierOrderController { final Article article = articleRepository.findArticleByArticleOffer(order.ordered).orElse(null); - if (order == null) { + if (article == null) { model.addAttribute("error", "Der bestellte Artikel wurde nicht angelegt, er hätte nicht bestellt werden dürfen."); response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED); return listSuppliers(model); -- 2.47.1