mirror of
https://github.com/st-tu-dresden-praktikum/swt23w23
synced 2024-07-19 21:04:36 +02:00
Add getAvailableStaffByJob to staff package
Co-authored-by: Simon Bruder <simon.bruder@mailbox.tu-dresden.de>
This commit is contained in:
parent
2dff2842fc
commit
17a0e29dad
|
@ -10,6 +10,11 @@ package Spring {
|
||||||
class Model
|
class Model
|
||||||
}
|
}
|
||||||
|
|
||||||
|
package catering.order {
|
||||||
|
class OrderManagement
|
||||||
|
class CustomOrder
|
||||||
|
}
|
||||||
|
|
||||||
package catering.staff {
|
package catering.staff {
|
||||||
|
|
||||||
class Employee {
|
class Employee {
|
||||||
|
@ -48,13 +53,16 @@ package catering.staff {
|
||||||
StaffController ..> Errors
|
StaffController ..> Errors
|
||||||
|
|
||||||
class StaffManagement {
|
class StaffManagement {
|
||||||
+ StaffManagement(staffRepository: StaffRepository)
|
+ StaffManagement(staffRepository: StaffRepository, orderManagement:OrderManagement<CustomOrder>)
|
||||||
+ findById(id: Long): Optional<Employee>
|
+ findById(id: Long): Optional<Employee>
|
||||||
+ save(employee: Employee): Employee
|
+ save(employee: Employee): Employee
|
||||||
+ findAll(): Streamable<Employee>
|
+ findAll(): Streamable<Employee>
|
||||||
+ delete(id: Long): void
|
+ delete(id: Long): void
|
||||||
|
+ getAvailableStaffByJob(job: JobType, start:LocalDateTime, finish:LocalDateTime): Set<Employee>
|
||||||
}
|
}
|
||||||
StaffManagement --> StaffRepository : -staffRepository
|
StaffManagement --> StaffRepository : -staffRepository
|
||||||
|
StaffManagement --> OrderManagement : -orderManagement
|
||||||
|
StaffManagement ..> Set
|
||||||
|
|
||||||
interface StaffRepository {
|
interface StaffRepository {
|
||||||
+ findAll(): Streamable<Employee>
|
+ findAll(): Streamable<Employee>
|
||||||
|
|
BIN
src/main/asciidoc/models/design/staff.svg
(Stored with Git LFS)
BIN
src/main/asciidoc/models/design/staff.svg
(Stored with Git LFS)
Binary file not shown.
|
@ -2,6 +2,8 @@ package catering.staff;
|
||||||
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.validation.Errors;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
@ -10,9 +12,6 @@ import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
|
|
||||||
import org.springframework.ui.Model;
|
|
||||||
import org.springframework.validation.Errors;
|
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
public class StaffController {
|
public class StaffController {
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,19 @@
|
||||||
package catering.staff;
|
package catering.staff;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.salespointframework.order.OrderManagement;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.util.Streamable;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.bind.annotation.SessionAttributes;
|
import org.springframework.web.bind.annotation.SessionAttributes;
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.data.util.Streamable;
|
import catering.order.CustomOrder;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Transactional
|
@Transactional
|
||||||
|
@ -12,9 +21,11 @@ import org.springframework.data.util.Streamable;
|
||||||
public class StaffManagement {
|
public class StaffManagement {
|
||||||
|
|
||||||
private final StaffRepository staffRepository;
|
private final StaffRepository staffRepository;
|
||||||
|
private final OrderManagement<CustomOrder> orderManagement;
|
||||||
|
|
||||||
public StaffManagement(StaffRepository staffRepository) {
|
public StaffManagement(StaffRepository staffRepository, OrderManagement<CustomOrder> orderManagement) {
|
||||||
this.staffRepository = staffRepository;
|
this.staffRepository = staffRepository;
|
||||||
|
this.orderManagement = orderManagement;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Employee> findById(Long id) {
|
public Optional<Employee> findById(Long id) {
|
||||||
|
@ -33,4 +44,64 @@ public class StaffManagement {
|
||||||
staffRepository.deleteById(id);
|
staffRepository.deleteById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a {@link Set} of all {@link Employee}s of given {@link JobType}
|
||||||
|
* available in the full time range between the given start and end
|
||||||
|
* {@link LocalDateTime}s.
|
||||||
|
*
|
||||||
|
* The range is inclusive, e.g., {@link Employee}s part of an order that lasts
|
||||||
|
* until the given start
|
||||||
|
* are not considered available.
|
||||||
|
*
|
||||||
|
* @param job the {@link JobType} of {@link Employee}s to search for
|
||||||
|
* @param start a {@link LocalDateTime} describing the start of the range the
|
||||||
|
* employee is needed for
|
||||||
|
* @param finish a {@link LocalDateTime} describing the end of the range the
|
||||||
|
* employee is needed for
|
||||||
|
* @return a {@link Set} of {@link Employee}s matching the requirements
|
||||||
|
*/
|
||||||
|
public Set<Employee> getAvailableStaffByJob(JobType job, LocalDateTime start, LocalDateTime finish) {
|
||||||
|
/*
|
||||||
|
* This function first computes all unavailable employees
|
||||||
|
* to then later take the set difference of all employees and the previous
|
||||||
|
* result
|
||||||
|
* to get a set of all employees available in the given range.
|
||||||
|
*/
|
||||||
|
Set<Employee> unavailable = orderManagement.findAll(Pageable.unpaged()).stream()
|
||||||
|
/*
|
||||||
|
* The most complex part is getting all orders overlapping the given range.
|
||||||
|
* It can be computed with the following:
|
||||||
|
* Let (S, F) be the tuple describing the start and finish of any given order O,
|
||||||
|
* let (S', F') be the tuple describing the start and finish of the given date range.
|
||||||
|
* Then the following holds:
|
||||||
|
*
|
||||||
|
* @formatter:off
|
||||||
|
* O overlaps with (S', F')
|
||||||
|
* ⇔ F ≥ S' ∧ S ≤ F'
|
||||||
|
* ⇔ ¬¬(F ≥ S' ∧ S ≤ F') (¬¬X ⇔ X ∀ X ∈ {0,1})
|
||||||
|
* ⇔ ¬(¬(F ≥ S') ∨ ¬(S ≤ F')) (De Morgan’s laws: ¬(X ∧ Y) ⇔ ¬X ∨ ¬Y ∀ X,Y ∈ {0,1})
|
||||||
|
* ⇔ ¬(F < S' ∨ S > F') (¬(a ≥ b) ⇔ a < b and ¬(a ≤ b) ⇔ a > b ∀ a,b totally ordered)
|
||||||
|
* ⇔ ¬(F < S') ∧ ¬(S > F') (De Morgan’s laws: ¬(X ∨ Y) ⇔ ¬X ∧ ¬Y ∀ X,Y ∈ {0,1})
|
||||||
|
* @formatter:on
|
||||||
|
*
|
||||||
|
* The last expression can be easily implemented with two filters,
|
||||||
|
* as chaining filters is equivalent to the logical conjunction,
|
||||||
|
* using LocalDateTime::isBefore and LocalDateTime::isAfter,
|
||||||
|
* which are < and > on the total ordering of all LocalDateTimes.
|
||||||
|
*
|
||||||
|
* Sadly, we can’t really avoid lambdas here
|
||||||
|
* as function composition and partial application are not first-class citizens in Java.
|
||||||
|
*/
|
||||||
|
.filter(order -> !order.getFinish().isBefore(start))
|
||||||
|
.filter(order -> !order.getStart().isAfter(finish))
|
||||||
|
.map(CustomOrder::getStaff)
|
||||||
|
.flatMap(Set::stream)
|
||||||
|
.filter(employee -> employee.getJob().equals(job))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
return findAll().stream()
|
||||||
|
.filter(e -> e.getJob().equals(job))
|
||||||
|
.filter(Predicate.not(unavailable::contains))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
package catering.staff;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.salespointframework.order.OrderManagement;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
import catering.order.CustomCart;
|
||||||
|
import catering.order.CustomOrder;
|
||||||
|
import catering.order.OrderType;
|
||||||
|
import catering.users.User;
|
||||||
|
import catering.users.UserManagement;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
class StaffManagmentIntegratonTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private StaffManagement staffManagement;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OrderManagement<CustomOrder> orderManagement;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserManagement userManagement;
|
||||||
|
|
||||||
|
private User defaultUser;
|
||||||
|
|
||||||
|
Employee e1;
|
||||||
|
Employee e2;
|
||||||
|
Employee e3;
|
||||||
|
Employee e4;
|
||||||
|
Employee e5;
|
||||||
|
Employee e6;
|
||||||
|
|
||||||
|
CustomOrder c1;
|
||||||
|
CustomOrder c2;
|
||||||
|
CustomOrder c3;
|
||||||
|
CustomOrder c4;
|
||||||
|
CustomOrder c5;
|
||||||
|
CustomOrder c6;
|
||||||
|
CustomOrder c7;
|
||||||
|
|
||||||
|
CustomOrder createCustomOrder(LocalDateTime start, LocalDateTime end, Set<Employee> staff) {
|
||||||
|
CustomOrder order = orderManagement.save(new CustomOrder(defaultUser.getUserAccount().getId(),
|
||||||
|
new CustomCart(OrderType.EVENT_CATERING, start, end)));
|
||||||
|
staff.forEach(order::addEmployee);
|
||||||
|
return orderManagement.save(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void addEmployees() {
|
||||||
|
defaultUser = userManagement.createCustomer("sarah", "Baum Weg", "123", "Sarah Klaus");
|
||||||
|
|
||||||
|
e1 = staffManagement.save(new Employee("Alan Turing", JobType.COOK));
|
||||||
|
e2 = staffManagement.save(new Employee("Ada Lovelace", JobType.COOK));
|
||||||
|
e3 = staffManagement.save(new Employee("Donald Knuth", JobType.COOK));
|
||||||
|
e4 = staffManagement.save(new Employee("Grace Hopper", JobType.SERVICE));
|
||||||
|
e5 = staffManagement.save(new Employee("John von Neumann", JobType.SERVICE));
|
||||||
|
e6 = staffManagement.save(new Employee("Noam Chomsky", JobType.SERVICE));
|
||||||
|
|
||||||
|
c1 = createCustomOrder(LocalDateTime.of(2023, 10, 27, 6, 0), LocalDateTime.of(2023, 10, 27, 20, 0), Set.of(e1));
|
||||||
|
c2 = createCustomOrder(LocalDateTime.of(2023, 10, 27, 8, 0), LocalDateTime.of(2023, 10, 27, 16, 0), Set.of(e2));
|
||||||
|
c3 = createCustomOrder(LocalDateTime.of(2023, 10, 27, 18, 0), LocalDateTime.of(2023, 10, 27, 22, 0),
|
||||||
|
Set.of(e3));
|
||||||
|
c4 = createCustomOrder(LocalDateTime.of(2023, 10, 27, 16, 0), LocalDateTime.of(2023, 10, 27, 18, 0),
|
||||||
|
Set.of(e4));
|
||||||
|
c5 = createCustomOrder(LocalDateTime.of(2023, 10, 27, 8, 0), LocalDateTime.of(2023, 10, 27, 12, 0), Set.of(e5));
|
||||||
|
c6 = createCustomOrder(LocalDateTime.of(2023, 10, 21, 12, 0), LocalDateTime.of(2023, 10, 21, 22, 0),
|
||||||
|
Set.of(e6));
|
||||||
|
c7 = createCustomOrder(LocalDateTime.of(2023, 10, 27, 19, 0), LocalDateTime.of(2023, 10, 28, 12, 0), Set.of(e2, e3));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getAvailableEmployees() throws Exception {
|
||||||
|
Set<Employee> availableService = staffManagement.getAvailableStaffByJob(JobType.SERVICE,
|
||||||
|
LocalDateTime.of(2023, 10, 27, 16, 0), LocalDateTime.of(2023, 10, 27, 18, 0));
|
||||||
|
Set<Employee> availableCook = staffManagement.getAvailableStaffByJob(JobType.COOK,
|
||||||
|
LocalDateTime.of(2023, 10, 27, 16, 0), LocalDateTime.of(2023, 10, 27, 18, 0));
|
||||||
|
|
||||||
|
assertThat(availableCook.size()).isEqualTo(0);
|
||||||
|
assertThat(availableService.size()).isEqualTo(2);
|
||||||
|
assertThat(availableService).contains(e5, e6);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue