Add basic order-staff-relation

Works on #73
This contains changes on multiple files to associate
multiple employees with an order and make customers
able to add employees to their order.
Because of SQL JPA things, this will not be final.
This commit is contained in:
Mathis Kral 2023-11-26 16:59:50 +01:00 committed by Mathis
parent d207386d1d
commit f50fbb5ac4
7 changed files with 149 additions and 26 deletions

View file

@ -1,15 +1,17 @@
package catering.order;
import catering.staff.Staff;
import org.javamoney.moneta.Money;
import org.salespointframework.order.Cart;
import javax.money.MonetaryAmount;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Set;
public class CustomCart extends Cart {
private Set<Staff> staff;
private final Set<Staff> staff;
private OrderType orderType;
private LocalDateTime start;
private LocalDateTime finish;
@ -29,6 +31,11 @@ public class CustomCart extends Cart {
* Adds an employee to the cart
*/
public boolean addStaff(Staff staff) {
for (Staff myStaff : this.staff) {
if (myStaff.equals(staff)) {
return false;
}
}
return this.staff.add(staff);
}
@ -37,7 +44,12 @@ public class CustomCart extends Cart {
}
public boolean removeStaff(Staff staff) {
return this.staff.remove(staff);
for (Staff myStaff : this.staff) {
if (myStaff.equals(staff)) {
return this.staff.remove(myStaff);
}
}
return false;
}
/**
@ -68,10 +80,10 @@ public class CustomCart extends Cart {
}
/**
* @return hours between start and finish
* @return hours between start and finish multiplied with a rate
*/
public long getDurationInHours(LocalDateTime start, LocalDateTime finish) {
return Duration.between(start, finish).getSeconds() / 3600;
public double getDurationInHoursTimesRate(double rate) {
return (float) Duration.between(start, finish).getSeconds() / 3600 * rate;
}
public LocalDateTime getFinish() {
@ -85,4 +97,21 @@ public class CustomCart extends Cart {
public String getFormatterPattern() {
return formatterPattern;
}
@Override
public MonetaryAmount getPrice() {
MonetaryAmount total = super.getPrice();
for (int i = 0; i < staff.size(); i++) { // TODO: get this from staff itself
total = total.add(Money.of(getDurationInHoursTimesRate(12.0), "EUR"));
}
return total;
}
@Override
public void clear() {
super.clear();
staff.forEach(staff::remove);
}
}

View file

@ -1,10 +1,7 @@
package catering.order;
import catering.staff.Staff;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.OneToMany;
import jakarta.persistence.*;
import org.javamoney.moneta.Money;
import org.salespointframework.order.Order;
import org.salespointframework.payment.Cash;
@ -23,7 +20,7 @@ public class CustomOrder extends Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany
@ManyToMany
private Set<Staff> staff;
private OrderType orderType = OrderType.SOMETHING_ELSE;
private LocalDateTime start;

View file

@ -1,18 +1,16 @@
package catering.order;
import jakarta.persistence.PostPersist;
import catering.staff.Staff;
import catering.staff.StaffManagement;
import org.salespointframework.catalog.Product;
import org.salespointframework.inventory.UniqueInventory;
import org.salespointframework.inventory.UniqueInventoryItem;
import org.salespointframework.order.*;
import org.salespointframework.quantity.Quantity;
import org.salespointframework.time.Interval;
import org.salespointframework.useraccount.Role;
import org.salespointframework.useraccount.UserAccount;
import org.salespointframework.useraccount.web.LoggedIn;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.query.Procedure;
import org.springframework.data.util.Streamable;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
@ -23,8 +21,6 @@ import java.time.LocalDateTime;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalUnit;
import java.util.*;
import java.util.stream.Collectors;
@ -36,16 +32,18 @@ public class OrderController {
private final OrderManagement<CustomOrder> orderManagement;
private final UniqueInventory<UniqueInventoryItem> inventory;
private final StaffManagement staffManagement;
public OrderController(OrderManagement<CustomOrder> orderManagement, UniqueInventory<UniqueInventoryItem> inventory) {
public OrderController(OrderManagement<CustomOrder> orderManagement, UniqueInventory<UniqueInventoryItem> inventory, StaffManagement staffManagement) {
this.orderManagement = orderManagement;
this.inventory = inventory;
this.staffManagement = staffManagement;
}
@GetMapping("/myOrders")
@PreAuthorize("hasRole('CUSTOMER')")
public String orders(Model model, @LoggedIn Optional<UserAccount> userAccount) {
List<CustomOrder> myOrders = orderManagement.findBy(userAccount.get()).stream().collect(Collectors.toList()); // to be changed
List<CustomOrder> myOrders = orderManagement.findBy(userAccount.get()).stream().collect(Collectors.toList());
model.addAttribute("orders", myOrders);
model.addAttribute("total", myOrders.size());
@ -70,7 +68,7 @@ public class OrderController {
@GetMapping("/allOrders/{day}")
@PreAuthorize("hasRole('ADMIN')")
public String orders(@PathVariable String day, Model model) {
// Obtains an instance of LocalDate from a text string such as 2007-12-03. (https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html)
// Obtains an instance of LocalDate from a text string such as 2007-12-03.
LocalDate date = LocalDate.parse(day);
List<CustomOrder> myOrders = orderManagement.findAll(Pageable.unpaged()).stream().filter(
@ -86,7 +84,8 @@ public class OrderController {
@ModelAttribute("event")
CustomCart initializeCart() {
return new CustomCart(OrderType.SOMETHING_ELSE, LocalDateTime.now().plusDays(7), LocalDateTime.now().plusDays(7));
return new CustomCart(OrderType.SOMETHING_ELSE, LocalDateTime.now().plusDays(7),
LocalDateTime.now().plusDays(7));
}
@GetMapping("/event")
@ -95,9 +94,35 @@ public class OrderController {
model.addAttribute("items", cart.stream().collect(Collectors.toList()));
model.addAttribute("totalPrice", cart.getPrice());
model.addAttribute("invItems", inventory.findAll().stream().collect(Collectors.toList()));
Set<Staff> myStaff = new HashSet<>();
staffManagement.findAll().forEach(myStaff::add);
model.addAttribute("allStaff", myStaff);
return "event";
}
@PostMapping("/event/addStaff")
@PreAuthorize("hasRole('CUSTOMER')")
String addStaffToCart(@RequestParam("sid") long staffId, @ModelAttribute("event") CustomCart cart) {
Staff staff = staffManagement.findById(staffId).get();
if (cart.getStaff().contains(staff)) {
return "redirect:/event";
}
cart.addStaff(staff);
return "redirect:/event";
}
@PostMapping("/event/removeStaff")
@PreAuthorize("hasRole('CUSTOMER')")
String removeStaffFromCart(@RequestParam("sid") long staffId, @ModelAttribute("event") CustomCart cart) {
Staff staff = staffManagement.findById(staffId).get();
cart.removeStaff(staff);
return "redirect:/event";
}
@PostMapping("/allOrders/remove")
@PreAuthorize("hasRole('ADMIN')")
public String removeOrder(@RequestParam Order.OrderIdentifier orderID, @LoggedIn Optional<UserAccount> userAccount) {
@ -146,8 +171,10 @@ public class OrderController {
int unwrappedFinishHour = finishHour.orElse(cart.getFinish().getHour());
finish = finish.isBefore(start) ? start : finish;
LocalDateTime startTime = LocalDateTime.of(start, LocalTime.of(unwrappedStartHour, 0)); // TODO
LocalDateTime finishTime = LocalDateTime.of(finish, LocalTime.of(unwrappedFinishHour <= unwrappedStartHour ? unwrappedStartHour+1 : unwrappedFinishHour, 0)); // TODO
LocalDateTime startTime = LocalDateTime.of(start, LocalTime.of(unwrappedStartHour, 0));
LocalDateTime finishTime = LocalDateTime.of(finish,
LocalTime.of(unwrappedFinishHour <= unwrappedStartHour
&& !finish.isAfter(start) ? unwrappedStartHour+1 : unwrappedFinishHour, 0));
cart.setStart(startTime);
cart.setFinish(finishTime);
@ -158,13 +185,14 @@ public class OrderController {
@PreAuthorize("hasRole('CUSTOMER')")
public String checkout(@ModelAttribute("event") CustomCart cart, @LoggedIn Optional<UserAccount> userAccount) {
if (cart.isEmpty()) {
if (cart.isEmpty() && cart.getStaff().isEmpty()) {
return "redirect:/event";
}
return userAccount.map(account -> {
CustomOrder myOrder = new CustomOrder(account.getId(), cart);
cart.addItemsTo(myOrder);
cart.addStaffTo(myOrder);
orderManagement.payOrder(myOrder); // TODO: change this later
orderManagement.completeOrder(myOrder);
cart.clear();

View file

@ -40,4 +40,12 @@ public class Staff {
public void setJob(JobType job) {
this.job = job;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Staff other) {
return id.equals(other.id);
}
return false;
}
}

View file

@ -49,7 +49,7 @@
<tr th:each="item : ${items}">
<td th:text="${item.getProductName()}">Sake Nigiri</td>
<td th:text="${item.getQuantity()}">200</td>
<td th:text="${item.getPrice()} +'€'">10€</td>
<td th:text="${item.getPrice().getNumber().doubleValue()} +'€'">10€</td>
<td>
<form method="post" th:action="@{/event/removeProduct}">
<input type="hidden" th:value="${item.getId()}" name="itemId"/>
@ -57,6 +57,21 @@
</form>
</td>
</tr>
<th>Angestellter</th>
<th>Typ</th>
<th>Preis</th>
<th></th>
<tr th:each="staff : ${event.getStaff()}">
<td th:text="${staff.getName()}">Name</td>
<td th:text="${staff.getJob()}">Job</td>
<td th:text="${event.getDurationInHoursTimesRate(12.0)} + '€'">Preis</td> <!--TODO: get from staff-->
<td>
<form method="post" th:action="@{/event/removeStaff}">
<input type="hidden" th:value="${staff.getId()}" name="sid"/>
<button class="btn btn-danger" type="submit">Angestellten entfernen</button>
</form>
</td>
</tr>
</table>
<span th:text="'Gesamt: ' + ${totalPrice}">Price</span>
@ -91,5 +106,28 @@
</td>
</tr>
</table>
<h4>Angestellte hinzufügen</h4>
<table class="table">
<tr>
<th>Name</th>
<th>Typ</th>
<th>Stundensatz</th>
<th>Verfügbar</th>
<td></td>
</tr>
<tr th:each="staff : ${allStaff}">
<td th:text="${staff.getName()}">Name</td>
<td th:text="${staff.getJob()}">Job</td>
<td th:text="'12€/h'">12€</td> <!--TODO: get from staff-->
<td style="color: green" th:text="Verfügbar">Verfügbar</td> <!--TODO: get from staff-->
<td>
<form th:action="@{/event/addStaff}" method="post">
<input type="hidden" name="sid" th:value="${staff.getId()}"/>
<input class="btn btn-primary" type="submit" th:value="Hinzufügen"/>
</form>
</td>
</tr>
</table>
</div>
</html>

View file

@ -10,7 +10,7 @@
<tr>
<th>Von</th>
<th>Bis</th>
<th>Kunde</th>
<th style="width: 14%">Kunde</th>
<th>Produktdetails</th>
<th>Rechnung</th>
<th>Status</th>
@ -31,6 +31,12 @@
<th:block th:text="'Preis: ' + ${orderLine.getPrice().getNumber().doubleValue() + ' €'}"/>
</li>
</ul>
<ul th:each="employee : ${order.getStaff()}">
<li>
<b th:text="${employee.getName()} + ', ' + ${employee.getJob()}"/><br>
<th:block th:text="'Preis: 12€/h'"/>
</li>
</ul>
</div>
</td>
<td>

View file

@ -1,5 +1,8 @@
package catering.order;
import catering.staff.JobType;
import catering.staff.Staff;
import catering.staff.StaffManagement;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.salespointframework.catalog.Product;
@ -45,10 +48,13 @@ public class OrderControllerIntegrationTests {
@Autowired
UserAccountManagement userAccountManagement;
@Autowired
StaffManagement staffManagement;
UserAccount myUser;
UserAccount admin;
CustomCart myCart;
Staff myStaff;
@BeforeEach
void setUp() {
@ -57,6 +63,9 @@ public class OrderControllerIntegrationTests {
Password.UnencryptedPassword.of("12345"), Role.of("CUSTOMER"));
}
myStaff = new Staff("Sabrina", JobType.SERVICE);
staffManagement.addStaff(myStaff);
myUser = userAccountManagement.findByUsername("andi").get();
admin = userAccountManagement.findByUsername("admin").get();
@ -177,4 +186,12 @@ public class OrderControllerIntegrationTests {
.andExpect(redirectedUrl("/event"));
}
@Test
@WithMockUser(username = "andi", roles = "CUSTOMER")
void addStaff() throws Exception {
mvc.perform(post("/event/addStaff")
.param("sid", myStaff.getId().toString()))
.andExpect(redirectedUrl("/event"));
}
}