source: backend/src/main/java/mk/finki/roomreservation/service/ReservationService.java@ 09e02d7

Last change on this file since 09e02d7 was 09e02d7, checked in by Nikola Sarafimov <sarafimov.nikola12345@…>, 3 days ago

Final room reservation system implementation

  • Property mode set to 100644
File size: 6.4 KB
Line 
1package mk.finki.roomreservation.service;
2
3import mk.finki.roomreservation.model.CreateReservationRequest;
4import mk.finki.roomreservation.model.EquipmentRequest;
5import mk.finki.roomreservation.model.ReservationDetails;
6import org.springframework.jdbc.core.JdbcTemplate;
7import org.springframework.stereotype.Service;
8import org.springframework.transaction.annotation.Transactional;
9
10import java.sql.Date;
11import java.sql.Time;
12import java.time.LocalDate;
13import java.time.LocalTime;
14import java.util.List;
15import java.util.Objects;
16
17@Service
18public class ReservationService {
19
20 private final JdbcTemplate jdbcTemplate;
21
22 public ReservationService(JdbcTemplate jdbcTemplate) {
23 this.jdbcTemplate = jdbcTemplate;
24 }
25
26 @Transactional
27 public ReservationDetails createReservation(CreateReservationRequest request) {
28 validateCreateRequest(request);
29
30 LocalDate date = LocalDate.parse(request.reservationDate());
31 LocalTime start = LocalTime.parse(request.startTime());
32 LocalTime end = LocalTime.parse(request.endTime());
33
34 List<EquipmentRequest> equipment =
35 request.equipment() == null ? List.of() : request.equipment();
36
37 String insertReservationSql = """
38 INSERT INTO project.reservations (
39 room_id,
40 user_id,
41 reservation_date,
42 start_time,
43 end_time,
44 status
45 )
46 VALUES (?, ?, ?, ?, ?, 'pending')
47 RETURNING reservation_id
48 """;
49
50 Integer reservationId = jdbcTemplate.queryForObject(
51 insertReservationSql,
52 Integer.class,
53 request.roomId(),
54 request.userId(),
55 Date.valueOf(date),
56 Time.valueOf(start),
57 Time.valueOf(end)
58 );
59
60 if (reservationId == null) {
61 throw new RuntimeException("Reservation was not created.");
62 }
63
64 for (EquipmentRequest item : equipment) {
65 jdbcTemplate.update(
66 """
67 INSERT INTO project.reservation_equipment (
68 reservation_id,
69 equipment_id,
70 requested_quantity
71 )
72 VALUES (?, ?, ?)
73 """,
74 reservationId,
75 item.equipmentId(),
76 item.requestedQuantity()
77 );
78 }
79
80 return findReservationDetails(reservationId);
81 }
82
83 public ReservationDetails findReservationDetails(int reservationId) {
84 String sql = """
85 SELECT
86 res.reservation_id,
87 u.full_name AS requester_name,
88 COALESCE(r.room_code, 'No room') AS room_code,
89 res.reservation_date::text AS reservation_date,
90 res.start_time::text AS start_time,
91 res.end_time::text AS end_time,
92 res.status,
93 COALESCE(eq.requested_equipment, 'No equipment') AS equipment
94 FROM project.reservations res
95 JOIN project.users u
96 ON res.user_id = u.user_id
97 LEFT JOIN project.rooms r
98 ON res.room_id = r.room_id
99 LEFT JOIN (
100 SELECT
101 req.reservation_id,
102 string_agg(e.name || ' x' || req.requested_quantity, ', ' ORDER BY e.name) AS requested_equipment
103 FROM project.reservation_equipment req
104 JOIN project.equipment e
105 ON req.equipment_id = e.equipment_id
106 GROUP BY req.reservation_id
107 ) eq
108 ON res.reservation_id = eq.reservation_id
109 WHERE res.reservation_id = ?
110 """;
111
112 ReservationDetails details = jdbcTemplate.queryForObject(
113 sql,
114 (rs, rowNum) -> new ReservationDetails(
115 rs.getInt("reservation_id"),
116 rs.getString("requester_name"),
117 rs.getString("room_code"),
118 rs.getString("reservation_date"),
119 rs.getString("start_time"),
120 rs.getString("end_time"),
121 rs.getString("status"),
122 rs.getString("equipment")
123 ),
124 reservationId
125 );
126
127 if (details == null) {
128 throw new RuntimeException("Reservation not found.");
129 }
130
131 return details;
132 }
133
134 private void validateCreateRequest(CreateReservationRequest request) {
135 if (request.userId() == null) {
136 throw new IllegalArgumentException("Requester user is required.");
137 }
138
139 if (request.reservationDate() == null || request.reservationDate().isBlank()) {
140 throw new IllegalArgumentException("Reservation date is required.");
141 }
142
143 if (request.startTime() == null || request.startTime().isBlank()) {
144 throw new IllegalArgumentException("Start time is required.");
145 }
146
147 if (request.endTime() == null || request.endTime().isBlank()) {
148 throw new IllegalArgumentException("End time is required.");
149 }
150
151 LocalTime start = LocalTime.parse(request.startTime());
152 LocalTime end = LocalTime.parse(request.endTime());
153
154 if (!end.isAfter(start)) {
155 throw new IllegalArgumentException("End time must be after start time.");
156 }
157
158 boolean hasRoom = request.roomId() != null;
159 boolean hasEquipment = request.equipment() != null && !request.equipment().isEmpty();
160
161 if (!hasRoom && !hasEquipment) {
162 throw new IllegalArgumentException("Reservation must include at least one resource: room or equipment.");
163 }
164
165 if (hasEquipment) {
166 for (EquipmentRequest item : request.equipment()) {
167 Objects.requireNonNull(item, "Equipment request cannot be null.");
168
169 if (item.equipmentId() <= 0) {
170 throw new IllegalArgumentException("Equipment ID must be valid.");
171 }
172
173 if (item.requestedQuantity() <= 0) {
174 throw new IllegalArgumentException("Requested equipment quantity must be greater than 0.");
175 }
176 }
177 }
178 }
179}
Note: See TracBrowser for help on using the repository browser.