add minimal/maximal booking delays (#12673)

This commit is contained in:
Frédéric Péters 2016-09-11 19:16:15 +02:00
parent 871d6c76c7
commit 71b7130445
7 changed files with 85 additions and 16 deletions

View File

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('agendas', '0008_auto_20160910_1319'),
]
operations = [
migrations.AddField(
model_name='agenda',
name='maximal_booking_delay',
field=models.PositiveIntegerField(default=56, verbose_name='Maximal booking delay (in days)'),
),
migrations.AddField(
model_name='agenda',
name='minimal_booking_delay',
field=models.PositiveIntegerField(default=1, verbose_name='Minimal booking delay (in days)'),
),
]

View File

@ -36,6 +36,10 @@ class Agenda(models.Model):
label = models.CharField(_('Label'), max_length=100)
slug = models.SlugField(_('Slug'))
kind = models.CharField(_('Kind'), max_length=20, choices=AGENDA_KINDS, default='events')
minimal_booking_delay = models.PositiveIntegerField(
_('Minimal booking delay (in days)'), default=1)
maximal_booking_delay = models.PositiveIntegerField(
_('Maximal booking delay (in days)'), default=56) # eight weeks
class Meta:
ordering = ['label']

View File

@ -47,14 +47,17 @@ agendas = Agendas.as_view()
class Datetimes(GenericAPIView):
def get(self, request, pk=None, format=None):
min_datetime = now()
agenda = Agenda.objects.get(id=pk)
if agenda.kind != 'events':
raise APIException('not an events agenda')
entries = Event.objects.filter(agenda=pk).filter(
start_datetime__gte=min_datetime,
full=False).order_by('start_datetime')
kwargs = {}
kwargs['full'] = False
kwargs['start_datetime__gte'] = (now() + datetime.timedelta(days=agenda.minimal_booking_delay)).date()
if agenda.maximal_booking_delay:
kwargs['start_datetime__lt'] = (now() + datetime.timedelta(days=agenda.maximal_booking_delay)).date()
entries = Event.objects.filter(agenda=pk).filter(**kwargs).order_by('start_datetime')
response = {'data': [{'id': x.id, 'text': unicode(x)} for x in entries]}
return Response(response)
@ -69,8 +72,9 @@ class MeetingDatetimes(GenericAPIView):
if agenda.kind != 'meetings':
raise APIException('not a meetings agenda')
min_datetime = now()
max_datetime = now() + datetime.timedelta(days=60)
now_datetime = now()
min_datetime = now() + datetime.timedelta(days=agenda.minimal_booking_delay)
max_datetime = now() + datetime.timedelta(days=agenda.maximal_booking_delay)
all_time_slots = []
for time_period in TimePeriod.objects.filter(agenda=agenda):
@ -88,6 +92,8 @@ class MeetingDatetimes(GenericAPIView):
# there's room for optimisations here, for a start both lists
# could be presorted and past busy time slots removed along the way.
for time_slot in all_time_slots:
if time_slot.start_datetime < now_datetime:
continue
if any((x for x in busy_time_slots if x.full and time_slot.intersects(x))):
continue
entries.append(time_slot)

View File

@ -6,7 +6,7 @@
<span class="identifier">[{% trans "identifier:" %} {{object.id}}]</span></h2>
</h2>
<a rel="popup" href="{% url 'chrono-manager-agenda-delete' pk=object.id %}">{% trans 'Delete' %}</a>
<a rel="popup" href="{% url 'chrono-manager-agenda-edit' pk=object.id %}">{% trans 'Rename' %}</a>
<a rel="popup" href="{% url 'chrono-manager-agenda-edit' pk=object.id %}">{% trans 'Options' %}</a>
{% if object.kind == "events" %}
<a rel="popup" href="{% url 'chrono-manager-agenda-add-event' pk=object.id %}">{% trans 'New Event' %}</a>
{% else %}

View File

@ -46,7 +46,7 @@ agenda_add = AgendaAddView.as_view()
class AgendaEditView(UpdateView):
template_name = 'chrono/manager_agenda_form.html'
model = Agenda
fields = ['label']
fields = ['label', 'minimal_booking_delay', 'maximal_booking_delay']
agenda_edit = AgendaEditView.as_view()

