mirror of
https://github.com/st-tu-dresden-praktikum/swt23w23
synced 2024-07-19 21:04:36 +02:00
Implement per-month employee working hours
Closes #76 Co-auther-by: Denis Natusch <denis.natusch@mailbox.tu-dresden.de>
This commit is contained in:
parent
e4d23d8e81
commit
580d3a6af6
|
@ -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
|
||||
|
|
BIN
src/main/asciidoc/models/design/order.svg
(Stored with Git LFS)
BIN
src/main/asciidoc/models/design/order.svg
(Stored with Git LFS)
Binary file not shown.
|
@ -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<YearMonth>): String
|
||||
+ getStaff(model: Model, form: StaffForm, month:Optional<YearMonth>): 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<Employee>
|
||||
+ delete(id: Long): void
|
||||
+ getAvailableStaffByJob(job: JobType, start:LocalDateTime, finish:LocalDateTime): Set<Employee>
|
||||
+ getWorkingHourseByemployee(e: Employee,month: YearMonth): double
|
||||
}
|
||||
StaffManagement --> StaffRepository : -staffRepository
|
||||
StaffManagement --> OrderManagement : -orderManagement
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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<YearMonth> 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";
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,11 +10,19 @@
|
|||
<div layout:fragment="content">
|
||||
<div>
|
||||
<h2>Mitarbeiterdetails</h2>
|
||||
<form th:action="@{/staff}" method="get">
|
||||
<div class="mb-3">
|
||||
<label for="month">Monat:</label>
|
||||
<input type="month" name="month" id="month" th:value="${month}" required>
|
||||
</div>
|
||||
<button class="btn btn-primary" type="submit">Zeitangabe aktualisieren</button>
|
||||
</form>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Beruf</th>
|
||||
<th>Lohn</th>
|
||||
<th>Arbeitszeit</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
|
@ -23,6 +31,7 @@
|
|||
<td th:text="${employee.name}">Max</td>
|
||||
<td th:text="${employee.job}">Koch</td>
|
||||
<td th:text="${employee.wage}"></td>
|
||||
<td th:with="month=${month}" th:text="${management.getWorkingHoursByEmployee(employee, month)}"></td>
|
||||
<td>
|
||||
<a th:href="@{'/staff/edit/' + ${employee.id}}"
|
||||
><button class="btn btn-warning">Bearbeiten</button></a
|
||||
|
|
|
@ -72,6 +72,7 @@ public class OrderControllerIntegrationTests {
|
|||
myUser = userAccountManagement.findByUsername("andi").get();
|
||||
admin = userAccountManagement.findByUsername("admin").get();
|
||||
|
||||
orderManagement.findAll(Pageable.unpaged()).forEach(orderManagement::delete);
|
||||
|
||||
if (orderManagement.findAll(Pageable.unpaged()).stream().findAny().isEmpty()) {
|
||||
myCart = new CustomCart(OrderType.EVENT_CATERING,
|
||||
|
|
|
@ -3,6 +3,7 @@ package catering.staff;
|
|||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.endsWith;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.salespointframework.core.Currencies.EURO;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
|
@ -11,19 +12,32 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.YearMonth;
|
||||
import java.util.Set;
|
||||
|
||||
import org.javamoney.moneta.Money;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.salespointframework.order.OrderManagement;
|
||||
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.data.domain.Pageable;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.security.test.context.support.WithAnonymousUser;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
|
||||
import catering.order.CustomCart;
|
||||
import catering.order.CustomOrder;
|
||||
import catering.order.OrderType;
|
||||
import catering.users.User;
|
||||
import catering.users.UserManagement;
|
||||
|
||||
@AutoConfigureMockMvc
|
||||
@SpringBootTest
|
||||
class StaffControllerIntegrationTests {
|
||||
|
@ -38,13 +52,44 @@ class StaffControllerIntegrationTests {
|
|||
@Autowired
|
||||
private StaffManagement staffManagement;
|
||||
|
||||
@Autowired
|
||||
private OrderManagement<CustomOrder> 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<Employee> 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 {
|
||||
|
|
Loading…
Reference in a new issue