Skip to content

Commit

Permalink
fix(reservation-retreat): overlapping of reservation data (#916)
Browse files Browse the repository at this point in the history
  • Loading branch information
RignonNoel committed Mar 16, 2021
1 parent 2c8e659 commit d27ebf9
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 28 deletions.
49 changes: 26 additions & 23 deletions retirement/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,34 +373,37 @@ def validate(self, attrs):
})
return attrs

# Generate a list of tuples containing start/end time of
# existing reservations.
start = validated_data['retreat'].start_time
end = validated_data['retreat'].end_time
active_reservations = Reservation.objects.filter(
user=validated_data['user'],
is_active=True,
)

active_reservations = active_reservations.all()

for reservation in active_reservations:
for date in reservation.retreat.retreat_dates.all():
latest_start = max(
date.start_time,
start,
)
shortest_end = min(
date.end_time,
end,
)
if latest_start < shortest_end:
raise serializers.ValidationError({
'non_field_errors': [_(
"This reservation overlaps with another active "
"reservations for this user."
)]
})
# We check for every new date we want to reserve if there
# is already an other date overlapping.
# This complexity is required since retreats can contain
# multiple date with a lot of free space between them.
for new_date in validated_data['retreat'].retreat_dates.all():
start = new_date.start_time
end = new_date.end_time

for reservation in active_reservations:
for date in reservation.retreat.retreat_dates.all():
latest_start = max(
date.start_time,
start,
)
shortest_end = min(
date.end_time,
end,
)
if latest_start < shortest_end:
raise serializers.ValidationError({
'non_field_errors': [_(
"This reservation overlaps with "
"another active reservations for "
"this user."
)]
})
return attrs

def create(self, validated_data):
Expand Down
81 changes: 77 additions & 4 deletions retirement/tests/tests_viewset_Reservation.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ def setUp(self):
end_time=LOCAL_TIMEZONE.localize(datetime(2130, 2, 17, 12)),
retreat=self.retreat2,
)
self.retreat_overlap = Retreat.objects.create(
self.retreat_overlap_conflict = Retreat.objects.create(
name="ultra_retreat",
details="This is a description of the ultra retreat.",
seats=400,
Expand All @@ -167,9 +167,43 @@ def setUp(self):
RetreatDate.objects.create(
start_time=LOCAL_TIMEZONE.localize(datetime(2130, 1, 15, 8)),
end_time=LOCAL_TIMEZONE.localize(datetime(2130, 1, 17, 12)),
retreat=self.retreat_overlap_conflict,
)
self.retreat_overlap_conflict.activate()

self.retreat_overlap = Retreat.objects.create(
name="ultra_retreat",
details="This is a description of the ultra retreat.",
seats=400,
address_line1="1234 random street",
postal_code="654 321",
state_province="Random state 2",
country="Random country 2",
price=199,
min_day_refund=7,
min_day_exchange=7,
refund_rate=50,
accessibility=True,
form_url="example.com",
carpool_url='example2.com',
review_url='example3.com',
has_shared_rooms=True,
toilet_gendered=False,
room_type=Retreat.SINGLE_OCCUPATION,
type=self.retreatType,
)
RetreatDate.objects.create(
start_time=LOCAL_TIMEZONE.localize(datetime(2130, 1, 13, 8)),
end_time=LOCAL_TIMEZONE.localize(datetime(2130, 1, 14, 12)),
retreat=self.retreat_overlap,
)
RetreatDate.objects.create(
start_time=LOCAL_TIMEZONE.localize(datetime(2130, 1, 18, 8)),
end_time=LOCAL_TIMEZONE.localize(datetime(2130, 1, 19, 12)),
retreat=self.retreat_overlap,
)
self.retreat_overlap.activate()

self.order = Order.objects.create(
user=self.user,
transaction_date=timezone.now(),
Expand Down Expand Up @@ -307,10 +341,10 @@ def test_create_without_permission(self):

self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

def test_create_overlapping(self):
def test_create_overlapping_without_conflict(self):
"""
Ensure we can't create reservations with overlapping retreat for the
same user.
Ensure we can create reservations with overlapping retreat for the
same user if the overlapping does not contain a conflict of date.
"""
self.client.force_authenticate(user=self.admin)

Expand All @@ -331,6 +365,45 @@ def test_create_overlapping(self):
format='json',
)

self.assertEqual(
response.status_code,
status.HTTP_201_CREATED
)

content = json.loads(response.content)

self.assertCountEqual(
content['retreat_details']['users'],
[
'http://testserver/users/' + str(self.user.id)
]
)
self.check_attributes(content)

def test_create_overlapping_with_conflict(self):
"""
Ensure we can't create reservations with overlapping retreat for the
same user if the overlapping contain a conflict of date.
"""
self.client.force_authenticate(user=self.admin)

data = {
'retreat': reverse(
'retreat:retreat-detail',
args=[self.retreat_overlap_conflict.id]
),
'user': reverse('user-detail', args=[self.user.id]),
'order_line': reverse(
'orderline-detail', args=[self.order_line.id]),
'is_active': True,
}

response = self.client.post(
reverse('retreat:reservation-list'),
data,
format='json',
)

content = {
'non_field_errors': [
'This reservation overlaps with another active reservations '
Expand Down
2 changes: 1 addition & 1 deletion retirement/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ def execute_automatic_email(self, request, pk=None):
"""
try:
retreat = Retreat.objects.get(pk=pk)
except:
except Exception:
response_data = {
'detail': "Retreat not found"
}
Expand Down

0 comments on commit d27ebf9

Please sign in to comment.