booking calendar cell: display first available slot if any (#19460)
This commit is contained in:
parent
2b44768f5c
commit
f2b51d4077
|
@ -1,8 +1,20 @@
|
|||
{% load i18n calendar %}
|
||||
|
||||
{% if cell.title %}
|
||||
<h2>{{cell.title}}</h2>
|
||||
<h2>
|
||||
<span>{{cell.title}}</span>
|
||||
{% if calendar %}
|
||||
<span class="calinfo">
|
||||
{% with calendar.get_first_available_slot as slot %}
|
||||
({% if slot %}{% trans "Next available slot:" %} {{ slot.date_time|date:"DATETIME_FORMAT"}}{% else %}{% trans "No available slots." %}{% endif %})
|
||||
{% endwith %}
|
||||
</span>
|
||||
{% endif %}
|
||||
</h2>
|
||||
{% endif %}
|
||||
<div class="calcontent">
|
||||
{% include 'calendar/booking_calendar_content.html' %}
|
||||
</div>
|
||||
|
||||
|
||||
<style>.calinfo { font-style: italic; font-size: 80%; }</style>
|
||||
|
|
|
@ -22,6 +22,7 @@ import urllib
|
|||
from django.conf import settings
|
||||
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||||
from django.utils.dateparse import parse_datetime
|
||||
from django.utils.timezone import localtime, make_aware
|
||||
|
||||
from combo.utils import requests
|
||||
|
||||
|
@ -81,7 +82,8 @@ def add_paginated_calendar_to_context(context):
|
|||
request = context['request']
|
||||
cell = context['cell']
|
||||
page = request.GET.get('chunk_%s' % cell.pk, 1)
|
||||
calendar = get_calendar(cell.agenda_reference, cell.slot_duration, cell.days_displayed)
|
||||
calendar = get_calendar(cell.agenda_reference, cell.slot_duration, cell.days_displayed,
|
||||
cell.minimal_booking_duration)
|
||||
paginator = Paginator(calendar.get_computed_days(), cell.days_displayed)
|
||||
try:
|
||||
cal_page = paginator.page(page)
|
||||
|
@ -95,11 +97,12 @@ def add_paginated_calendar_to_context(context):
|
|||
return context
|
||||
|
||||
|
||||
def get_calendar(agenda_reference, offset, days_displayed):
|
||||
def get_calendar(agenda_reference, offset, days_displayed, min_duration):
|
||||
if not agenda_reference:
|
||||
return []
|
||||
events = get_chrono_events(agenda_reference)
|
||||
calendar = Calendar(offset, days_displayed)
|
||||
calendar = Calendar(offset, days_displayed, min_duration)
|
||||
|
||||
for event in events:
|
||||
event_datetime = parse_datetime(event['datetime'])
|
||||
if not calendar.has_day(event_datetime.date()):
|
||||
|
@ -129,7 +132,7 @@ def get_form_url_with_params(cell, data):
|
|||
class DaySlot(object):
|
||||
|
||||
def __init__(self, date_time, available, exist=True):
|
||||
self.date_time = date_time
|
||||
self.date_time = localtime(make_aware(date_time))
|
||||
self.available = available
|
||||
self.exist = exist
|
||||
|
||||
|
@ -170,14 +173,27 @@ class WeekDay(object):
|
|||
|
||||
class Calendar(object):
|
||||
|
||||
def __init__(self, offset, days_displayed):
|
||||
def __init__(self, offset, days_displayed, min_duration):
|
||||
self.offset = offset
|
||||
self.days_displayed = days_displayed
|
||||
self.days = []
|
||||
self.min_duration = min_duration
|
||||
|
||||
def __repr__(self):
|
||||
return '<Calendar>'
|
||||
|
||||
def get_first_available_slot(self):
|
||||
"""return the first available slot that has enough
|
||||
consecutive available slots to be allowed for booking
|
||||
"""
|
||||
required_contiguous_slots = self.min_duration.seconds / self.offset.seconds
|
||||
for day in self.days:
|
||||
slots = day.slots
|
||||
for idx in range(len(slots) - required_contiguous_slots):
|
||||
if all([x.available for x in slots[idx:idx+required_contiguous_slots]]):
|
||||
return slots[idx]
|
||||
return None
|
||||
|
||||
def get_slots(self):
|
||||
start = self.get_minimum_slot()
|
||||
end = self.get_maximum_slot()
|
||||
|
|
|
@ -215,13 +215,13 @@ def test_cell_rendering(mocked_get, client, cell):
|
|||
assert parsed.path == '/test/'
|
||||
qs = urlparse.parse_qs(parsed.query)
|
||||
assert qs['session_var_booking_agenda_slug'] == ['test']
|
||||
assert qs['session_var_booking_start'] == ['2017-06-13T08:00:00']
|
||||
assert qs['session_var_booking_end'] == ['2017-06-13T09:30:00']
|
||||
assert qs['session_var_booking_start'] == ['2017-06-13T08:00:00+00:00']
|
||||
assert qs['session_var_booking_end'] == ['2017-06-13T09:30:00+00:00']
|
||||
|
||||
|
||||
@mock.patch('combo.apps.calendar.utils.requests.get', side_effect=mocked_requests_get)
|
||||
def test_calendar(mocked_get, cell):
|
||||
cal = get_calendar('default:whatever', cell.slot_duration, 7)
|
||||
cal = get_calendar('default:whatever', cell.slot_duration, 7, cell.minimal_booking_duration)
|
||||
assert len(cal.days) == 3
|
||||
for day in cal.get_computed_days():
|
||||
assert day in [
|
||||
|
@ -286,3 +286,40 @@ def test_cell_pagination(mocked_get, client, cell):
|
|||
previous_page_link = links[0]
|
||||
assert previous_page_link.text == 'previous'
|
||||
assert previous_page_link.attrs['data-content-url'] == '/ajax/calendar/content/%d/?chunk_%d=1' % (cell.pk, cell.pk)
|
||||
|
||||
|
||||
@mock.patch('combo.apps.calendar.utils.requests.get', side_effect=mocked_requests_get)
|
||||
def test_cell_rendering_cal_info(mocked_get, client, cell):
|
||||
page = client.get('/booking/')
|
||||
title_info = page.html.h2.find('span', {'class': 'calinfo'})
|
||||
assert title_info.text.strip() == '(Next available slot: June 13, 2017, 8 a.m.)'
|
||||
|
||||
|
||||
def test_cell_rendering_cal_info_when_available_slots_next_day(client, cell):
|
||||
with mock.patch('combo.utils.requests.get') as request_get:
|
||||
events = CHRONO_EVENTS['data'][::]
|
||||
for idx in range(2):
|
||||
events[idx]['disabled'] = True
|
||||
|
||||
def side_effect(*args, **kwargs):
|
||||
if 'chrono' in kwargs['remote_service']['url']:
|
||||
return MockedRequestResponse(content=json.dumps({"data": events}))
|
||||
return MockedRequestResponse(content=json.dumps(WCS_FORMDEFS))
|
||||
|
||||
request_get.side_effect = side_effect
|
||||
page = client.get('/booking/')
|
||||
title_info = page.html.h2.find('span', {'class': 'calinfo'})
|
||||
assert title_info.text.strip() == '(Next available slot: June 14, 2017, 9:30 a.m.)'
|
||||
|
||||
|
||||
def test_cell_rendering_cal_info_when_no_available_slots(client, cell):
|
||||
with mock.patch('combo.utils.requests.get') as request_get:
|
||||
def side_effect(*args, **kwargs):
|
||||
if 'chrono' in kwargs['remote_service']['url']:
|
||||
return MockedRequestResponse(content=json.dumps({"data": []}))
|
||||
return MockedRequestResponse(content=json.dumps(WCS_FORMDEFS))
|
||||
|
||||
request_get.side_effect = side_effect
|
||||
page = client.get('/booking/')
|
||||
title_info = page.html.h2.find('span', {'class': 'calinfo'})
|
||||
assert title_info.text.strip() == '(No available slots.)'
|
||||
|
|
Loading…
Reference in New Issue