manager: display exceptions in day/month views (#39906)

This commit is contained in:
Frédéric Péters 2020-02-16 17:05:52 +01:00
parent 3d9ea06ec7
commit f6bb6282ac
5 changed files with 77 additions and 4 deletions

View File

@ -172,13 +172,17 @@ a.timeperiod-exception-all {
padding: 1ex;
position: absolute;
overflow: hidden;
&.opening-hours {
&.opening-hours, &.exception-hours {
z-index: 1;
background: #b1ea4d linear-gradient(135deg, #b1ea4d 0%, #459522 100%);
opacity: 0.6;
left: 0.5ex;
width: calc(100% - 1ex);
}
&.exception-hours {
background: #fee linear-gradient(135deg, #fee 0%, #fdd 100%);
text-align: center;
}
&.booking {
background: #eef linear-gradient(135deg, #eef 0%, #ddf 100%);
box-shadow: 0 0 1px 0 #2d2dad;

View File

@ -60,6 +60,11 @@
style="height: {{ slot.css_height }}%; top: {{ slot.css_top }}%;"
>{{slot.begin}} {{slot.end}}</div>
{% endfor %}
{% for slot in desk_info.exceptions %}
<div class="exception-hours"
style="height: {{ slot.css_height }}%; top: {{ slot.css_top }}%;"
>{% if slot.label %}<span class="exception-label">{{slot.label}}</span>{% endif %}</div>
{% endfor %}
{% endif %}
{% for booking in desk_info.bookings %}

View File

@ -26,6 +26,11 @@
{% for slot in day.infos.opening_hours %}
<div class="opening-hours" style="height:{{ slot.css_height|stringformat:".1f" }}%;top:{{ slot.css_top|stringformat:".1f" }}%;width:{{ slot.css_width|stringformat:".1f" }}%;left:{{ slot.css_left|stringformat:".1f" }}%;"></div>
{% endfor %}
{% for slot in day.infos.exceptions %}
<div class="exception-hours" style="height:{{ slot.css_height|stringformat:".1f" }}%;top:{{ slot.css_top|stringformat:".1f" }}%;width:{{ slot.css_width|stringformat:".1f" }}%;left:{{ slot.css_left|stringformat:".1f" }}%;" {% if slot.label %}title="{{ slot.label }}"{% endif %}></div>
{% endfor %}
{% for slot in day.infos.booked_slots %}
<div class="booking" style="left:{{ slot.css_left|stringformat:".1f" }}%;height:{{ slot.css_height|stringformat:".1f" }}%;top:{{ slot.css_top|stringformat:".1f" }}%;width:{{ slot.css_width|stringformat:".1f" }}%">
<span class="start-time">{{slot.booking.event.start_datetime|date:"TIME_FORMAT"}}</span>

View File

@ -380,7 +380,7 @@ class AgendaDayView(AgendaDateView, DayArchiveView):
# until the end of the last hour.
max_date += datetime.timedelta(hours=1)
desks = self.agenda.desk_set.all()
desks = self.agenda.desk_set.all().prefetch_related('timeperiodexception_set')
first = True
while current_date < max_date:
@ -399,6 +399,20 @@ class AgendaDayView(AgendaDateView, DayArchiveView):
'css_height': 100 * (opening_hour.end - opening_hour.begin).seconds // 3600,
}
)
# and exceptions for this desk
info['exceptions'] = []
for exception in desk.timeperiodexception_set.all():
if exception.end_datetime < start_date:
continue
if exception.start_datetime > max_date:
continue
start_max = max(start_date, exception.start_datetime)
end_min = min(max_date, exception.end_datetime)
exception.css_top = int(100 * (start_max - start_date).seconds // 3600)
exception.css_height = int(100 * (end_min - start_max).seconds // 3600)
info['exceptions'].append(exception)
infos.append(info)
info['bookings'] = bookings = [] # bookings for this desk
finish_datetime = current_date + interval
@ -511,10 +525,10 @@ class AgendaMonthView(AgendaDateView, MonthArchiveView):
'date': current_date,
'today': day.date() == datetime.date.today(),
'other_month': day.month != self.date.month,
'infos': {'opening_hours': [], 'booked_slots': []},
'infos': {'opening_hours': [], 'exceptions': [], 'booked_slots': []},
}
desks = self.agenda.desk_set.all()
desks = self.agenda.desk_set.all().prefetch_related('timeperiodexception_set')
desks_len = len(desks)
max_date = day.replace(hour=self.max_timeperiod.hour, minute=0)
@ -557,6 +571,19 @@ class AgendaMonthView(AgendaDateView, MonthArchiveView):
'css_left': left,
}
)
for exception in desk.timeperiodexception_set.all():
if exception.end_datetime < current_date:
continue
if exception.start_datetime > max_date:
continue
start_max = max(current_date, exception.start_datetime)
end_min = min(max_date, exception.end_datetime)
exception.css_top = int(100 * (start_max - current_date).seconds // 3600)
exception.css_height = int(100 * (end_min - start_max).seconds // 3600)
exception.css_width = width
exception.css_left = left
timetable['infos']['exceptions'].append(exception)
left += width + 1
period += interval

View File

@ -4,6 +4,7 @@ from __future__ import unicode_literals
import copy
import json
import os
import re
from django.contrib.auth.models import User, Group
from django.utils.encoding import force_text
@ -1724,6 +1725,23 @@ def test_agenda_day_view(app, admin_user, manager_user, api_user):
agenda.save()
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day), status=200)
# display exception
TimePeriodException.objects.create(
label='Exception for the afternoon',
desk=desk,
start_datetime=make_aware(datetime.datetime(date.year, date.month, date.day, 13, 0)),
end_datetime=make_aware(datetime.datetime(date.year, date.month, date.day, 23, 0)),
)
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day), status=200)
# day is displaying rows from 10am to 6pm,
# opening hours, 10am to 1pm gives top: 300%
# rest of the day, 1pm to 6(+1)pm gives 600%
assert resp.pyquery.find('.exception-hours')[0].attrib == {
'class': 'exception-hours',
'style': 'height: 600%; top: 300%;',
}
assert resp.pyquery.find('.exception-hours span')[0].text == 'Exception for the afternoon'
def test_agenda_day_view_late_meeting(app, admin_user, manager_user, api_user):
agenda = Agenda.objects.create(label='New Example', kind='meetings')
@ -1888,6 +1906,20 @@ def test_agenda_month_view(app, admin_user, manager_user, api_user):
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.id, today.year, today.month))
assert not 'No opening hours this month.' in resp.text
# display exception
TimePeriodException.objects.create(
label='Exception for a December day',
desk=desk,
start_datetime=make_aware(datetime.datetime(2018, 12, 15, 5, 0)),
end_datetime=make_aware(datetime.datetime(2018, 12, 15, 23, 0)),
)
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.id, today.year, today.month))
assert resp.pyquery.find('.exception-hours')[0].attrib == {
'class': 'exception-hours',
'style': 'height:800.0%;top:0.0%;width:48.0%;left:50.0%;',
'title': 'Exception for a December day',
}
def test_agenda_month_view_weekend(app, admin_user, manager_user, api_user):
agenda = Agenda.objects.create(label='Passeports', kind='meetings')