diff --git a/account-service/src/test/java/com/drinkool/services/StaffServiceTest.java b/account-service/src/test/java/com/drinkool/services/StaffServiceTest.java index 5cce294..c13b0e5 100644 --- a/account-service/src/test/java/com/drinkool/services/StaffServiceTest.java +++ b/account-service/src/test/java/com/drinkool/services/StaffServiceTest.java @@ -10,12 +10,8 @@ import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.kafka.*; import io.restassured.http.ContentType; -import io.smallrye.reactive.messaging.kafka.companion.ConsumerTask; -import io.smallrye.reactive.messaging.kafka.companion.KafkaCompanion; import jakarta.ws.rs.core.Response; -import java.time.Duration; import net.datafaker.Faker; -import org.eclipse.microprofile.config.inject.ConfigProperty; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/eatery-service/src/main/java/com/drinkool/entities/ShiftEntity.java b/eatery-service/src/main/java/com/drinkool/entities/ShiftEntity.java new file mode 100644 index 0000000..c04f39c --- /dev/null +++ b/eatery-service/src/main/java/com/drinkool/entities/ShiftEntity.java @@ -0,0 +1,24 @@ +package com.drinkool.entities; + +import com.drinkool.lib.entities.BaseEntity; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; +import java.time.LocalTime; + +@Entity +@Table +public class ShiftEntity extends BaseEntity { + + @Column(nullable = false) + public String name; + + @Column(nullable = false) + public LocalTime startTime; + + @Column(nullable = false) + public LocalTime endTime; + + @Column(nullable = true) + public Integer maxStaff; +} diff --git a/eatery-service/src/main/java/com/drinkool/entities/ShiftRegistrationEntity.java b/eatery-service/src/main/java/com/drinkool/entities/ShiftRegistrationEntity.java new file mode 100644 index 0000000..22f643c --- /dev/null +++ b/eatery-service/src/main/java/com/drinkool/entities/ShiftRegistrationEntity.java @@ -0,0 +1,37 @@ +package com.drinkool.entities; + +import com.drinkool.lib.entities.BaseEntity; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; + +import java.util.List; +import java.util.UUID; + +@Entity +@Table +public class ShiftRegistrationEntity extends BaseEntity { + + @Column(nullable = false) + public UUID staffId; + + @ManyToOne + public ShiftEntity shift; + + public static long countByShift(UUID shiftId) { + return count("shift.id = ?1", shiftId); + } + + public static List findOverlappingShifts( + UUID staffId, + ShiftEntity registratingShift + ) { + return list( + "staffId = ?1 and shift.startTime < ?2 and shift.endTime > ?3", + staffId, + registratingShift.endTime, + registratingShift.startTime + ); + } +} diff --git a/eatery-service/src/main/java/com/drinkool/services/ShiftService.java b/eatery-service/src/main/java/com/drinkool/services/ShiftService.java new file mode 100644 index 0000000..7c2f2d7 --- /dev/null +++ b/eatery-service/src/main/java/com/drinkool/services/ShiftService.java @@ -0,0 +1,117 @@ +package com.drinkool.services; + +import com.drinkool.InternalValue; +import com.drinkool.Role; +import com.drinkool.Url; +import com.drinkool.entities.ShiftEntity; +import com.drinkool.entities.ShiftRegistrationEntity; +import com.drinkool.lib.dtos.CreateShift; +import com.drinkool.lib.dtos.RegisterShift; +import io.vertx.core.http.HttpServerRequest; +import jakarta.annotation.security.RolesAllowed; +import jakarta.inject.Inject; +import jakarta.transaction.Transactional; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.Response; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +@Path(Url.Shift) +public class ShiftService { + + @Inject + HttpServerRequest request; + + @POST + @Path("/me") + @RolesAllowed(Role.Staff) + @Transactional + public Response registerShift(RegisterShift registration) { + String userIdStr = request.getHeader(InternalValue.userId); + + UUID staffId = UUID.fromString(userIdStr); + + ShiftEntity shift = ShiftEntity.findById(registration.shiftId); + if (shift == null) { + return Response.status(Response.Status.NOT_FOUND) + .entity("NotFoundShift") + .build(); + } + + List overlappingShifts = + ShiftRegistrationEntity.findOverlappingShifts(staffId, shift); + if (!overlappingShifts.isEmpty()) { + String overlappingNames = overlappingShifts + .stream() + .map(reg -> reg.shift.id.toString()) + .distinct() + .collect(Collectors.joining(", ")); + + return Response.status(Response.Status.CONFLICT) + .entity(overlappingNames) + .build(); + } + + long currentStaffCount = ShiftRegistrationEntity.countByShift(shift.id); + if (shift.maxStaff != null && currentStaffCount >= shift.maxStaff) { + return Response.status(Response.Status.BAD_REQUEST) + .entity("FulledShift") + .build(); + } + + ShiftRegistrationEntity record = new ShiftRegistrationEntity(); + record.staffId = staffId; + record.shift = shift; + record.persist(); + + return Response.ok(record).build(); + } + + @GET + @Path("/me") + @RolesAllowed(Role.Staff) + public List getMyShifts() { + String userId = request.getHeader(InternalValue.userId); + return ShiftRegistrationEntity.list("staffId", UUID.fromString(userId)); + } + + @GET + @RolesAllowed({ Role.Staff, Role.Manager }) + public List getShift() { + return ShiftEntity.listAll(); + } + + @POST + @Transactional + public Response createShift(CreateShift request) { + if ( + request.name == null || + request.name.isEmpty() || + request.startTime == null || + request.endTime == null + ) { + return Response.status(Response.Status.BAD_REQUEST) + .entity("BadInput") + .build(); + } + + ShiftEntity shift = new ShiftEntity(); + shift.name = request.name; + shift.startTime = request.startTime; + shift.endTime = request.endTime; + shift.maxStaff = request.maxStaff; + + if (shift.endTime.isBefore(shift.startTime)) { + return Response.status(Response.Status.BAD_REQUEST) + .entity("InvalidEndTime") + .build(); + } + + shift.persist(); + + return Response.status(Response.Status.CREATED).entity(shift).build(); + } +} diff --git a/lib/src/main/java/com/drinkool/Url.java b/lib/src/main/java/com/drinkool/Url.java index f02fa93..0d30a18 100644 --- a/lib/src/main/java/com/drinkool/Url.java +++ b/lib/src/main/java/com/drinkool/Url.java @@ -11,4 +11,5 @@ public class Url { public static final String Logout = "/logout"; public static final String Cart = "/cart"; public static final String Review = "/review"; + public static final String Shift = "/shift"; } diff --git a/lib/src/main/java/com/drinkool/lib/dtos/CreateShift.java b/lib/src/main/java/com/drinkool/lib/dtos/CreateShift.java new file mode 100644 index 0000000..1568451 --- /dev/null +++ b/lib/src/main/java/com/drinkool/lib/dtos/CreateShift.java @@ -0,0 +1,11 @@ +package com.drinkool.lib.dtos; + +import java.time.LocalTime; + +public class CreateShift { + + public String name; + public LocalTime startTime; + public LocalTime endTime; + public Integer maxStaff; +} diff --git a/lib/src/main/java/com/drinkool/lib/dtos/RegisterShift.java b/lib/src/main/java/com/drinkool/lib/dtos/RegisterShift.java new file mode 100644 index 0000000..d547637 --- /dev/null +++ b/lib/src/main/java/com/drinkool/lib/dtos/RegisterShift.java @@ -0,0 +1,8 @@ +package com.drinkool.lib.dtos; + +import java.util.UUID; + +public class RegisterShift { + + public UUID shiftId; +}