Skip to content

Commit abb1d56

Browse files
fatmaebrahimCopilot
andcommitted
feat: restricted non excuse leaves not to be 0.25 day
Co-authored-by: Copilot <copilot@github.com>
1 parent 387fb52 commit abb1d56

4 files changed

Lines changed: 82 additions & 47 deletions

File tree

client/src/components/requests/leaveRequest.vue

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
The actual number of vacation days requested is zero. Please note that the selected days may include weekends or
66
public holidays.
77
</p>
8-
<p v-else-if="leaveReason?.reason== 'excuse'">
8+
<p v-else-if="leaveReason?.reason == 'excuse'">
99
The vacation request submitted is for a total of 1 excuse. </p>
1010
<p v-else>
1111
The vacation request submitted is for a total of {{ vacationDays.state.value }}
@@ -49,15 +49,15 @@
4949

5050
<div class="mt-3">
5151
<v-text-field ref="excuseStartField" item-color="info" base-color="info" color="info" variant="outlined"
52-
label="Vacation Start Time" v-model="excuseStart" hide-details="auto" type="time" :rules="[validateTimes,validateExcuse]"
53-
:readonly="startDate !== endDate">
52+
label="Vacation Start Time" v-model="excuseStart" hide-details="auto" type="time"
53+
:rules="[validateTimes, validateLeave,]" :readonly="startDate !== endDate">
5454
</v-text-field>
5555
</div>
5656

