package catering.order; import jakarta.persistence.PostPersist; 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; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; 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; @Controller @PreAuthorize("isAuthenticated()") @SessionAttributes("event") public class OrderController { private final OrderManagement orderManagement; private final UniqueInventory inventory; public OrderController(OrderManagement orderManagement, UniqueInventory inventory) { this.orderManagement = orderManagement; this.inventory = inventory; } @GetMapping("/myOrders") @PreAuthorize("hasRole('CUSTOMER')") public String orders(Model model, @LoggedIn Optional userAccount) { List myOrders = orderManagement.findBy(userAccount.get()).stream().collect(Collectors.toList()); // to be changed model.addAttribute("orders", myOrders); model.addAttribute("total", myOrders.size()); model.addAttribute("cancelled", OrderStatus.CANCELED); model.addAttribute("completed", OrderStatus.COMPLETED); return "orders"; } @GetMapping("/allOrders") @PreAuthorize("hasRole('ADMIN')") public String orders(Model model) { List myOrders = orderManagement.findAll(Pageable.unpaged()).stream().collect(Collectors.toList()); model.addAttribute("orders", myOrders); model.addAttribute("total", myOrders.size()); model.addAttribute("cancelled", OrderStatus.CANCELED); model.addAttribute("completed", OrderStatus.COMPLETED); return "orders"; } // For Theo: filters orders by day @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) LocalDate date = LocalDate.parse(day); List myOrders = orderManagement.findAll(Pageable.unpaged()).stream().filter( order -> (order.getStart().toLocalDate().isBefore(date) || order.getStart().toLocalDate().isEqual(date)) && (order.getFinish().toLocalDate().isAfter(date) || order.getFinish().toLocalDate().isEqual(date)) ).collect(Collectors.toList()); model.addAttribute("orders", myOrders); model.addAttribute("total", myOrders.size()); return "orders"; } @ModelAttribute("event") CustomCart initializeCart() { return new CustomCart(OrderType.SOMETHING_ELSE, LocalDateTime.now().plusDays(7), LocalDateTime.now().plusDays(7)); } @GetMapping("/event") @PreAuthorize("hasRole('CUSTOMER')") public String event(Model model, @ModelAttribute("event") CustomCart cart) { model.addAttribute("items", cart.stream().collect(Collectors.toList())); model.addAttribute("totalPrice", cart.getPrice()); model.addAttribute("invItems", inventory.findAll().stream().collect(Collectors.toList())); return "event"; } @PostMapping("/allOrders/remove") @PreAuthorize("hasRole('ADMIN')") public String removeOrder(@RequestParam Order.OrderIdentifier orderID, @LoggedIn Optional userAccount) { return userAccount.map(account -> { if (account.hasRole(Role.of("ADMIN"))) { CustomOrder myOrder = orderManagement.get(orderID).get(); // FIXME orderManagement.cancelOrder(myOrder, "I have my own reasons."); return "redirect:/allOrders"; } return "redirect:/"; }).orElse("redirect:/"); } @PostMapping("/event/addProduct") @PreAuthorize("hasRole('CUSTOMER')") public String addProduct(@RequestParam("pid") Product product, @RequestParam("number") int number, @ModelAttribute("event") CustomCart cart) { Quantity amount = Quantity.of(number > 0 ? number : 1); Quantity invAmount = inventory.findByProduct(product).get().getQuantity(); // TODO ERROR HANDLING Quantity cartQuantity = cart.getQuantity(product); // check for possible miss-inputs if (amount.add(cartQuantity).isGreaterThan(invAmount)) { cart.addOrUpdateItem(product, cartQuantity.negate().add(invAmount)); } else { cart.addOrUpdateItem(product, amount); } return "redirect:/event"; } @PostMapping("/event/removeProduct") @PreAuthorize("hasRole('CUSTOMER')") public String removeProduct(@RequestParam("itemId") String itemId, @ModelAttribute("event") CustomCart cart) { cart.removeItem(itemId); return "redirect:/event"; } @PostMapping("/event/changeDate") @PreAuthorize("hasRole('CUSTOMER')") public String changeDate(@RequestParam("startDate") LocalDate start, @RequestParam("startHour") Optional startHour, @RequestParam("finishDate") LocalDate finish, @RequestParam("finishHour") Optional finishHour, @ModelAttribute("event") CustomCart cart) { int unwrappedStartHour = startHour.orElse(cart.getStart().getHour()); 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 cart.setStart(startTime); cart.setFinish(finishTime); return "redirect:/event"; } @PostMapping("/event/checkout") @PreAuthorize("hasRole('CUSTOMER')") public String checkout(@ModelAttribute("event") CustomCart cart, @LoggedIn Optional userAccount) { if (cart.isEmpty()) { return "redirect:/event"; } return userAccount.map(account -> { CustomOrder myOrder = new CustomOrder(account.getId(), cart); cart.addItemsTo(myOrder); orderManagement.payOrder(myOrder); // TODO: change this later orderManagement.completeOrder(myOrder); cart.clear(); return "redirect:/myOrders"; }).orElse("redirect:/event"); } @PostMapping("/event/changeOrderType") @PreAuthorize("hasRole('CUSTOMER')") public String changeOrderType(@RequestParam(name = "type") Optional optionalOrderType, @ModelAttribute("event") CustomCart cart) { String orderType = optionalOrderType.orElse("FOO"); switch (orderType) { case "RaK": cart.setOrderType(OrderType.RENT_A_COOK); break; case "EK": cart.setOrderType(OrderType.EVENT_CATERING); break; case "SN": cart.setOrderType(OrderType.SUSHI_NIGHT); break; case "MB": cart.setOrderType(OrderType.MOBILE_BREAKFAST); break; default: cart.setOrderType(OrderType.SOMETHING_ELSE); } return "redirect:/event"; } @GetMapping("/orders/calender") public String calender(Model model) { ArrayList> datesOfMonth = new ArrayList>(28); LocalDateTime startDateTime = LocalDateTime.now(); LocalDateTime endDateTime = startDateTime.plusDays(27).withHour(23).withMinute(59).withSecond(59); // FIXME: set me to end of day LocalDate startDate = startDateTime.toLocalDate(); LocalDate endDate = endDateTime.toLocalDate(); // create all dates of the calender for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) { ArrayList x = new ArrayList(2); x.add(Integer.toString(date.getDayOfMonth())); x.add(date.toString()); datesOfMonth.add(x); } /* * FIXME: Do not load all orders into java, * instead query orderManagement better to only return orders overlapping with interval [startDate,endDate] * by using "query creation" of the jpa * e.g. this.orderManagement.findByFinishDateIsNotBeforeAndStartDateIsNotAfter(LocalDateTime startDateTime, LocalDateTime endDateTime) */ Streamable x = this.orderManagement.findAll(Pageable.unpaged()).filter(e -> !e.getFinish().toLocalDate().isBefore(startDate) && // end is not before today !e.getStart().toLocalDate().isAfter(endDate) ); // add each order overlapping with the calendar to the days it overlaps with for (CustomOrder order : x) { int start_index_inclusive = Math.max((int) startDate.until(order.getStart().toLocalDate(), ChronoUnit.DAYS),0); int end_index_exclusive = Math.min((int) startDate.until(order.getFinish().toLocalDate(), ChronoUnit.DAYS), 27) + 1; String order_id = Objects.requireNonNull(order.getId()).toString(); for (int i = start_index_inclusive; i < end_index_exclusive; i++) { // FIXME: exchange order ids for a short name or a color datesOfMonth.get(i).add(order_id); } } // get names of weekdays for table header starting with the current day LocalDate endOfWeekDate = startDate.plusDays(6); ArrayList dayNames = new ArrayList(7); for (LocalDate date = startDate; !date.isAfter(endOfWeekDate); date = date.plusDays(1)) { dayNames.add(date.getDayOfWeek().toString()); } // FIXME: Get rid of the following paragraph of code by change of order_calender.html // put data of datesOfMonth inside current structure used in order_calender.html ArrayList>> weeksOfMonth = new ArrayList>>(); for (int i = 0; i < 4; i++) { weeksOfMonth.add(new ArrayList>(7)); for (int j = 0; j < 7; j++) { weeksOfMonth.get(i).add(new ArrayList()); weeksOfMonth.get(i).get(j).addAll(datesOfMonth.get( i*7+j ) ); } } model.addAttribute("weeksOfMonth", weeksOfMonth); model.addAttribute("dayNames", dayNames); return "orders_calender"; } }