From 580d3a6af690d7a5c97f789ba3c3be39a55525f9 Mon Sep 17 00:00:00 2001 From: Simon Bruder Date: Tue, 5 Dec 2023 15:21:22 +0100 Subject: [PATCH] Implement per-month employee working hours Closes #76 Co-auther-by: Denis Natusch --- src/main/asciidoc/models/design/order.puml | 8 +++ src/main/asciidoc/models/design/order.svg | 4 +- src/main/asciidoc/models/design/staff.puml | 5 +- src/main/java/catering/order/CustomOrder.java | 30 ++++++++++- .../java/catering/staff/StaffController.java | 13 +++-- .../java/catering/staff/StaffManagement.java | 7 +++ src/main/resources/templates/staff.html | 9 ++++ .../OrderControllerIntegrationTests.java | 1 + .../StaffControllerIntegrationTests.java | 53 +++++++++++++++++++ 9 files changed, 120 insertions(+), 10 deletions(-) diff --git a/src/main/asciidoc/models/design/order.puml b/src/main/asciidoc/models/design/order.puml index 814ada1..d472c86 100644 --- a/src/main/asciidoc/models/design/order.puml +++ b/src/main/asciidoc/models/design/order.puml @@ -25,7 +25,14 @@ package catering.order { class CustomOrder { - start : LocalDateTime - finish : LocalDateTime + + getDurationInSeconds(start:LocalDateTime,finish:LocalDateTime): long + + getDurationInHours(start:LocalDateTime,finish:LocalDateTime): long + + min(a:LocalDateTime,b:LocalDateTime): LocalDateTime + + max(b:LocalDateTime,b:LocalDateTime): LocalDateTime + + getDurationInSecondsDuringMonth(month:YearMonth): long } + CustomOrder ..> time.LocalDateTime + CustomOrder ..> time.YearMonth enum EventType { EVENT_CATERING @@ -72,6 +79,7 @@ OrderController .....> catering.orderCatalog.OrderCatalogEntry package time { class LocalDateTime class DateTimeFormatter + class YearMonth } @enduml diff --git a/src/main/asciidoc/models/design/order.svg b/src/main/asciidoc/models/design/order.svg index 7b43d2d..6cae087 100644 --- a/src/main/asciidoc/models/design/order.svg +++ b/src/main/asciidoc/models/design/order.svg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4d5942dc47a595446ca7779f16d44cc1eaeeef2a0fff408342fdcdc8323112b0 -size 41219 +oid sha256:083508e73bc8b109b9aca6756bcefacfa6aa65b23a92db12ff92e5f0dea2eb5e +size 42670 diff --git a/src/main/asciidoc/models/design/staff.puml b/src/main/asciidoc/models/design/staff.puml index 6d78088..a0ba8c7 100644 --- a/src/main/asciidoc/models/design/staff.puml +++ b/src/main/asciidoc/models/design/staff.puml @@ -47,8 +47,8 @@ package catering.staff { class StaffController { + StaffController(staffRepository: StaffRepository) - + getStaff(model: Model): String - + getStaff(model: Model, form: StaffForm): String + + getStaff(model: Model, month:Optional): String + + getStaff(model: Model, form: StaffForm, month:Optional): String + removeEmployee(employee: Employee, model: Model): String + addEmployee(form:StaffForm, result:Errors, model: Model): String + editEmployee(employee: Employee, model Model): String @@ -70,6 +70,7 @@ package catering.staff { + findAll(): Streamable + delete(id: Long): void + getAvailableStaffByJob(job: JobType, start:LocalDateTime, finish:LocalDateTime): Set + + getWorkingHourseByemployee(e: Employee,month: YearMonth): double } StaffManagement --> StaffRepository : -staffRepository StaffManagement --> OrderManagement : -orderManagement diff --git a/src/main/java/catering/order/CustomOrder.java b/src/main/java/catering/order/CustomOrder.java index 3724b9a..dfe8377 100644 --- a/src/main/java/catering/order/CustomOrder.java +++ b/src/main/java/catering/order/CustomOrder.java @@ -11,6 +11,7 @@ import org.springframework.data.annotation.Id; import javax.money.MonetaryAmount; import java.time.Duration; import java.time.LocalDateTime; +import java.time.YearMonth; import java.time.format.DateTimeFormatter; import java.util.HashSet; import java.util.Set; @@ -38,14 +39,39 @@ public class CustomOrder extends Order { this.formatterPattern = cart.getFormatterPattern(); } - public CustomOrder() {} + public CustomOrder() { } + + private long getDurationInSeconds(LocalDateTime start, LocalDateTime finish) { + if (start.compareTo(finish) > 0) { + return 0; + } + return Duration.between(start, finish).getSeconds(); + } /** * Helper function to get the amount of hours in between start and finish (analogous to CustomCart) * @return hours between start and finish */ + private long getDurationInHours(LocalDateTime start, LocalDateTime finish) { + return getDurationInSeconds(start, finish) / 3600; + } + public long getDurationInHours() { - return Duration.between(start, finish).getSeconds() / 3600; + return getDurationInHours(start, finish); + } + + private static LocalDateTime min(LocalDateTime a, LocalDateTime b) { + return (a.compareTo(b)) < 0 ? a : b; + } + + private static LocalDateTime max(LocalDateTime a, LocalDateTime b) { + return (a.compareTo(b)) > 0 ? a : b; + } + + public long getDurationInSecondsDuringMonth(YearMonth month) { + LocalDateTime startInMonth = max(this.start, month.atDay(1).atStartOfDay()); + LocalDateTime finishInMonth = min(this.finish, month.plusMonths(1).atDay(1).atStartOfDay()); + return getDurationInSeconds(startInMonth, finishInMonth); } /** diff --git a/src/main/java/catering/staff/StaffController.java b/src/main/java/catering/staff/StaffController.java index bb7aeb9..c965dff 100644 --- a/src/main/java/catering/staff/StaffController.java +++ b/src/main/java/catering/staff/StaffController.java @@ -2,6 +2,9 @@ package catering.staff; import static org.salespointframework.core.Currencies.EURO; +import java.time.YearMonth; +import java.util.Optional; + import org.javamoney.moneta.Money; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; @@ -26,13 +29,15 @@ public class StaffController { @GetMapping("/staff") @PreAuthorize("hasRole('ADMIN')") - public String getStaff(Model model) { - return getStaff(model, new StaffForm()); + public String getStaff(Model model, @RequestParam Optional month) { + return getStaff(model, new StaffForm(), month.orElseGet(YearMonth::now)); } - public String getStaff(Model model, @Valid StaffForm form) { + public String getStaff(Model model, @Valid StaffForm form, YearMonth month) { model.addAttribute("staff", staffManagement.findAll()); model.addAttribute("form", form); + model.addAttribute("month", month); + model.addAttribute("management", staffManagement); return "staff"; } @@ -41,7 +46,7 @@ public class StaffController { public String addEmployee(@Valid @ModelAttribute("form") StaffForm form, Errors result, Model model) { form.validate(result); if (result.hasErrors()) { - return getStaff(model, form); + return getStaff(model, form, YearMonth.now()); } staffManagement.save(new Employee(form.getName(), form.getJob(), Money.of(form.getWage(), EURO))); return "redirect:/staff"; diff --git a/src/main/java/catering/staff/StaffManagement.java b/src/main/java/catering/staff/StaffManagement.java index 3844946..2f48528 100644 --- a/src/main/java/catering/staff/StaffManagement.java +++ b/src/main/java/catering/staff/StaffManagement.java @@ -1,6 +1,7 @@ package catering.staff; import java.time.LocalDateTime; +import java.time.YearMonth; import java.util.Optional; import java.util.Set; import java.util.function.Predicate; @@ -104,4 +105,10 @@ public class StaffManagement { .collect(Collectors.toSet()); } + public double getWorkingHoursByEmployee(Employee e, YearMonth month) { + return orderManagement.findAll(Pageable.unpaged()).stream() + .filter(order -> order.getStaff().contains(e)) + .map(order -> order.getDurationInSecondsDuringMonth(month)) + .collect(Collectors.summingDouble(seconds -> (double) seconds / 3600)); + } } diff --git a/src/main/resources/templates/staff.html b/src/main/resources/templates/staff.html index c0a2491..075b502 100644 --- a/src/main/resources/templates/staff.html +++ b/src/main/resources/templates/staff.html @@ -10,11 +10,19 @@