View File

@ -47,14 +47,19 @@ def some_data():
@pytest.fixture
def meetings_agenda():
agenda = Agenda(label=u'Foo bar', kind='meetings')
agenda = Agenda(label=u'Foo bar', kind='meetings',
minimal_booking_delay=1, maximal_booking_delay=56)
agenda.save()
meeting_type = MeetingType(agenda=agenda, label='Blah', duration=30)
meeting_type.save()
time_period = TimePeriod(agenda=agenda, weekday=0,
test_1st_weekday = (now().weekday() + 2) % 7
test_2nd_weekday = (now().weekday() + 3) % 7
time_period = TimePeriod(agenda=agenda, weekday=test_1st_weekday,
start_time=datetime.time(10, 0), end_time=datetime.time(12, 0))
time_period.save()
time_period = TimePeriod(agenda=agenda, weekday=1,
time_period = TimePeriod(agenda=agenda, weekday=test_2nd_weekday,
start_time=datetime.time(10, 0), end_time=datetime.time(17, 0))
time_period.save()
return agenda
@ -71,11 +76,28 @@ def test_agendas_api(app, some_data):
]}
def test_datetimes_api(app, some_data):
agenda_id = Agenda.objects.filter(label=u'Foo bar')[0].id
agenda = Agenda.objects.filter(label=u'Foo bar')[0]
agenda_id = agenda.id
resp = app.get('/api/agenda/%s/datetimes/' % agenda_id)
assert 'data' in resp.json
assert len(resp.json['data']) == 3
agenda.minimal_booking_delay = 5
agenda.save()
resp = app.get('/api/agenda/%s/datetimes/' % agenda_id)
assert len(resp.json['data']) == 0
agenda.minimal_booking_delay = 2
agenda.save()
resp = app.get('/api/agenda/%s/datetimes/' % agenda_id)
assert len(resp.json['data']) == 2
agenda.minimal_booking_delay = 0
agenda.maximal_booking_delay = 3
agenda.save()
resp = app.get('/api/agenda/%s/datetimes/' % agenda_id)
assert len(resp.json['data']) == 2
def test_datetimes_api_wrong_kind(app, some_data):
agenda = Agenda.objects.filter(label=u'Foo bar')[0]
agenda.kind = 'meetings'
@ -101,8 +123,21 @@ def test_datetime_api_label(app, some_data):
def test_datetimes_api_meetings_agenda(app, meetings_agenda):
meeting_type = MeetingType.objects.get(agenda=meetings_agenda)
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
assert len(resp.json['data']) == 162
assert len(resp.json['data']) == 144
meetings_agenda.minimal_booking_delay = 10
meetings_agenda.maximal_booking_delay = 30
meetings_agenda.save()
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
assert len(resp.json['data']) == 54
meetings_agenda.minimal_booking_delay = 1
meetings_agenda.maximal_booking_delay = 56
meetings_agenda.save()
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
assert len(resp.json['data']) == 144
resp = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
dt = datetime.datetime.strptime(resp.json['data'][2]['id'].split(':')[1], '%Y-%m-%d-%H%M')
ev = Event(agenda=meetings_agenda, meeting_type=meeting_type,
places=1, full=False, start_datetime=make_aware(dt))
@ -111,7 +146,7 @@ def test_datetimes_api_meetings_agenda(app, meetings_agenda):
booking.save()
resp2 = app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
assert len(resp2.json['data']) == 161
assert len(resp2.json['data']) == 143
assert resp.json['data'][0] == resp2.json['data'][0]
assert resp.json['data'][1] == resp2.json['data'][1]
assert resp.json['data'][3] == resp2.json['data'][2]

View File

@ -83,13 +83,13 @@ def test_add_agenda(app, admin_user):
resp = resp.follow()
assert '<h2>Foo bar' in resp.body
def test_rename_agenda(app, admin_user):
def test_options_agenda(app, admin_user):
agenda = Agenda(label=u'Foo bar')
agenda.save()
app = login(app)
resp = app.get('/manage/', status=200)
resp = resp.click('Foo bar')
resp = resp.click('Rename')
resp = resp.click('Options')
assert resp.form['label'].value == 'Foo bar'
resp.form['label'] = 'Foo baz'
resp = resp.form.submit()