Filter and distinguish products in orderCatalog

protocol-2024-01-19
Erik Hohlfeld 2024-01-12 16:21:54 +01:00 committed by Mathis
parent c94a4d4adb
commit 5aefd4e05f
17 changed files with 433 additions and 142 deletions

View File

@ -22,7 +22,7 @@ Files: src/main/asciidoc/models/analysis/*.svg
src/main/asciidoc/models/design/*.svg
src/main/asciidoc/models/mockups/*.svg
src/main/resources/banner.txt
Copyright: 2023 swt23w23
Copyright: 2023-2024 swt23w23
License: AGPL-3.0-or-later
# Small and/or autogenenerated files that cant be copyrighted

View File

@ -267,6 +267,7 @@ image:models/design/orderCatalog.svg[class design diagram - OrderCatalog]
|OrderCatalogController |A Spring MVC Controller to handle the event catalog
|OrderCatalogEntry |A class to save an event pack created by the administrator
|OrderCatalogEntryRepository |A repository to save all event packs in the form of OrderCatalogEntry
|CartService |A service class to make sure that Order and OrderCatalog use the same CustomCart object
|===
=== Order

View File

@ -1,5 +1,5 @@
' SPDX-License-Identifier: AGPL-3.0-or-later
' SPDX-FileCopyrightText: 2023 swt23w23
' SPDX-FileCopyrightText: 2023-2024 swt23w23
@startuml
skinparam linetype ortho
skinparam groupInheritance 2
@ -13,6 +13,7 @@ package Salespoint {
class Quantity
class UserAccount
class Product
class Inventory
}
package catering.order {
@ -23,34 +24,44 @@ package catering.orderCatalog {
class OrderCatalogController {
+ OrderCatalogController()
+ catalog(model : Model) : String
+ configureCatalog(model : Model) : String
+ catalogAdd(eventType : OrderCatalogEntry.EventType, minimumTimePeriod : int, totalCost : int, model : Model) : String
+ editCatalog(model : Model) : String
+ addCatalogEntry(eventType : OrderCatalogEntry.EventType, minimumTimePeriod : int, totalCost : int, model : Model) : String
+ removeEntry(catalogEntryID : int) : String
+ addProduct(name : String, amount : int, cost : double) : String
+ removeProduct(id : String, model : Model) : String
+ addTime(minimumTimePeriod : int, eventType : OrderCatalogEntry.EventType, products : Collection<Salespoint.Product>, model : Model) : String
+ chooseEvent(events : String) : String
+ addToCart(catalogEntryID : long) : String
}
class OrderCatalogEntry {
- id : Long
- eventType : OrderType
- products : Map<Salespoint.Product, Salespoint.Quantity>
- totalCost: double
+ OrderCatalogEntry()
+ getId() : int
+ getEventType() : EventType
+ getProducts() : Collection<Salespoint.Product>
+ getMinimumTimePeriod() : int
+ getTotalCost() : int
+ setEventType(eventType : EventType) : void
+ setMinimumTimePeriod(timePeriod : int) : void
+ setTotalCost(totalCost : int) : void
+ addProduct(name : String, count : Integer) : void
+ getId() : long
+ getEventType() : OrderType
+ getProducts() : Map<Salespoint.Product, Salespoint.Quantity>
+ getTotalCost() : double
+ setEventType(eventType : OrderType) : void
+ setTotalCost(totalCost : double) : void
+ addProduct(product : Salespoint.Product, count : Salespoint.Quantity) : void
+ setProducts(Map<Salespoint.Product, Salespoint.Quantity>) : void
}
class OrderCatalogEntryRepository {
interface OrderCatalogEntryRepository {
+ OrderCatalogEntryRepository()
+ addCatalogEntry(catalogEntry : OrderCatalogEntry) : boolean
+ removeCatalogEntry(catalogEntryID : int) : boolean
+ getCatalogEntries() : Set<OrderCatalogEntries>
}
class CartService {
- CustomCart cart
+ CartService()
+ getCart() : CustomCart
+ setCart(CustomCart cart) : void
}
}
OrderCatalogEntryRepository o---> OrderCatalogEntry
@ -62,5 +73,7 @@ OrderCatalogController ...> Salespoint.Cash
OrderCatalogController ...> Salespoint.Quantity
OrderCatalogController ...> Salespoint.UserAccount
OrderCatalogEntry ...> catering.order.EventType
CartService ...> catering.order.OrderController
OrderCatalogController ...> Salespoint.Inventory
@enduml

Binary file not shown.

View File

@ -2,6 +2,7 @@
// SPDX-FileCopyrightText: 2023-2024 swt23w23
package catering.inventory;
import catering.orderCatalog.CustomCatalogEntryRepository;
import org.salespointframework.catalog.Product;
import org.salespointframework.inventory.UniqueInventory;
import org.salespointframework.inventory.UniqueInventoryItem;
@ -50,12 +51,14 @@ import jakarta.validation.Valid;
class InventoryController {
private final UniqueInventory<UniqueInventoryItem> inventory;
private final CateringCatalog cateringCatalog;
private final CustomCatalogEntryRepository catalogEntryRepository;
InventoryController(UniqueInventory<UniqueInventoryItem> inventory, CateringCatalog cateringCatalog) {
InventoryController(UniqueInventory<UniqueInventoryItem> inventory, CateringCatalog cateringCatalog, CustomCatalogEntryRepository catalogEntryRepository) {
Assert.notNull(inventory, "Inventory must not be null!");
Assert.notNull(inventory, "CateringCatalog must not be null!");
this.inventory = inventory;
this.cateringCatalog = cateringCatalog;
this.catalogEntryRepository = catalogEntryRepository;
}
/**
@ -261,6 +264,7 @@ class InventoryController {
@GetMapping("/inventory/delete/{pid}")
String delete(@PathVariable Product pid) {
UniqueInventoryItem item = inventory.findByProduct(pid).get();
catalogEntryRepository.deleteAll(catalogEntryRepository.findByProduct(pid));
inventory.delete(item);
cateringCatalog.delete(pid);
return "redirect:/inventory";

View File

@ -5,6 +5,7 @@ package catering.order;
import catering.catalog.CateringCatalog;
import catering.catalog.Consumable;
import catering.catalog.Rentable;
import catering.orderCatalog.CartService;
import catering.staff.Employee;
import catering.staff.JobType;
import catering.staff.StaffManagement;
@ -17,6 +18,7 @@ import org.salespointframework.quantity.Quantity;
import org.salespointframework.useraccount.Role;
import org.salespointframework.useraccount.UserAccount;
import org.salespointframework.useraccount.web.LoggedIn;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
@ -44,16 +46,21 @@ public class OrderController {
private final CateringCatalog catalog;
private final StaffManagement staffManagement;
@Autowired
private CartService cartService;
public OrderController(OrderManagement<CustomOrder> orderManagement,
CustomOrderRepository customOrderRepository,
UniqueInventory<UniqueInventoryItem> inventory,
CateringCatalog catalog,
StaffManagement staffManagement) {
StaffManagement staffManagement,
CartService cartService) {
this.orderManagement = orderManagement;
this.customOrderRepository = customOrderRepository;
this.catalog = catalog;
this.inventory = inventory;
this.staffManagement = staffManagement;
this.cartService = cartService;
}
@GetMapping("/myOrders")
@ -109,8 +116,7 @@ public class OrderController {
@ModelAttribute("event")
CustomCart initializeCart() {
return new CustomCart(OrderType.EVENT_CATERING, LocalDateTime.now().plusDays(7),
LocalDateTime.now().plusDays(7).plusHours(1));
return cartService.getCart();
}
@GetMapping("/event")

View File

@ -0,0 +1,29 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
// SPDX-FileCopyrightText: 2023-2024 swt23w23
package catering.orderCatalog;
import catering.order.CustomCart;
import catering.order.OrderType;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
@Service
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class CartService {
private CustomCart cart;
public CartService() {
this.cart = new CustomCart(OrderType.EVENT_CATERING, LocalDateTime.now().plusDays(7),
LocalDateTime.now().plusDays(7).plusHours(1));
}
public CustomCart getCart() {
return cart;
}
public void setCart(CustomCart cart) {
this.cart = cart;
}
}

View File

@ -3,10 +3,14 @@
package catering.orderCatalog;
import catering.order.OrderType;
import catering.staff.Employee;
import catering.staff.StaffManagement;
import org.javamoney.moneta.Money;
import org.salespointframework.catalog.Product;
import org.salespointframework.inventory.UniqueInventory;
import org.salespointframework.inventory.UniqueInventoryItem;
import org.salespointframework.quantity.Quantity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@ -23,16 +27,20 @@ public class CatalogController {
private CustomCatalogEntry formCatalogEntry;
private final UniqueInventory<UniqueInventoryItem> inventory;
@Autowired
private CartService cartService;
public CatalogController(CustomCatalogEntryRepository catalogEntryRepository,
UniqueInventory<UniqueInventoryItem> inventory) {
UniqueInventory<UniqueInventoryItem> inventory,
CartService cartService) {
productMap = new HashMap<>();
formCatalogEntry = new CustomCatalogEntry(
OrderType.EVENT_CATERING,
new HashMap<String, Quantity>(),
0,
0);
new HashMap<Product, Quantity>(),
Money.of(0, "EUR"));
this.catalogEntryRepository = catalogEntryRepository;
this.inventory = inventory;
this.cartService = cartService;
}
@GetMapping("/catalog")
@ -42,34 +50,35 @@ public class CatalogController {
}
@GetMapping("/catalog_editor")
public String editCatalog(Model model) {;
public String editCatalog(Model model) {
model.addAttribute("productMap", productMap);
model.addAttribute("formCatalogEntry", formCatalogEntry);
model.addAttribute("inventory", inventory.findAll().stream().collect(Collectors.toList()));
model.addAttribute("inventory", inventory.findAll().stream()
.filter(i -> i.getProduct()
.getCategories()
.stream().anyMatch(c -> c.equals(formCatalogEntry.getEventType().toString())))
.collect(Collectors.toList()));
return "catalog_editor";
}
@PostMapping("/catalog_editor/addCatalogEntry")
public String addCatalogEntry(@RequestParam OrderType eventType,
@RequestParam int minimumTimePeriod,
@RequestParam int totalCost,
Model model) {
Map<String, Quantity> products = new HashMap<String, Quantity>();
@RequestParam double totalCost,
Model model) {
Map<Product, Quantity> products = new HashMap<Product, Quantity>();
for (Product product : productMap.keySet()) {
products.put(product.getName(), productMap.get(product));
products.put(product, productMap.get(product));
}
catalogEntryRepository.save(new CustomCatalogEntry(
eventType,
products,
minimumTimePeriod,
totalCost));
Money.of(totalCost, "EUR")));
this.formCatalogEntry = new CustomCatalogEntry(
OrderType.EVENT_CATERING,
new HashMap<String, Quantity>(),
0,
0);
new HashMap<Product, Quantity>(),
Money.of(0, "EUR"));
productMap.clear();
model.addAttribute("productMap", productMap);
model.addAttribute("formCatalogEntry", formCatalogEntry);
@ -86,10 +95,10 @@ public class CatalogController {
@PostMapping("/catalog_editor/addProduct")
public String addProduct(@RequestParam("pid") Product product, @RequestParam("number") int number) {
Quantity amount = Quantity.of(number);
productMap.compute(product, (key, existingQuantity) ->
(existingQuantity == null) ? amount : existingQuantity.add(amount));
formCatalogEntry.addProduct(product.getName(), amount);
Quantity amount = product.createQuantity(number);
productMap.compute(product,
(key, existingQuantity) -> (existingQuantity == null) ? amount : existingQuantity.add(amount));
formCatalogEntry.addProduct(product, amount);
return "redirect:/catalog_editor";
}
@ -107,31 +116,41 @@ public class CatalogController {
return "redirect:/catalog_editor";
}
@PostMapping("/catalog_editor/addTime")
public String addTime(@RequestParam int minimumTimePeriod,
@RequestParam OrderType eventType,
@RequestParam Map<String, Integer> products,
Model model) {
formCatalogEntry.setMinimumTimePeriod(minimumTimePeriod);
model.addAttribute("formCatalogEntry", formCatalogEntry);
return "redirect:/catalog_editor";
}
@PostMapping("/catalog_editor/chooseEvent")
public String chooseEvent(String events) {
switch (events) {
case "mobile_breakfast":
formCatalogEntry.setEventType(OrderType.MOBILE_BREAKFAST);
break;
case "rent_a_cook":
formCatalogEntry.setEventType(OrderType.RENT_A_COOK);
break;
default:
public String chooseEvent(String eventType) {
try {
formCatalogEntry.setEventType(OrderType.valueOf(eventType));
} catch (IllegalArgumentException e) {
formCatalogEntry.setEventType(OrderType.EVENT_CATERING);
break;
}
}
productMap.clear();
return "redirect:/catalog_editor";
}
@PostMapping("/catalog/addToCart")
public String addToCart(@RequestParam long catalogEntryID) {
if (cartService.getCart() == null) {
return "redirect:/event";
}
CustomCatalogEntry entry = catalogEntryRepository.findById(catalogEntryID).get();
for (Product product : entry.getProducts().keySet()) {
// Checks if inventory has sufficient Quantity of a Product
Quantity cartQuantity = cartService.getCart().getQuantity(product);
if (entry.getProducts().get(product).add(cartQuantity).isGreaterThan(
inventory.findByProduct(product).get().getQuantity())) {
cartService.getCart().addOrUpdateItem(
product,
inventory.findByProduct(product).get().getQuantity().subtract(cartQuantity));
} else {
cartService.getCart().addOrUpdateItem(
product,
entry.getProducts().get(product));
}
}
cartService.getCart().setOrderType(entry.getEventType());
return "redirect:/event";
}
}

View File

@ -4,9 +4,11 @@ package catering.orderCatalog;
import catering.order.OrderType;
import jakarta.persistence.*;
import org.javamoney.moneta.Money;
import org.salespointframework.catalog.Product;
import org.salespointframework.quantity.Quantity;
import java.util.Iterator;
import javax.money.MonetaryAmount;
import java.util.Map;
import java.util.Objects;
@ -19,14 +21,12 @@ public class CustomCatalogEntry {
private OrderType eventType;
@ElementCollection
private Map<String, Quantity> products;
private int minimumTimePeriod; // Declared as int for simplification of the prototype. Only whole hours.
private int totalCost; // Should actually accumulate the price of all items.
private Map<Product, Quantity> products;
private MonetaryAmount totalCost;
public CustomCatalogEntry(OrderType eventType, Map<String, Quantity> products, int minimumTimePeriod, int totalCost) {
public CustomCatalogEntry(OrderType eventType, Map<Product, Quantity> products, MonetaryAmount totalCost) {
this.eventType = eventType;
this.products = products;
this.minimumTimePeriod = minimumTimePeriod;
this.totalCost = totalCost;
}
@ -42,21 +42,16 @@ public class CustomCatalogEntry {
return eventType;
}
public Map<String, Quantity> getProducts() {
public Map<Product, Quantity> getProducts() {
return products;
}
public int getMinimumTimePeriod() {
return minimumTimePeriod;
}
public MonetaryAmount getTotalCost() {
MonetaryAmount totalCost = products.entrySet().stream()
.map(e -> e.getKey().getPrice().multiply(e.getValue().getAmount().doubleValue()))
.reduce(Money.of(0, "EUR"), MonetaryAmount::add);
public int getTotalCost() {
totalCost = 0;
Iterator<Quantity> iterator = products.values().iterator();
while (iterator.hasNext()) {
Quantity currentQuantity = iterator.next();
totalCost += currentQuantity.getAmount().intValue();
}
setTotalCost(totalCost);
return totalCost;
}
@ -64,18 +59,19 @@ public class CustomCatalogEntry {
this.eventType = eventType;
}
public void addProduct(String name, Quantity count) {
this.products.put(name, count);
public void addProduct(Product product, Quantity count) {
if (products.containsKey(product)) {
this.products.put(product, products.get(product).add(count));
} else {
this.products.put(product, count);
}
}
public void setProducts(Map<String, Quantity> products) {
public void setProducts(Map<Product, Quantity> products) {
this.products = products;
}
public void setMinimumTimePeriod(int timePeriod) {
this.minimumTimePeriod = timePeriod;
}
public void setTotalCost(int totalCost) {
public void setTotalCost(MonetaryAmount totalCost) {
this.totalCost = totalCost;
}

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 swt23w23
// SPDX-FileCopyrightText: 2023-2024 swt23w23
package catering.orderCatalog;
import catering.order.OrderType;
@ -7,43 +7,40 @@ import org.salespointframework.catalog.Product;
import org.salespointframework.core.DataInitializer;
import org.salespointframework.quantity.Quantity;
import org.springframework.stereotype.Component;
import org.salespointframework.inventory.UniqueInventory;
import org.salespointframework.inventory.UniqueInventoryItem;
import javax.money.CurrencyUnit;
import javax.money.Monetary;
import java.util.HashMap;
import java.util.Map;
import org.javamoney.moneta.Money;
@Component
public class CustomCatalogEntryDataInitializer implements DataInitializer {
private CustomCatalogEntryRepository catalogEntryRepository;
private final UniqueInventory<UniqueInventoryItem> inventory;
public CustomCatalogEntryDataInitializer(CustomCatalogEntryRepository catalogEntryRepository) {
public CustomCatalogEntryDataInitializer(CustomCatalogEntryRepository catalogEntryRepository, UniqueInventory<UniqueInventoryItem> inventory) {
this.catalogEntryRepository = catalogEntryRepository;
this.inventory = inventory;
}
@Override
public void initialize() {
Map<Product, Quantity> products = new HashMap<>();
CurrencyUnit currencyUnit = Monetary.getCurrency("EUR");
products.put(new Product("Brötchen", Monetary.getDefaultAmountFactory()
.setCurrency(currencyUnit)
.setNumber(1)
.create()), Quantity.of(30));
products.put(new Product("Kerze", Monetary.getDefaultAmountFactory()
.setCurrency(currencyUnit)
.setNumber(2)
.create()), Quantity.of(20));
Product product1 = inventory.findAll().stream().toList().get(0).getProduct();
Product product2 = inventory.findAll().stream().toList().get(1).getProduct();
Product product3 = inventory.findAll().stream().toList().get(2).getProduct();
products.put(product1, product1.createQuantity(30));
products.put(product2, product2.createQuantity(15));
products.put(product3, product3.createQuantity(1));
Map<String, Quantity> productsFormatted = new HashMap<String, Quantity>();
for (Product product : products.keySet()) {
productsFormatted.put(product.getName(), products.get(product));
}
catalogEntryRepository.save(
new CustomCatalogEntry(
OrderType.EVENT_CATERING,
productsFormatted,
4,
500));
products,
Money.of(500, "EUR")));
}
}

View File

@ -1,11 +1,16 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 swt23w23
// SPDX-FileCopyrightText: 2023-2024 swt23w23
package catering.orderCatalog;
import org.salespointframework.catalog.Product;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.util.Streamable;
interface CustomCatalogEntryRepository extends CrudRepository<CustomCatalogEntry, Long> {
public interface CustomCatalogEntryRepository extends CrudRepository<CustomCatalogEntry, Long> {
@Override
Streamable<CustomCatalogEntry> findAll();
@Query("SELECT entry FROM CustomCatalogEntry entry JOIN entry.products p WHERE KEY(p) = :product")
Streamable<CustomCatalogEntry> findByProduct(Product product);
}

View File

@ -14,22 +14,16 @@ SPDX-FileCopyrightText: 2023-2024 swt23w23
<div>
<table class="table">
<tr>
<th></th>
<th>Name</th>
<th>Mindestzeitraum</th>
<th>Eventtyp</th>
<th>Basisausstattung</th>
<th>Preis ab</th>
<th></th>
</tr>
<tr th:each="catalogEntry : ${catalogEntries}">
<td>
**BILD**
</td>
<td th:text="${catalogEntry.getEventType()}">
<td th:text="${catalogEntry.getMinimumTimePeriod()} + ' h'">
<td th:text="${catalogEntry.eventType.toHumanReadable()}">
<td>
<ul th:each="product : ${catalogEntry.getProducts()}">
<li th:text="${product.getKey().toString()} + ': ' + ${product.getValue().toString()}"/>
<li th:text="${product.getKey().getName()} + ': ' + ${product.getValue().toString()}"/>
</ul>
</td>
<td th:text="${catalogEntry.getTotalCost()}">
@ -39,6 +33,13 @@ SPDX-FileCopyrightText: 2023-2024 swt23w23
<button class="btn btn-danger" type="submit">Entfernen</button>
</form>
</td>
<td>
<form method="post" sec:authorize="hasRole('CUSTOMER')" th:action="@{/catalog/addToCart}">
<input type="hidden" name="catalogEntryID" th:value="${catalogEntry.getId()}">
<button class="btn btn-primary" type="submit">Zum Eventplaner hinzufügen</button>
</form>
</td>
<td></td>
</tr>
</table>
</div>

View File

@ -13,27 +13,15 @@ SPDX-FileCopyrightText: 2023-2024 swt23w23
<input type="hidden" name="addCatalog">
<div class="content">
<h2>Dienstleistung</h2>
<label class="form-label" for="events"></label>
<form th:object="${formCatalogEntry}" method="post" th:action="@{/catalog_editor/chooseEvent}">
<select class="form-select w-auto d-inline-block" name="events" id="events">
<option value="event_catering">Eventcatering</option>
<option value="mobile_breakfast">Mobile Breakfast</option>
<option value="rent_a_cook">Rent-a-Cook</option>
<form class="my-4" th:object="${formCatalogEntry}" method="post" th:action="@{/catalog_editor/chooseEvent}">
<select class="form-select w-auto d-inline-block" name="eventType">
<option th:selected="${formCatalogEntry.getEventType().toString() == enumValue.toString()}" th:each="enumValue : ${T(catering.order.OrderType).values()}" th:value="${enumValue.toString()}" th:text="${enumValue.toHumanReadable()}"/>
</select>
<button class="btn btn-secondary" type="submit">Event auswählen</button>
</form>
Eventbasispreis: EUR 500
<h2>Mindestzeitraum</h2>
<form th:object="${formCatalogEntry}" method="post" th:action="@{/catalog_editor/addTime}">
<label class="form-label">Mindestzeitraum:</label>
<input type="hidden" th:field="*{eventType}">
<input class="form-control w-auto d-inline-block" th:field="*{minimumTimePeriod}" type="number" min="0" step="1" value="1"/>
<button class="btn btn-secondary" type="submit">Zum Model hinzufügen</button>
</form>
<h2>Basisausstattung</h2>
<table class="table">
<table class="table my-4">
<tr>
<th>Produktname</th>
<th>Menge</th>
@ -51,15 +39,37 @@ SPDX-FileCopyrightText: 2023-2024 swt23w23
</td>
</tr>
</table>
<h2>Produktauswahl</h2>
<table class="table">
<h2 class="mb-4">Produktauswahl</h2>
<h3>Verbrauchsgegenstände</h3>
<table class="table my-4">
<tr>
<th>Produktname</th>
<th>Kosten</th>
<th>Verfügbar</th>
<th>Menge</th>
</tr>
<tr th:each="item : ${inventory}">
<tr th:each="item : ${inventory}" th:if="${item.getProduct().getClass().simpleName == 'Consumable'}">
<td th:text="${item.getProduct().getName()}">Name</td>
<td th:text="${item.getProduct().getPrice()}">Preis</td>
<td th:text="${item.getQuantity()}">Verfügbar</td>
<td>
<form th:action="@{/catalog_editor/addProduct}" method="post">
<input id="number" type="number" name="number" min="1" value="1"/>
<input type="hidden" name="pid" th:value="${item.getProduct().getId()}"/>
<input class="btn btn-primary" type="submit" th:value="Hinzufügen"/>
</form>
</td>
</tr>
</table>
<h3>Mietgegenstände</h3>
<table class="table my-4">
<tr>
<th>Produktname</th>
<th>Kosten</th>
<th>Verfügbar</th>
<th>Menge</th>
</tr>
<tr th:each="item : ${inventory}" th:if="${item.getProduct().getClass().simpleName == 'Rentable'}">
<td th:text="${item.getProduct().getName()}">Name</td>
<td th:text="${item.getProduct().getPrice()}">Preis</td>
<td th:text="${item.getQuantity()}">Verfügbar</td>
@ -72,16 +82,14 @@ SPDX-FileCopyrightText: 2023-2024 swt23w23
</td>
</tr>
</table>
<br>
<h3>Momentane Auswahl</h3>
Eventtyp: <span th:text="${formCatalogEntry.getEventType()}"></span><br>
Mindestzeitraum: <span th:text="${formCatalogEntry.getMinimumTimePeriod()} + ' h'"></span><br>
Eventtyp: <span th:text="${formCatalogEntry.getEventType().toHumanReadable()}"></span>
<br>
<span th:text="'Gesamtpreis: ' + ${formCatalogEntry.getTotalCost()}">Gesamtpreis</span>
<form method="post" th:action="@{/catalog_editor/addCatalogEntry}" th:object="${formCatalogEntry}">
<input type="hidden" name="eventType" th:value="${formCatalogEntry.getEventType()}">
<input type="hidden" name="products" th:value="${productSet}">
<input type="hidden" name="minimumTimePeriod" th:value="${formCatalogEntry.getMinimumTimePeriod}">
<input type="hidden" name="totalCost" th:value="${formCatalogEntry.getTotalCost()}">
<input type="hidden" name="totalCost" th:value="${formCatalogEntry.getTotalCost().getNumber().doubleValueExact()}">
<button class="btn btn-primary" type="submit">Zum Katalog hinzufügen</button>
</form>
</div>

View File

@ -25,6 +25,7 @@ import java.math.BigDecimal;
import java.util.Optional;
import java.util.Set;
import catering.orderCatalog.CustomCatalogEntryRepository;
import org.javamoney.moneta.Money;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -60,6 +61,9 @@ class InventoryControllerIntegrationTests {
@Autowired
CateringCatalog catalog;
@Autowired
private CustomCatalogEntryRepository catalogEntryRepository;
UniqueInventoryItem anyConsumableItem;
UniqueInventoryItem anyRentableItem;
Consumable anyConsumable;
@ -101,6 +105,7 @@ class InventoryControllerIntegrationTests {
@BeforeEach
void populateAnyInventoryItem() {
catalogEntryRepository.deleteAll();
inventory.deleteAll();
catalog.deleteAll();

View File

@ -0,0 +1,98 @@
package catering.orderCatalog;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
import java.util.HashMap;
import java.util.Map;
import org.javamoney.moneta.Money;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.salespointframework.catalog.Product;
import org.salespointframework.inventory.UniqueInventory;
import org.salespointframework.inventory.UniqueInventoryItem;
import org.salespointframework.quantity.Quantity;
import org.salespointframework.useraccount.Password;
import org.salespointframework.useraccount.Role;
import org.salespointframework.useraccount.UserAccountManagement;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;
import catering.order.OrderType;
@SpringBootTest
@AutoConfigureMockMvc
public class CatalogControllerIntegrationTests {
@Autowired
private MockMvc mockMvc;
@Autowired
private CatalogController catalogController;
@Autowired
UserAccountManagement userAccountManagement;
@Autowired
private CustomCatalogEntryRepository catalogEntryRepository;
@Autowired
private UniqueInventory<UniqueInventoryItem> inventory;
@BeforeEach
void setUp() {
if (userAccountManagement.findByUsername("anna").isEmpty()) {
userAccountManagement.create("anna",
Password.UnencryptedPassword.of("12345"), Role.of("CUSTOMER"));
}
if (catalogEntryRepository.findAll().isEmpty()) {
Map<Product, Quantity> products = new HashMap<>();
products.put(inventory.findAll().stream().toList().get(0).getProduct(), Quantity.of(1));
CustomCatalogEntry testCatalogEntry = new CustomCatalogEntry(
OrderType.RENT_A_COOK,
products,
Money.of(3000, "EUR"));
catalogEntryRepository.save(testCatalogEntry);
}
}
@Test
void testCustomerViewsCatalog() throws Exception {
this.mockMvc.perform(get("/catalog").with(user("anna").roles("CUSTOMER")))
.andExpect(status().isOk())
.andExpect(view().name("catalog"))
.andExpect(model().attributeExists("catalogEntries"));
}
@Test
@WithMockUser(username = "admin", roles = "ADMIN")
void testAddCatalogEntry() throws Exception {
this.mockMvc.perform(post("/catalog_editor/addCatalogEntry")
.param("eventType", "MOBILE_BREAKFAST")
.param("totalCost", "5000"))
.andExpect(redirectedUrl("/catalog"));
}
@Test
@WithMockUser(username = "admin", roles = "ADMIN")
void testRemoveCatalogEntry() throws Exception {
this.mockMvc.perform(post("/catalog/remove")
.param("catalogEntryID",
String.valueOf(catalogEntryRepository.findAll()
.stream().toList()
.get(0)
.getId())))
.andExpect(redirectedUrl("/catalog"));
}
}

View File

@ -0,0 +1,48 @@
package catering.orderCatalog;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.HashMap;
import java.util.Map;
import org.javamoney.moneta.Money;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.salespointframework.catalog.Product;
import org.salespointframework.inventory.UniqueInventory;
import org.salespointframework.inventory.UniqueInventoryItem;
import org.salespointframework.quantity.Quantity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import catering.order.OrderType;
@SpringBootTest
public class CatalogControllerUnitTests {
@Autowired
CustomCatalogEntryRepository catalogEntryRepository;
@Autowired
UniqueInventory<UniqueInventoryItem> inventory;
@BeforeEach
void setup() {
Product product1 = inventory.findAll().stream().toList().get(0).getProduct();
Map<Product, Quantity> products = new HashMap<Product, Quantity>();
products.put(product1, Quantity.of(1));
CustomCatalogEntry catalogEntry1 = new CustomCatalogEntry(
OrderType.EVENT_CATERING,
products,
Money.of(0, "EUR"));
catalogEntryRepository.save(catalogEntry1);
}
@Test
void countOfEntries() {
// Includes entry of data initializer
assertThat(catalogEntryRepository.findAll().stream().count()).isEqualTo(2);
}
}

View File

@ -0,0 +1,61 @@
package catering.orderCatalog;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.HashMap;
import java.util.Map;
import org.javamoney.moneta.Money;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.salespointframework.catalog.Product;
import org.salespointframework.inventory.UniqueInventory;
import org.salespointframework.inventory.UniqueInventoryItem;
import org.salespointframework.quantity.Quantity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import catering.order.OrderType;
@SpringBootTest
public class CatalogUnitTests {
@Autowired
CustomCatalogEntryRepository catalogEntryRepository;
@Autowired
UniqueInventory<UniqueInventoryItem> inventory;
private CustomCatalogEntry catalogEntry;
@BeforeEach
void setUp() {
Product product1 = inventory.findAll().stream().toList().get(0).getProduct();
Map<Product, Quantity> products = new HashMap<Product, Quantity>();
products.put(product1, Quantity.of(1));
this.catalogEntry = new CustomCatalogEntry(
OrderType.EVENT_CATERING,
products,
Money.of(0, "EUR"));
}
@Test
void testAddProduct() {
catalogEntry.addProduct(inventory.findAll().stream().toList().get(0).getProduct(), Quantity.of(1));
assertTrue(catalogEntry.getProducts().containsValue(Quantity.of(2)));
}
@Test
void testSetEventType() {
catalogEntry.setEventType(OrderType.PARTY_SERVICE);
assertTrue(catalogEntry.getEventType().equals(OrderType.PARTY_SERVICE));
}
// Getter is being tested because it calculates totalCost before
@Test
void testGetTotalCost() {
assertTrue(inventory.findAll().stream().toList().get(0).getProduct().getPrice()
.equals(catalogEntry.getTotalCost()));
}
}