5757
<div class="mt-3">
5858
<v-text-field ref="excuseEndField" item-color="info" base-color="info" color="info" variant="outlined"
59-
label="Vacation End Time" v-model="excuseEnd" hide-details="auto" type="time" :rules="[validateTimes,validateExcuse]"
60-
:readonly="startDate !== endDate">
59+
label="Vacation End Time" v-model="excuseEnd" hide-details="auto" type="time"
60+
:rules="[validateTimes, validateLeave,]" :readonly="startDate !== endDate">
6161
</v-text-field>
6262
</div>
6363
<v-row class="mt-3 pa-4 d-flex justify-end">
@@ -224,26 +224,28 @@ export default {
224224
return true
225225
}
226226
227-
watch(leaveReason, () => {
228-
excuseStartField.value?.validate()
229-
excuseEndField.value?.validate()
230-
})
231-
const validateExcuse = (): string | boolean => {
232-
if (leaveReason.value && leaveReason.value.reason === 'excuse') {
233-
let endHour = Number(excuseEnd.value.split(':')[0])
234-
let startHour = Number(excuseStart.value.split(':')[0])
227+
watch(leaveReason, () => {
228+
excuseStartField.value?.validate()
229+
excuseEndField.value?.validate()
230+
})
231+
const validateLeave = (): string | boolean => {
232+
let endHour = Number(excuseEnd.value.split(':')[0])
233+
let startHour = Number(excuseStart.value.split(':')[0])
235234
236-
let endMinute = Number(excuseEnd.value.split(':')[1])
237-
let startMinute = Number(excuseStart.value.split(':')[1])
235+
let endMinute = Number(excuseEnd.value.split(':')[1])
236+
let startMinute = Number(excuseStart.value.split(':')[1])
238237
239-
let diff = (endHour - startHour) * 60 + (endMinute - startMinute)
238+
let diff = (endHour - startHour) * 60 + (endMinute - startMinute)
239+
240+
if (leaveReason.value && leaveReason.value.reason === 'excuse') {
240241
if (diff > 120) return 'Excuse time cannot exceed 2 hours in a day.'
242+
} else {
243+
if (diff < 180) return 'Vacation duration cannot be less than 0.5 days.'
241244
}
242245
return true
243246
}
244247
245248
246-
247249
onMounted(async () => {
248250
startDateField.value.validate()
249251
endDateField.value.validate()
@@ -322,7 +324,7 @@ export default {
322324
createLeave,
323325
validateDates,
324326
validateTimes,
325-
validateExcuse,
327+
validateLeave,
326328
useOldBalance,
327329
balance,
328330
couldApplyUsingOldBalance,

server/cshr/tests/test_vacation.py

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ def test_create_vacation(self) -> Vacation:
9292
url = "/api/vacations/"
9393
data = {
9494
"reason": "annual",
95-
"from_date": "2022-08-23",
96-
"end_date": "2022-08-23",
95+
"from_date": "2022-08-23:08:00:00",
96+
"end_date": "2022-08-23:17:00:00",
9797
"change_log": [],
9898
}
9999
self.headers = client.credentials(
@@ -106,8 +106,8 @@ def test_create_vacation_with_invalid_reason(self) -> Vacation:
106106
url = "/api/vacations/"
107107
data = {
108108
"reason": "invalid",
109-
"from_date": "2022-08-23",
110-
"end_date": "2022-08-23",
109+
"from_date": "2022-08-23:08:00:00",
110+
"end_date": "2022-08-23:17:00:00",
111111
"change_log": [],
112112
}
113113
self.headers = client.credentials(
@@ -147,8 +147,8 @@ def test_get_certain_vacation_request(self) -> Vacation:
147147
url = "/api/vacations/"
148148
data = {
149149
"reason": "annual",
150-
"from_date": "2022-08-23",
151-
"end_date": "2022-08-23",
150+
"from_date": "2022-08-23:08:00:00",
151+
"end_date": "2022-08-23:17:00:00",
152152
"change_log": [],
153153
}
154154
self.headers = client.credentials(
@@ -166,8 +166,8 @@ def test_get_invalid_vacation_request(self) -> Vacation:
166166
url = "/api/vacations/"
167167
data = {
168168
"reason": "annual",
169-
"from_date": "2022-08-23",
170-
"end_date": "2022-08-23",
169+
"from_date": "2022-08-23:08:00:00",
170+
"end_date": "2022-08-23:17:00:00",
171171
"change_log": [],
172172
}
173173
self.headers = client.credentials(
@@ -184,8 +184,8 @@ def test_cancel_certain_vacation_request(self) -> Vacation:
184184
url = "/api/vacations/"
185185
data = {
186186
"reason": "annual",
187-
"from_date": "2022-08-23",
188-
"end_date": "2022-08-23",
187+
"from_date": "2022-08-23:08:00:00",
188+
"end_date": "2022-08-23:17:00:00",
189189
"change_log": [],
190190
}
191191
self.headers = client.credentials(
@@ -221,8 +221,8 @@ def test_update_vacation_request_invalid_user_id(self) -> Vacation:
221221
url = "/api/vacations/"
222222
data = {
223223
"reason": "annual",
224-
"from_date": "2022-08-23",
225-
"end_date": "2022-08-23",
224+
"from_date": "2022-08-23:08:00:00",
225+
"end_date": "2022-08-23:17:00:00",
226226
"change_log": [],
227227
}
228228
self.headers = client.credentials(
@@ -240,8 +240,8 @@ def test_user_updates_status(self) -> Vacation:
240240
url = "/api/vacations/"
241241
data = {
242242
"reason": "annual",
243-
"from_date": "2022-08-23",
244-
"end_date": "2022-08-23",
243+
"from_date": "2022-08-23:08:00:00",
244+
"end_date": "2022-08-23:17:00:00",
245245
"change_log": [],
246246
}
247247
self.headers = client.credentials(
@@ -259,8 +259,8 @@ def test_get_vacations_for_user_with_data(self) -> Vacation:
259259
url = "/api/vacations/"
260260
data = {
261261
"reason": "annual",
262-
"from_date": "2022-08-23",
263-
"end_date": "2022-08-23",
262+
"from_date": "2022-08-23:08:00:00",
263+
"end_date": "2022-08-23:17:00:00",
264264
"change_log": [],
265265
}
266266
self.headers = client.credentials(
@@ -285,8 +285,8 @@ def test_accept_vacation_for_unauthorized_user(self) -> Vacation:
285285
url = "/api/vacations/"
286286
data = {
287287
"reason": "annual",
288-
"from_date": "2022-08-23",
289-
"end_date": "2022-08-23",
288+
"from_date": "2022-08-23:08:00:00",
289+
"end_date": "2022-08-23:17:00:00",
290290
"change_log": [],
291291
}
292292
self.headers = client.credentials(
@@ -303,8 +303,8 @@ def test_reject_vacation_for_unauthorized_user(self) -> Vacation:
303303
url = "/api/vacations/"
304304
data = {
305305
"reason": "annual",
306-
"from_date": "2022-08-23",
307-
"end_date": "2022-08-23",
306+
"from_date": "2022-08-23:08:00:00",
307+
"end_date": "2022-08-23:17:00:00",
308308
"change_log": [],
309309
}
310310
self.headers = client.credentials(
@@ -321,8 +321,8 @@ def test_accept_vacation_for_supervisor_auth(self) -> Vacation:
321321
url = "/api/vacations/"
322322
data = {
323323
"reason": "annual",
324-
"from_date": "2022-08-23",
325-
"end_date": "2022-08-23",
324+
"from_date": "2022-08-23:08:00:00",
325+
"end_date": "2022-08-23:17:00:00",
326326
"change_log": [],
327327
}
328328
self.headers = client.credentials(
@@ -341,8 +341,8 @@ def test_reject_vacation_for_supervisor_auth(self) -> Vacation:
341341
url = "/api/vacations/"
342342
data = {
343343
"reason": "annual",
344-
"from_date": "2022-08-23",
345-
"end_date": "2022-08-23",
344+
"from_date": "2022-08-23:08:00:00",
345+
"end_date": "2022-08-23:17:00:00",
346346
"change_log": [],
347347
}
348348
self.headers = client.credentials(
@@ -361,8 +361,8 @@ def test_reject_invalid_vacation(self) -> Vacation:
361361
url = "/api/vacations/"
362362
data = {
363363
"reason": "annual",
364-
"from_date": "2022-08-23",
365-
"end_date": "2022-08-23",
364+
"from_date": "2022-08-23:08:00:00",
365+
"end_date": "2022-08-23:17:00:00",
366366
"change_log": [],
367367
}
368368
self.headers = client.credentials(
@@ -379,8 +379,8 @@ def test_accept_invalid_vacation(self) -> Vacation:
379379
url = "/api/vacations/"
380380
data = {
381381
"reason": "annual",
382-
"from_date": "2022-08-23",
383-
"end_date": "2022-08-23",
382+
"from_date": "2022-08-23:08:00:00",
383+
"end_date": "2022-08-23:17:00:00",
384384
"change_log": [],
385385
}
386386
self.headers = client.credentials(
@@ -485,7 +485,7 @@ def test_update_annual_to_excuse_with_valid_duration(self) -> Vacation:
485485
data = {
486486
"reason": "annual",
487487
"from_date": "2022-08-23:08:00:00",
488-
"end_date": "2022-08-23:10:00:00",
488+
"end_date": "2022-08-23:17:00:00",
489489
"change_log": [],
490490
}
491491
self.headers = client.credentials(
@@ -529,3 +529,21 @@ def test_update_annual_to_excuse_with_invalid_duration(self) -> Vacation:
529529
}
530530
response = client.put(url, data, format="json")
531531
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
532+
533+
def test_invalid_annual_vacation_duration(self) -> Vacation:
534+
url = "/api/vacations/"
535+
data = {
536+
"reason": "annual",
537+
"from_date": "2022-08-23:08:00:00",
538+
"end_date": "2022-08-23:10:00:00",
539+
"change_log": [],
540+
}
541+
self.headers = client.credentials(
542+
HTTP_AUTHORIZATION="Bearer " + self.access_token_user
543+
)
544+
response = client.post(url, data, format="json")
545+
self.assertEqual(
546+
response.data.get("message"),
547+
"Vacation duration cannot be less than 0.5 days.",
548+
)
549+
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

server/cshr/utils/balance_calculator.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,18 @@ def check_locked_balance(self, is_update: bool = False):
213213

214214
if total_days + locked_balance > reason_days:
215215
raise ValueError("Insufficient balance for the requested vacation days.")
216+
217+
218+
@validate_applying_user
219+
@validate_vacation
220+
@validate_user_balance
221+
def check_vacation_validations(self):
222+
"""
223+
Run all necessary validations for the vacation request.
224+
"""
225+
total_days = self.get_vacation_days()
226+
if self.vacation.reason != "excuse" and total_days < 0.5:
227+
raise ValueError("Vacation duration cannot be less than 0.5 days.")
216228

217229
@validate_applying_user
218230
@validate_vacation

server/cshr/views/vacations.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ def post(self, request: Request) -> Response:
7575
try:
7676
balance_calculator.check_requests_in_selected_dates()
7777
balance_calculator.check_locked_balance()
78+
balance_calculator.check_vacation_validations()
7879
except Exception as e:
7980
return CustomResponse.bad_request(message=str(e))
8081

@@ -219,6 +220,7 @@ def put(self, request: Request, id: str, format=None) -> Response:
219220

220221
try:
221222
balance_calculator.check_user_balance()
223+
balance_calculator.check_vacation_validations()
222224
balance_calculator.check_requests_in_selected_dates(is_update=True)
223225
balance_calculator.check_locked_balance(is_update=True)
224226
except Exception as e:
@@ -491,6 +493,7 @@ def post(self, request: Request, user_id: str) -> Response:
491493
try:
492494
balance_calculator.check_requests_in_selected_dates()
493495
balance_calculator.check_locked_balance()
496+
balance_calculator.check_vacation_validations()
494497
vacation_days = balance_calculator.get_vacation_days()
495498
balance_calculator.adjust_balance()
496499
except ValueError as e:

0 commit comments

Comments
 (0)