Mitarbeiterdetails

+
+
+ + +
+ +
+ @@ -23,6 +31,7 @@ +
Name Beruf LohnArbeitszeit
Max Koch orderManagement; + + @Autowired + private UserManagement userManagement; + + @Autowired + private UserAccountManagement userAccountManagement; + Employee defaultEmployee; Long defaultEmployeeId; + User defaultCustomer; + Employee orderEmployee; + CustomOrder defaultStaffOrder; + + CustomOrder createCustomOrder(LocalDateTime start, LocalDateTime end, Set staff) { + CustomOrder order = orderManagement.save(new CustomOrder(defaultCustomer.getUserAccount().getId(), + new CustomCart(OrderType.EVENT_CATERING, start, end))); + staff.forEach(order::addEmployee); + return orderManagement.save(order); + } @BeforeEach void setup() throws Exception { + orderManagement.findAll(Pageable.unpaged()).forEach(orderManagement::delete); + staffManagement.findAll().map(Employee::getId).forEach(staffManagement::delete); + defaultEmployee = staffManagement.save(new Employee("Dieter Baum", JobType.COOK, Money.of(0, EURO))); defaultEmployeeId = defaultEmployee.getId(); + + if (userAccountManagement.findByUsername("hemming").isEmpty()) { + userManagement.createCustomer("hemming", "Nürnberger Platz", "123", "Hemming Quark"); + } + defaultCustomer = userManagement.getUserByName("hemming").get(); + + orderEmployee = staffManagement.save(new Employee("Tyler Baum", JobType.COOK, Money.of(10, EURO))); + defaultStaffOrder = createCustomOrder(LocalDateTime.of(2023, 12, 20, 10, 0), + LocalDateTime.of(2023, 12, 20, 21, 0), Set.of(orderEmployee)); } @AfterEach @@ -158,6 +203,14 @@ class StaffControllerIntegrationTests { .containsExactly("Dieter Baum", JobType.COOK); } + @Test + @WithMockUser(username = "admin", password = "admin", roles = "ADMIN") + void viewHoursesOfWork() throws Exception { + mvc.perform(get("/staff")) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("11.0"))); + } + @Test @WithMockUser(username = "dieter", password = "123", roles = "CUSTOMER") void refuseCustomer() throws Exception {