0001-manager-weekly-wiew-for-agendas-resources-33404.patch
chrono/agendas/migrations/0090_default_view.py | ||
---|---|---|
12 | 12 |
model_name='agenda', |
13 | 13 |
name='default_view', |
14 | 14 |
field=models.CharField( |
15 |
choices=[('day', 'Day view'), ('month', 'Month view'), ('open_events', 'Open events')], |
|
15 |
choices=[ |
|
16 |
('day', 'Day view'), |
|
17 |
('week', 'Week view'), |
|
18 |
('month', 'Month view'), |
|
19 |
('open_events', 'Open events'), |
|
20 |
], |
|
16 | 21 |
max_length=20, |
17 | 22 |
verbose_name='Default view', |
18 | 23 |
), |
chrono/agendas/models.py | ||
---|---|---|
70 | 70 | |
71 | 71 |
AGENDA_VIEWS = ( |
72 | 72 |
('day', _('Day view')), |
73 |
('week', _('Week view')), |
|
73 | 74 |
('month', _('Month view')), |
74 | 75 |
('open_events', _('Open events')), |
75 | 76 |
) |
chrono/manager/static/js/chrono.manager.js | ||
---|---|---|
10 | 10 |
$('.date-picker button').on('click', function() { |
11 | 11 |
if ($('[name=day]').val()) { |
12 | 12 |
window.location = '../../../' + $('[name=year]').val() + '/' + $('[name=month]').val() + '/' + $('[name=day]').val() + '/'; |
13 |
} else { |
|
13 |
} else if ($('[name=month]').val()) {
|
|
14 | 14 |
window.location = '../../' + $('[name=year]').val() + '/' + $('[name=month]').val() + '/'; |
15 |
} else { |
|
16 |
window.location = '../../../' + $('[name=year]').val() + '/week/' + $('[name=week]').val() + '/'; |
|
15 | 17 |
} |
16 | 18 |
return false; |
17 | 19 |
}); |
chrono/manager/templates/chrono/manager_agenda_week_view.html | ||
---|---|---|
1 |
{% extends "chrono/manager_agenda_view.html" %} |
|
2 |
{% load i18n %} |
|
3 | ||
4 |
{% block bodyargs %}class="weekview"{% endblock %} |
|
5 | ||
6 |
{% block breadcrumb %} |
|
7 |
{{ block.super }} |
|
8 |
<a>{{ view.date|date:"F Y" }}</a> |
|
9 |
{% endblock %} |
|
10 | ||
11 |
{% block appbar %} |
|
12 |
<h2> |
|
13 |
<a href="{{ view.get_previous_week_url }}">←</a> |
|
14 |
<span class="date-title">{{ view.date|date:_("Y \w\e\e\k W") }}</span> |
|
15 |
{% with selected_week=view.date|date:"W" selected_year=view.date|date:"Y" %} |
|
16 |
<div class="date-picker" style="display: none"> |
|
17 |
<select name="week">{% for week, week_label in view.get_weeks %}<option value="{{ week }}" {% if selected_week == week %}selected{% endif %}>{{ week_label }}</option>{% endfor %}</select> |
|
18 |
<select name="year">{% for year in view.get_years %}<option value="{{ year }}" {% if selected_year == year %}selected{% endif %}>{{ year }}</option>{% endfor %}</select> |
|
19 |
<button>{% trans 'Set Date' %}</button> |
|
20 |
</div> |
|
21 |
{% endwith %} |
|
22 |
<a href="{{ view.get_next_week_url }}">→</a> |
|
23 |
</h2> |
|
24 |
<span class="actions"> |
|
25 |
{% block actions %} |
|
26 |
{% if user_can_manage %} |
|
27 |
<a href="{{ agenda.get_settings_url }}">{% trans 'Settings' %}</a> |
|
28 |
{% endif %} |
|
29 |
<a href="" onclick="window.print()">{% trans 'Print' %}</a> |
|
30 |
{% endblock %} |
|
31 |
</span> |
|
32 |
{% endblock %} |
chrono/manager/templates/chrono/manager_events_agenda_day_view.html | ||
---|---|---|
11 | 11 |
{{ block.super }} |
12 | 12 |
<a href="{% url 'chrono-manager-agenda-open-events-view' pk=agenda.pk %}">{% trans 'Open events' %}</a> |
13 | 13 |
<a href="{% url 'chrono-manager-agenda-month-view' pk=agenda.pk year=view.date|date:"Y" month=view.date|date:"n" %}">{% trans 'Month view' %}</a> |
14 |
<a href="{% url 'chrono-manager-agenda-week-view' pk=agenda.pk year=view.date|date:"Y" week=view.date|date:"W" %}">{% trans 'Week view' %}</a> |
|
14 | 15 |
{% endblock %} |
15 | 16 | |
16 | 17 |
{% block content %} |
chrono/manager/templates/chrono/manager_events_agenda_month_view.html | ||
---|---|---|
11 | 11 |
</ul> |
12 | 12 |
{{ block.super }} |
13 | 13 |
<a href="{% url 'chrono-manager-agenda-open-events-view' pk=agenda.pk %}">{% trans 'Open events' %}</a> |
14 |
<a href="{% url 'chrono-manager-agenda-week-view' pk=agenda.pk year=view.date|date:"Y" week=view.date|date:"W" %}">{% trans 'Week view' %}</a> |
|
14 | 15 |
<a href="{% url 'chrono-manager-agenda-day-view' pk=agenda.pk year=view.date|date:"Y" month=view.date|date:"m" day=view.date|date:"d" %}">{% trans 'Day view' %}</a> |
15 | 16 |
{% endblock %} |
16 | 17 |
chrono/manager/templates/chrono/manager_events_agenda_week_view.html | ||
---|---|---|
1 |
{% extends "chrono/manager_agenda_week_view.html" %} |
|
2 |
{% load i18n %} |
|
3 | ||
4 |
{% block actions %} |
|
5 |
<a class="extra-actions-menu-opener"></a> |
|
6 |
<ul class="extra-actions-menu"> |
|
7 |
<li><a href="{% url 'chrono-manager-event-cancellation-report-list' pk=agenda.pk %}">{% trans 'Cancellation error reports' %}</a></li> |
|
8 |
{% if agenda.subscriptions.exists %} |
|
9 |
<li><a href="{% url 'chrono-manager-events-timesheet' pk=agenda.pk %}">{% trans 'Timesheet' %}</a></li> |
|
10 |
{% endif %} |
|
11 |
</ul> |
|
12 |
{{ block.super }} |
|
13 |
<a href="{% url 'chrono-manager-agenda-open-events-view' pk=agenda.pk %}">{% trans 'Open events' %}</a> |
|
14 |
<a href="{% url 'chrono-manager-agenda-month-view' pk=agenda.pk year=view.date|date:"Y" month=view.date|date:"m" %}">{% trans 'Month view' %}</a> |
|
15 |
<a href="{% url 'chrono-manager-agenda-day-view' pk=agenda.pk year=view.date|date:"Y" month=view.date|date:"m" day=view.date|date:"d" %}">{% trans 'Day view' %}</a> |
|
16 |
{% endblock %} |
|
17 | ||
18 |
{% block content %} |
|
19 |
<div class="section"> |
|
20 |
<h3>{% trans "Events" %}</h3> |
|
21 |
{% include 'chrono/manager_event_cancellation_report_notice.html' %} |
|
22 |
<div> |
|
23 |
{% if object_list %} |
|
24 |
<ul class="objects-list single-links"> |
|
25 |
{% for object in object_list %} |
|
26 |
{% if object.is_exception %} |
|
27 |
<li><a class="disabled">{% trans "Exception:"%} {{ object }}</a></li> |
|
28 |
{% else %} |
|
29 |
{% include 'chrono/manager_agenda_event_fragment.html' with event=object %} |
|
30 |
{% endif %} |
|
31 |
{% endfor %} |
|
32 |
</ul> |
|
33 |
{% include "gadjo/pagination.html" %} |
|
34 |
{% else %} |
|
35 |
<div class="big-msg-info"> |
|
36 |
{% blocktrans trimmed %} |
|
37 |
This week doesn't have any event configured. |
|
38 |
{% endblocktrans %} |
|
39 |
</div> |
|
40 |
{% endif %} |
|
41 |
</div> |
|
42 |
</div> |
|
43 | ||
44 |
{% endblock %} |
chrono/manager/templates/chrono/manager_meetings_agenda_day_view.html | ||
---|---|---|
4 | 4 |
{% block actions %} |
5 | 5 |
{{ block.super }} |
6 | 6 |
<a href="{% url 'chrono-manager-agenda-month-view' pk=agenda.id year=view.date|date:"Y" month=view.date|date:"n" %}">{% trans 'Month view' %}</a> |
7 |
<a href="{% url 'chrono-manager-agenda-week-view' pk=agenda.id year=view.date|date:"Y" week=view.date|date:"W" %}">{% trans 'Week view' %}</a> |
|
7 | 8 |
{% endblock %} |
8 | 9 | |
9 | 10 |
{% block content %} |
chrono/manager/templates/chrono/manager_meetings_agenda_month_view.html | ||
---|---|---|
3 | 3 | |
4 | 4 |
{% block actions %} |
5 | 5 |
{{ block.super }} |
6 |
<a href="{% url 'chrono-manager-agenda-week-view' pk=agenda.id year=view.date|date:"Y" week=view.date|date:"W" %}">{% trans 'Week view' %}</a> |
|
6 | 7 |
<a href="{% url 'chrono-manager-agenda-day-view' pk=agenda.id year=view.date|date:"Y" month=view.date|date:"m" day=view.date|date:"d" %}">{% trans 'Day view' %}</a> |
7 | 8 |
{% endblock %} |
8 | 9 | |
9 | 10 |
{% block content %} |
10 | ||
11 |
{% for week_days in view.get_timetable_infos %} |
|
12 |
{% if forloop.first %} |
|
13 |
<table class="agenda-table month-view {% if single_desk %}single-desk{% endif %}"> |
|
14 |
<tbody> |
|
15 |
{% endif %} |
|
16 |
<tr> |
|
17 |
<th></th> |
|
18 |
{% for day in week_days.days %} |
|
19 |
<th class="weekday {% if day.today %}today{% endif %}">{% if not day.other_month %}<a href="{% url 'chrono-manager-agenda-day-view' pk=agenda.id year=day.date|date:"Y" month=day.date|date:"m" day=day.date|date:"d" %}">{{ day.date|date:"l j" }}</a>{% endif %}</th> |
|
20 |
{% endfor %} |
|
21 |
</tr> |
|
22 |
{% for hour in week_days.periods %} |
|
23 |
<tr class="{% cycle 'odd' 'even' %}"> |
|
24 |
<th class="hour">{{ hour|date:"TIME_FORMAT" }}</th> |
|
25 |
{% for day in week_days.days %} |
|
26 |
<td class="{% if day.other_month %}other-month{% endif %} {% if day.today %}today{% endif %}"> |
|
27 |
{% if forloop.parentloop.first %} |
|
28 |
{% for slot in day.infos.opening_hours %} |
|
29 |
<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> |
|
30 |
{% endfor %} |
|
31 | ||
32 |
{% for slot in day.infos.exceptions %} |
|
33 |
<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> |
|
34 |
{% endfor %} |
|
35 | ||
36 |
{% for slot in day.infos.booked_slots %} |
|
37 |
<div class="booking{% if slot.booking.color %} booking-color-{{ slot.booking.color.index }}{% endif %}" style="left:{{ slot.css_left|stringformat:".1f" }}%;height:{{ slot.css_height|stringformat:".1f" }}%;min-height:{{ slot.css_height|stringformat:".1f" }}%;top:{{ slot.css_top|stringformat:".1f" }}%;width:{{ slot.css_width|stringformat:".1f" }}%;"> |
|
38 |
<span class="start-time">{{slot.booking.event.start_datetime|date:"TIME_FORMAT"}}</span> |
|
39 |
<a {% if slot.booking.get_backoffice_url %}href="{{slot.booking.get_backoffice_url}}"{% endif %}>{{ slot.booking.get_user_block }}</a> |
|
40 |
<a rel="popup" class="cancel" href="{% url 'chrono-manager-booking-cancel' pk=slot.booking.event.agenda_id booking_pk=slot.booking.id %}?next={{ request.path }}">{% trans "Cancel" %}</a> |
|
41 |
{% if not single_desk %}<span class="desk">{{ slot.desk }}</span>{% endif %} |
|
42 |
{% if slot.booking.color %}<span class="booking-color-label booking-bg-color-{{ slot.booking.color.index }}">{{ slot.booking.color }}</span>{% endif %} |
|
43 |
</div> |
|
44 |
{% endfor %} |
|
45 |
{% endif %} |
|
46 |
</td> |
|
47 |
{% endfor %} |
|
48 |
</tr> |
|
49 |
{% endfor %} |
|
50 |
{% resetcycle %} |
|
51 |
{% if forloop.last %} |
|
52 |
</tbody> |
|
53 |
</table> |
|
54 |
{% endif %} |
|
55 | ||
56 |
{% empty %} |
|
57 |
<div class="closed-for-the-day"> |
|
58 |
<p>{% trans "No opening hours this month." %}</p> |
|
59 |
</div> |
|
60 |
{% endfor %} |
|
61 | ||
62 |
{% if booking_colors %} |
|
63 |
{% include "chrono/booking_color_legend.html" with colors=booking_colors %} |
|
64 |
{% endif %} |
|
65 | ||
11 |
{% include "chrono/manager_meetings_agenda_week_timetable_fragment.html" %} |
|
66 | 12 |
{% endblock %} |
chrono/manager/templates/chrono/manager_meetings_agenda_week_timetable_fragment.html | ||
---|---|---|
1 |
{% load i18n %} |
|
2 |
{% for week_days in view.get_timetable_infos %} |
|
3 |
{% if forloop.first %} |
|
4 |
<table class="agenda-table {{ kind }}-view {% if kind == 'week' %}hourspan-{{ hour_span }}{% endif %} {% if single_desk %}single-desk{% endif %}"> |
|
5 |
<tbody> |
|
6 |
{% endif %} |
|
7 |
<tr> |
|
8 |
<th></th> |
|
9 |
{% for day in week_days.days %} |
|
10 |
<th class="weekday {% if day.today %}today{% endif %}">{% if kind == 'month' and not day.other_month or kind == 'week' %}<a href="{% url 'chrono-manager-agenda-day-view' pk=agenda.id year=day.date|date:"Y" month=day.date|date:"m" day=day.date|date:"d" %}">{{ day.date|date:"l j" }}{% if kind == 'week' %}<br />{{ day.date|date:"F" }}{% endif %}</a>{% endif %}</th> |
|
11 |
{% endfor %} |
|
12 |
</tr> |
|
13 |
{% for hour in week_days.periods %} |
|
14 |
<tr class="{% cycle 'odd' 'even' %}"> |
|
15 |
<th class="hour">{{ hour|date:"TIME_FORMAT" }}</th> |
|
16 |
{% for day in week_days.days %} |
|
17 |
<td class="{% if kind == 'month' and day.other_month %}other-month{% endif %} {% if day.today %}today{% endif %}"> |
|
18 |
{% if forloop.parentloop.first %} |
|
19 |
{% for slot in day.infos.opening_hours %} |
|
20 |
<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> |
|
21 |
{% endfor %} |
|
22 | ||
23 |
{% for slot in day.infos.exceptions %} |
|
24 |
<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> |
|
25 |
{% endfor %} |
|
26 | ||
27 |
{% for slot in day.infos.booked_slots %} |
|
28 |
<div class="booking{% if slot.booking.color %} booking-color-{{ slot.booking.color.index }}{% endif %}" style="left:{{ slot.css_left|stringformat:".1f" }}%;height:{{ slot.css_height|stringformat:".1f" }}%;min-height:{{ slot.css_height|stringformat:".1f" }}%;top:{{ slot.css_top|stringformat:".1f" }}%;width:{{ slot.css_width|stringformat:".1f" }}%;"> |
|
29 |
<span class="start-time">{{slot.booking.event.start_datetime|date:"TIME_FORMAT"}}</span> |
|
30 |
<a {% if slot.booking.get_backoffice_url %}href="{{slot.booking.get_backoffice_url}}"{% endif %}>{{ slot.booking.get_user_block }}</a> |
|
31 |
<a rel="popup" class="cancel" href="{% url 'chrono-manager-booking-cancel' pk=slot.booking.event.agenda_id booking_pk=slot.booking.id %}?next={{ request.path }}">{% trans "Cancel" %}</a> |
|
32 |
{% if not single_desk %}<span class="desk">{{ slot.desk }}</span>{% endif %} |
|
33 |
{% if slot.booking.color %}<span class="booking-color-label booking-bg-color-{{ slot.booking.color.index }}">{{ slot.booking.color }}</span>{% endif %} |
|
34 |
</div> |
|
35 |
{% endfor %} |
|
36 |
{% endif %} |
|
37 |
</td> |
|
38 |
{% endfor %} |
|
39 |
</tr> |
|
40 |
{% endfor %} |
|
41 |
{% resetcycle %} |
|
42 |
{% if forloop.last %} |
|
43 |
</tbody> |
|
44 |
</table> |
|
45 |
{% endif %} |
|
46 | ||
47 |
{% empty %} |
|
48 |
<div class="closed-for-the-day"> |
|
49 |
{% if kind == 'month' %} |
|
50 |
<p>{% trans "No opening hours this month." %}</p> |
|
51 |
{% else %} |
|
52 |
<p>{% trans "No opening hours this week." %}</p> |
|
53 |
{% endif %} |
|
54 |
</div> |
|
55 |
{% endfor %} |
|
56 | ||
57 |
{% if booking_colors %} |
|
58 |
{% include "chrono/booking_color_legend.html" with colors=booking_colors %} |
|
59 |
{% endif %} |
chrono/manager/templates/chrono/manager_meetings_agenda_week_view.html | ||
---|---|---|
1 |
{% extends "chrono/manager_agenda_week_view.html" %} |
|
2 |
{% load i18n %} |
|
3 | ||
4 |
{% block actions %} |
|
5 |
{{ block.super }} |
|
6 |
<a href="{% url 'chrono-manager-agenda-month-view' pk=agenda.id year=view.date|date:"Y" month=view.date|date:"m" %}">{% trans 'Month view' %}</a> |
|
7 |
<a href="{% url 'chrono-manager-agenda-day-view' pk=agenda.id year=view.date|date:"Y" month=view.date|date:"m" day=view.date|date:"d" %}">{% trans 'Day view' %}</a> |
|
8 |
{% endblock %} |
|
9 | ||
10 |
{% block content %} |
|
11 |
{% include "chrono/manager_meetings_agenda_week_timetable_fragment.html" %} |
|
12 |
{% endblock %} |
chrono/manager/templates/chrono/manager_resource_day_view.html | ||
---|---|---|
23 | 23 |
{% endblock %} |
24 | 24 |
{% block appbar-extras %} |
25 | 25 |
<a href="{% url 'chrono-manager-resource-month-view' pk=resource.pk year=view.date|date:"Y" month=view.date|date:"n" %}">{% trans 'Month view' %}</a> |
26 |
<a href="{% url 'chrono-manager-resource-week-view' pk=resource.pk year=view.date|date:"Y" week=view.date|date:"W" %}">{% trans 'Week view' %}</a> |
|
26 | 27 |
{% endblock %} |
27 | 28 | |
28 | 29 |
{% block content %} |
chrono/manager/templates/chrono/manager_resource_detail.html | ||
---|---|---|
22 | 22 |
{% endif %} |
23 | 23 |
{% now "Y" as today_year %} |
24 | 24 |
{% now "n" as today_month %} |
25 |
{% now "W" as today_week %} |
|
25 | 26 |
{% now "j" as today_day %} |
26 | 27 |
<a href="{% url 'chrono-manager-resource-month-view' pk=resource.pk year=today_year month=today_month %}">{% trans 'Month view' %}</a> |
28 |
<a href="{% url 'chrono-manager-resource-week-view' pk=resource.pk year=today_year week=today_week %}">{% trans 'Week view' %}</a> |
|
27 | 29 |
<a href="{% url 'chrono-manager-resource-day-view' pk=resource.pk year=today_year month=today_month day=today_day %}">{% trans 'Day view' %}</a> |
28 | 30 |
{% endblock %} |
29 | 31 |
</span> |
chrono/manager/templates/chrono/manager_resource_month_view.html | ||
---|---|---|
23 | 23 |
</h2> |
24 | 24 |
{% endblock %} |
25 | 25 |
{% block appbar-extras %} |
26 |
<a href="{% url 'chrono-manager-resource-day-view' pk=resource.pk year=view.date|date:"Y" month=view.date|date:"n" day=1 %}">{% trans 'Day view' %}</a> |
|
26 |
<a href="{% url 'chrono-manager-resource-week-view' pk=resource.pk year=view.date|date:"Y" week=view.date|date:"W" %}">{% trans 'Week view' %}</a> |
|
27 |
<a href="{% url 'chrono-manager-resource-day-view' pk=resource.pk year=view.date|date:"Y" month=view.date|date:"n" day=view.date|date:"d" %}">{% trans 'Day view' %}</a> |
|
27 | 28 |
{% endblock %} |
28 | 29 | |
29 | 30 |
{% block content %} |
30 | ||
31 |
{% for week_days in view.get_timetable_infos %} |
|
32 | ||
33 |
{% if forloop.first %} |
|
34 |
<table class="agenda-table month-view single-desk"> |
|
35 |
<tbody> |
|
36 |
{% endif %} |
|
37 |
<tr> |
|
38 |
<th></th> |
|
39 |
{% for day in week_days.days %} |
|
40 |
<th class="weekday {% if day.today %}today{% endif %}">{% if not day.other_month %}<a href="{% url 'chrono-manager-resource-day-view' pk=resource.pk year=day.date|date:"Y" month=day.date|date:"m" day=day.date|date:"j" %}">{{ day.date|date:"l j" }}</a>{% endif %}</th> |
|
41 |
{% endfor %} |
|
42 |
</tr> |
|
43 |
{% for hour in week_days.periods %} |
|
44 |
<tr class="{% cycle 'odd' 'even' %}"> |
|
45 |
<th class="hour">{{ hour|date:"TIME_FORMAT" }}</th> |
|
46 |
{% for day in week_days.days %} |
|
47 |
<td class="{% if day.other_month %}other-month{% endif %} {% if day.today %}today{% endif %}"> |
|
48 |
{% if forloop.parentloop.first %} |
|
49 |
{% for slot in day.infos.booked_slots %} |
|
50 |
<div class="booking" style="height:{{ slot.css_height|stringformat:".1f" }}%;min-height:{{ slot.css_height|stringformat:".1f" }}%;top:{{ slot.css_top|stringformat:".1f" }}%"> |
|
51 |
<span class="start-time">{{ slot.booking.event.start_datetime|date:"TIME_FORMAT" }}</span> |
|
52 |
<a {% if slot.booking.get_backoffice_url %}href="{{ slot.booking.get_backoffice_url }}"{% endif %}>{{ slot.booking.get_user_block }}</a> |
|
53 |
</div> |
|
54 |
{% endfor %} |
|
55 |
{% endif %} |
|
56 |
</td> |
|
57 |
{% endfor %} |
|
58 |
</tr> |
|
59 |
{% endfor %} |
|
60 |
{% if forloop.last %} |
|
61 |
</tbody> |
|
62 |
</table> |
|
63 |
{% endif %} |
|
64 |
{% empty %} |
|
65 |
<div class="closed-for-the-day"> |
|
66 |
<p>{% trans "No bookings this month." %}</p> |
|
67 |
</div> |
|
68 |
{% endfor %} |
|
69 | ||
31 |
{% include "chrono/manager_resource_week_timetable_fragment.html" %} |
|
70 | 32 |
{% endblock %} |
chrono/manager/templates/chrono/manager_resource_week_timetable_fragment.html | ||
---|---|---|
1 |
{% load i18n %} |
|
2 |
{% for week_days in view.get_timetable_infos %} |
|
3 | ||
4 |
{% if forloop.first %} |
|
5 |
<table class="agenda-table {{ kind }}-view {% if kind == 'week' %}hourspan-{{ hour_span }}{% endif %} single-desk"> |
|
6 |
<tbody> |
|
7 |
{% endif %} |
|
8 |
<tr> |
|
9 |
<th></th> |
|
10 |
{% for day in week_days.days %} |
|
11 |
<th class="weekday {% if day.today %}today{% endif %}">{% if kind == 'month' and not day.other_month or kind == 'week' %}<a href="{% url 'chrono-manager-resource-day-view' pk=resource.pk year=day.date|date:"Y" month=day.date|date:"m" day=day.date|date:"d" %}">{{ day.date|date:"l j" }}{% if kind == 'week' %}<br />{{ day.date|date:"F" }}{% endif %}</a>{% endif %}</th> |
|
12 |
{% endfor %} |
|
13 |
</tr> |
|
14 |
{% for hour in week_days.periods %} |
|
15 |
<tr class="{% cycle 'odd' 'even' %}"> |
|
16 |
<th class="hour">{{ hour|date:"TIME_FORMAT" }}</th> |
|
17 |
{% for day in week_days.days %} |
|
18 |
<td class="{% if kind == 'month' and day.other_month %}other-month{% endif %} {% if day.today %}today{% endif %}"> |
|
19 |
{% if forloop.parentloop.first %} |
|
20 |
{% for slot in day.infos.booked_slots %} |
|
21 |
<div class="booking" style="height:{{ slot.css_height|stringformat:".1f" }}%;min-height:{{ slot.css_height|stringformat:".1f" }}%;top:{{ slot.css_top|stringformat:".1f" }}%"> |
|
22 |
<span class="start-time">{{ slot.booking.event.start_datetime|date:"TIME_FORMAT" }}</span> |
|
23 |
<a {% if slot.booking.get_backoffice_url %}href="{{ slot.booking.get_backoffice_url }}"{% endif %}>{{ slot.booking.get_user_block }}</a> |
|
24 |
</div> |
|
25 |
{% endfor %} |
|
26 |
{% endif %} |
|
27 |
</td> |
|
28 |
{% endfor %} |
|
29 |
</tr> |
|
30 |
{% endfor %} |
|
31 |
{% if forloop.last %} |
|
32 |
</tbody> |
|
33 |
</table> |
|
34 |
{% endif %} |
|
35 |
{% empty %} |
|
36 |
<div class="closed-for-the-day"> |
|
37 |
{% if kind == 'month' %} |
|
38 |
<p>{% trans "No bookings this month." %}</p> |
|
39 |
{% else %} |
|
40 |
<p>{% trans "No bookings this week." %}</p> |
|
41 |
{% endif %} |
|
42 |
</div> |
|
43 |
{% endfor %} |
chrono/manager/templates/chrono/manager_resource_week_view.html | ||
---|---|---|
1 |
{% extends "chrono/manager_resource_detail.html" %} |
|
2 |
{% load i18n %} |
|
3 | ||
4 |
{% block bodyargs %}class="weekview"{% endblock %} |
|
5 | ||
6 |
{% block breadcrumb %} |
|
7 |
{{ block.super }} |
|
8 |
<a>{{ view.date|date:"F Y" }}</a> |
|
9 |
{% endblock %} |
|
10 | ||
11 |
{% block appbar-title %} |
|
12 |
<h2> |
|
13 |
<a href="{{ view.get_previous_week_url }}">←</a> |
|
14 |
<span class="date-title">{{ view.date|date:_("Y \w\e\e\k W") }}</span> |
|
15 |
{% with selected_week=view.date|date:"W" selected_year=view.date|date:"Y" %} |
|
16 |
<div class="date-picker" style="display: none"> |
|
17 |
<select name="week">{% for week, week_label in view.get_weeks %}<option value="{{ week }}" {% if selected_week == week %}selected{% endif %}>{{ week_label }}</option>{% endfor %}</select> |
|
18 |
<select name="year">{% for year in view.get_years %}<option value="{{ year }}" {% if selected_year == year %}selected{% endif %}>{{ year }}</option>{% endfor %}</select> |
|
19 |
<button>{% trans 'Set Date' %}</button> |
|
20 |
</div> |
|
21 |
{% endwith %} |
|
22 |
<a href="{{ view.get_next_week_url }}">→</a> |
|
23 |
</h2> |
|
24 |
{% endblock %} |
|
25 |
{% block appbar-extras %} |
|
26 |
<a href="{% url 'chrono-manager-resource-month-view' pk=resource.pk year=view.date|date:"Y" month=view.date|date:"n" %}">{% trans 'Month view' %}</a> |
|
27 |
<a href="{% url 'chrono-manager-resource-day-view' pk=resource.pk year=view.date|date:"Y" month=view.date|date:"n" day=view.date|date:"d" %}">{% trans 'Day view' %}</a> |
|
28 |
{% endblock %} |
|
29 | ||
30 |
{% block content %} |
|
31 |
{% include "chrono/manager_resource_week_timetable_fragment.html" %} |
|
32 |
{% endblock %} |
chrono/manager/urls.py | ||
---|---|---|
73 | 73 |
views.resource_monthly_view, |
74 | 74 |
name='chrono-manager-resource-month-view', |
75 | 75 |
), |
76 |
re_path( |
|
77 |
r'^resource/(?P<pk>\d+)/(?P<year>[0-9]{4})/week/(?P<week>[0-9]+)/$', |
|
78 |
views.resource_weekly_view, |
|
79 |
name='chrono-manager-resource-week-view', |
|
80 |
), |
|
76 | 81 |
re_path( |
77 | 82 |
r'^resource/(?P<pk>\d+)/(?P<year>[0-9]{4})/(?P<month>[0-9]+)/(?P<day>[0-9]+)/$', |
78 | 83 |
views.resource_day_view, |
... | ... | |
107 | 112 |
views.agenda_monthly_view, |
108 | 113 |
name='chrono-manager-agenda-month-view', |
109 | 114 |
), |
115 |
path( |
|
116 |
'agendas/<int:pk>/week/', |
|
117 |
views.agenda_week_redirect_view, |
|
118 |
name='chrono-manager-agenda-week-redirect-view', |
|
119 |
), |
|
120 |
re_path( |
|
121 |
r'^agendas/(?P<pk>\d+)/(?P<year>[0-9]{4})/week/(?P<week>[0-9]+)/$', |
|
122 |
views.agenda_weekly_view, |
|
123 |
name='chrono-manager-agenda-week-view', |
|
124 |
), |
|
110 | 125 |
path( |
111 | 126 |
'agendas/<int:pk>/day/', |
112 | 127 |
views.agenda_day_redirect_view, |
chrono/manager/views.py | ||
---|---|---|
57 | 57 |
TemplateView, |
58 | 58 |
UpdateView, |
59 | 59 |
View, |
60 |
WeekArchiveView, |
|
60 | 61 |
) |
61 | 62 |
from django.views.generic.dates import MonthMixin, YearMixin |
62 | 63 |
from weasyprint import HTML |
... | ... | |
250 | 251 |
def get_months(self): |
251 | 252 |
return [(str(x), MONTHS[x]) for x in range(1, 13)] |
252 | 253 | |
254 |
def get_weeks(self): |
|
255 |
return [(str(x), _('Week %s') % x) for x in range(1, 53)] |
|
256 | ||
253 | 257 |
def get_years(self): |
254 | 258 |
year = now().year |
255 | 259 |
return [str(x) for x in range(year - 1, year + 5)] |
... | ... | |
384 | 388 |
resource_day_view = ResourceDayView.as_view() |
385 | 389 | |
386 | 390 | |
387 |
class ResourceMonthView(DateMixin, MonthArchiveView): |
|
388 |
template_name = 'chrono/manager_resource_month_view.html' |
|
389 |
model = Event |
|
390 |
month_format = '%m' |
|
391 |
date_field = 'start_datetime' |
|
392 |
allow_empty = True |
|
393 |
allow_future = True |
|
394 | ||
395 |
def dispatch(self, request, *args, **kwargs): |
|
396 |
self.resource = get_object_or_404(Resource, pk=kwargs['pk']) |
|
397 |
if not self.resource.can_be_viewed(request.user): |
|
398 |
raise PermissionDenied() |
|
399 |
try: |
|
400 |
self.date = make_aware( |
|
401 |
datetime.datetime.strptime( |
|
402 |
'%s-%s-%s 06:00' % (self.get_year(), self.get_month(), 1), '%Y-%m-%d %H:%M' |
|
403 |
) |
|
404 |
) |
|
405 |
except ValueError: |
|
406 |
raise Http404 |
|
407 |
return super().dispatch(request, *args, **kwargs) |
|
408 | ||
391 |
class ResourceWeekMonthMixin: |
|
409 | 392 |
def get_queryset(self): |
410 | 393 |
queryset = ( |
411 | 394 |
self.resource.event_set.all() |
... | ... | |
418 | 401 |
context = super().get_context_data(**kwargs) |
419 | 402 | |
420 | 403 |
context['resource'] = self.resource |
421 | ||
422 |
return context |
|
423 | ||
424 |
def get_previous_month_url(self): |
|
425 |
previous_month = self.get_previous_month(self.date.date()) |
|
426 |
return reverse( |
|
427 |
'chrono-manager-resource-month-view', |
|
428 |
kwargs={'pk': self.resource.pk, 'year': previous_month.year, 'month': previous_month.month}, |
|
404 |
context['kind'] = self.kind |
|
405 |
context['hour_span'] = 1 |
|
406 |
durations = MeetingType.objects.filter(agenda__resources=self.resource).values_list( |
|
407 |
'duration', flat=True |
|
429 | 408 |
) |
409 |
if durations: |
|
410 |
gcd = durations[0] |
|
411 |
for duration in durations[1:]: |
|
412 |
gcd = math.gcd(duration, gcd) |
|
413 |
context['hour_span'] = max(60 // gcd, 1) |
|
430 | 414 | |
431 |
def get_next_month_url(self): |
|
432 |
next_month = self.get_next_month(self.date.date()) |
|
433 |
return reverse( |
|
434 |
'chrono-manager-resource-month-view', |
|
435 |
kwargs={'pk': self.resource.pk, 'year': next_month.year, 'month': next_month.month}, |
|
436 |
) |
|
415 |
return context |
|
437 | 416 | |
438 | 417 |
def get_timetable_infos(self): |
439 | 418 |
interval = datetime.timedelta(minutes=60) |
... | ... | |
469 | 448 |
hide_weekend = hide_weekend_timeperiod and hide_weekend_event |
470 | 449 | |
471 | 450 |
# avoid displaying empty first week |
472 |
first_week_offset = int( |
|
473 |
(hide_sunday and self.date.weekday() == 6) or (hide_weekend and self.date.weekday() == 5) |
|
474 |
) |
|
475 | ||
451 |
first_week_offset = 0 |
|
476 | 452 |
first_week_number = self.date.isocalendar()[1] |
477 |
if first_week_number >= 52: |
|
478 |
first_week_number = 0 |
|
479 |
last_month_day = self.get_next_month(self.date.date()) - datetime.timedelta(days=1) |
|
480 |
last_week_number = last_month_day.isocalendar()[1] |
|
453 |
last_week_number = first_week_number |
|
454 |
if self.kind == 'month': |
|
455 |
first_week_offset = int( |
|
456 |
(hide_sunday and self.date.weekday() == 6) or (hide_weekend and self.date.weekday() == 5) |
|
457 |
) |
|
458 |
if first_week_number >= 52: |
|
459 |
first_week_number = 0 |
|
460 |
last_day = self.get_next(self.date.date()) - datetime.timedelta(days=1) |
|
461 |
last_week_number = last_day.isocalendar()[1] |
|
481 | 462 | |
482 |
if last_week_number < first_week_number: # new year |
|
483 |
last_week_number = 53 |
|
463 |
if last_week_number < first_week_number: # new year
|
|
464 |
last_week_number = 53
|
|
484 | 465 | |
485 | 466 |
for week_number in range(first_week_number + first_week_offset, last_week_number + 1): |
486 | 467 |
yield self.get_week_timetable_infos( |
... | ... | |
528 | 509 |
# until the end of the last hour. |
529 | 510 |
max_date += datetime.timedelta(hours=1) |
530 | 511 | |
531 |
# compute booking and opening hours only for current month |
|
532 |
if self.date.month != day.month:
|
|
512 |
# compute booking and opening hours only for current month/week
|
|
513 |
if self.kind == 'month' and timetable['other_month']:
|
|
533 | 514 |
return timetable |
534 | 515 | |
535 | 516 |
while period <= max_date: |
... | ... | |
552 | 533 |
return timetable |
553 | 534 | |
554 | 535 | |
536 |
class ResourceWeekView(ResourceWeekMonthMixin, DateMixin, WeekArchiveView): |
|
537 |
template_name = 'chrono/manager_resource_week_view.html' |
|
538 |
model = Event |
|
539 |
week_format = '%W' |
|
540 |
date_field = 'start_datetime' |
|
541 |
allow_empty = True |
|
542 |
allow_future = True |
|
543 |
kind = 'week' |
|
544 | ||
545 |
def dispatch(self, request, *args, **kwargs): |
|
546 |
self.resource = get_object_or_404(Resource, pk=kwargs['pk']) |
|
547 |
if not self.resource.can_be_viewed(request.user): |
|
548 |
raise PermissionDenied() |
|
549 |
try: |
|
550 |
date = datetime.datetime.strptime('%s-W%s-1' % (self.get_year(), self.get_week()), "%Y-W%W-%w") |
|
551 |
self.date = make_aware( |
|
552 |
datetime.datetime.strptime( |
|
553 |
'%s-%s-%s 06:00' % (self.get_year(), date.month, date.day), '%Y-%m-%d %H:%M' |
|
554 |
) |
|
555 |
) |
|
556 |
except ValueError: |
|
557 |
raise Http404 |
|
558 |
return super().dispatch(request, *args, **kwargs) |
|
559 | ||
560 |
def get_previous_week_url(self): |
|
561 |
previous_week = self.get_previous_week(self.date.date()) |
|
562 |
return reverse( |
|
563 |
'chrono-manager-resource-week-view', |
|
564 |
kwargs={'pk': self.resource.pk, 'year': previous_week.year, 'week': previous_week.strftime('%W')}, |
|
565 |
) |
|
566 | ||
567 |
def get_next_week_url(self): |
|
568 |
next_week = self.get_next_week(self.date.date()) |
|
569 |
return reverse( |
|
570 |
'chrono-manager-resource-week-view', |
|
571 |
kwargs={'pk': self.resource.pk, 'year': next_week.year, 'week': next_week.strftime('%W')}, |
|
572 |
) |
|
573 | ||
574 |
def get_next(self, date): |
|
575 |
return self.get_next_week(date) |
|
576 | ||
577 | ||
578 |
resource_weekly_view = ResourceWeekView.as_view() |
|
579 | ||
580 | ||
581 |
class ResourceMonthView(ResourceWeekMonthMixin, DateMixin, MonthArchiveView): |
|
582 |
template_name = 'chrono/manager_resource_month_view.html' |
|
583 |
model = Event |
|
584 |
month_format = '%m' |
|
585 |
date_field = 'start_datetime' |
|
586 |
allow_empty = True |
|
587 |
allow_future = True |
|
588 |
kind = 'month' |
|
589 | ||
590 |
def dispatch(self, request, *args, **kwargs): |
|
591 |
self.resource = get_object_or_404(Resource, pk=kwargs['pk']) |
|
592 |
if not self.resource.can_be_viewed(request.user): |
|
593 |
raise PermissionDenied() |
|
594 |
try: |
|
595 |
self.date = make_aware( |
|
596 |
datetime.datetime.strptime( |
|
597 |
'%s-%s-%s 06:00' % (self.get_year(), self.get_month(), 1), '%Y-%m-%d %H:%M' |
|
598 |
) |
|
599 |
) |
|
600 |
except ValueError: |
|
601 |
raise Http404 |
|
602 |
return super().dispatch(request, *args, **kwargs) |
|
603 | ||
604 |
def get_previous_month_url(self): |
|
605 |
previous_month = self.get_previous_month(self.date.date()) |
|
606 |
return reverse( |
|
607 |
'chrono-manager-resource-month-view', |
|
608 |
kwargs={'pk': self.resource.pk, 'year': previous_month.year, 'month': previous_month.month}, |
|
609 |
) |
|
610 | ||
611 |
def get_next_month_url(self): |
|
612 |
next_month = self.get_next_month(self.date.date()) |
|
613 |
return reverse( |
|
614 |
'chrono-manager-resource-month-view', |
|
615 |
kwargs={'pk': self.resource.pk, 'year': next_month.year, 'month': next_month.month}, |
|
616 |
) |
|
617 | ||
618 |
def get_next(self, date): |
|
619 |
return self.get_next_month(date) |
|
620 | ||
621 | ||
555 | 622 |
resource_monthly_view = ResourceMonthView.as_view() |
556 | 623 | |
557 | 624 | |
... | ... | |
1082 | 1149 |
if self.agenda.default_view == 'day': |
1083 | 1150 |
return redirect('chrono-manager-agenda-day-redirect-view', pk=self.agenda.pk) |
1084 | 1151 | |
1152 |
if self.agenda.default_view == 'week': |
|
1153 |
return redirect('chrono-manager-agenda-week-redirect-view', pk=self.agenda.pk) |
|
1154 | ||
1085 | 1155 |
if self.agenda.default_view == 'month': |
1086 | 1156 |
return redirect('chrono-manager-agenda-month-redirect-view', pk=self.agenda.pk) |
1087 | 1157 | |
... | ... | |
1114 | 1184 |
agenda_month_redirect_view = AgendaMonthRedirectView.as_view() |
1115 | 1185 | |
1116 | 1186 | |
1187 |
class AgendaWeekRedirectView(AgendaMonthRedirectView): |
|
1188 |
def get(self, request, *args, **kwargs): |
|
1189 |
day = self.get_day() |
|
1190 |
return redirect( |
|
1191 |
'chrono-manager-agenda-week-view', pk=self.agenda.pk, year=day.year, week=day.strftime('%W') |
|
1192 |
) |
|
1193 | ||
1194 | ||
1195 |
agenda_week_redirect_view = AgendaWeekRedirectView.as_view() |
|
1196 | ||
1197 | ||
1117 | 1198 |
class AgendaDayRedirectView(AgendaMonthRedirectView): |
1118 | 1199 |
def get(self, request, *args, **kwargs): |
1119 | 1200 |
day = self.get_day() |
... | ... | |
1128 | 1209 |
class AgendaDateView(DateMixin, ViewableAgendaMixin): |
1129 | 1210 |
model = Event |
1130 | 1211 |
month_format = '%m' |
1212 |
week_format = '%W' |
|
1131 | 1213 |
date_field = 'start_datetime' |
1132 | 1214 |
allow_empty = True |
1133 | 1215 |
allow_future = True |
... | ... | |
1333 | 1415 |
agenda_day_view = AgendaDayView.as_view() |
1334 | 1416 | |
1335 | 1417 | |
1336 |
class AgendaMonthView(AgendaDateView, MonthArchiveView):
|
|
1418 |
class AgendaWeekMonthMixin:
|
|
1337 | 1419 |
def get_queryset(self): |
1338 | 1420 |
qs = super().get_queryset() |
1339 | 1421 |
if self.agenda.kind != 'events': |
... | ... | |
1343 | 1425 |
def get_dated_items(self): |
1344 | 1426 |
date_list, object_list, extra_context = super().get_dated_items() |
1345 | 1427 |
if self.agenda.kind == 'events': |
1346 |
min_start = make_aware(datetime.datetime.combine(extra_context['month'], datetime.time(0, 0)))
|
|
1428 |
min_start = make_aware(datetime.datetime.combine(extra_context[self.kind], datetime.time(0, 0)))
|
|
1347 | 1429 |
max_start = make_aware( |
1348 |
datetime.datetime.combine(extra_context['next_month'], datetime.time(0, 0))
|
|
1430 |
datetime.datetime.combine(extra_context['next_%s' % self.kind], datetime.time(0, 0))
|
|
1349 | 1431 |
) |
1350 | 1432 |
exceptions = TimePeriodException.objects.filter( |
1351 | 1433 |
desk__agenda=self.agenda, start_datetime__gte=min_start, end_datetime__lt=max_start |
... | ... | |
1353 | 1435 |
object_list = sorted(itertools.chain(object_list, exceptions), key=lambda x: x.start_datetime) |
1354 | 1436 |
return date_list, object_list, extra_context |
1355 | 1437 | |
1356 |
def get_template_names(self): |
|
1357 |
if self.agenda.kind == 'virtual': |
|
1358 |
return ['chrono/manager_meetings_agenda_month_view.html'] |
|
1359 |
return ['chrono/manager_%s_agenda_month_view.html' % self.agenda.kind] |
|
1360 | ||
1361 | 1438 |
def get_context_data(self, **kwargs): |
1362 | 1439 |
context = super().get_context_data(**kwargs) |
1363 | 1440 |
if self.agenda.kind == 'events': |
... | ... | |
1367 | 1444 |
).all() |
1368 | 1445 |
else: |
1369 | 1446 |
context['single_desk'] = bool(len(self.agenda.prefetched_desks) == 1) |
1447 |
context['kind'] = self.kind |
|
1370 | 1448 |
return context |
1371 | 1449 | |
1372 |
def get_previous_month_url(self): |
|
1373 |
previous_month = self.get_previous_month(self.date.date()) |
|
1374 |
return reverse( |
|
1375 |
'chrono-manager-agenda-month-view', |
|
1376 |
kwargs={'pk': self.agenda.id, 'year': previous_month.year, 'month': previous_month.month}, |
|
1377 |
) |
|
1378 | ||
1379 |
def get_next_month_url(self): |
|
1380 |
next_month = self.get_next_month(self.date.date()) |
|
1381 |
return reverse( |
|
1382 |
'chrono-manager-agenda-month-view', |
|
1383 |
kwargs={'pk': self.agenda.id, 'year': next_month.year, 'month': next_month.month}, |
|
1384 |
) |
|
1385 | ||
1386 |
def get_day(self): |
|
1387 |
return '1' |
|
1388 | ||
1389 | 1450 |
def get_timetable_infos(self): |
1390 | 1451 |
timeperiods = itertools.chain(*(d.timeperiod_set.all() for d in self.agenda.prefetched_desks)) |
1391 | 1452 |
timeperiods = sorted(timeperiods, key=lambda t: (t.weekday, t.start_time)) |
... | ... | |
1419 | 1480 |
hide_weekend = hide_weekend_timeperiod and hide_weekend_event |
1420 | 1481 | |
1421 | 1482 |
# avoid displaying empty first week |
1422 |
first_week_offset = int( |
|
1423 |
(hide_sunday and self.date.weekday() == 6) or (hide_weekend and self.date.weekday() == 5) |
|
1424 |
) |
|
1425 | ||
1483 |
first_week_offset = 0 |
|
1426 | 1484 |
first_week_number = self.date.isocalendar()[1] |
1427 |
if first_week_number >= 52: |
|
1428 |
first_week_number = 0 |
|
1429 |
last_month_day = self.get_next_month(self.date.date()) - datetime.timedelta(days=1) |
|
1430 |
last_week_number = last_month_day.isocalendar()[1] |
|
1485 |
last_week_number = first_week_number |
|
1486 |
if self.kind == 'month': |
|
1487 |
first_week_offset = int( |
|
1488 |
(hide_sunday and self.date.weekday() == 6) or (hide_weekend and self.date.weekday() == 5) |
|
1489 |
) |
|
1490 |
first_week_number = self.date.isocalendar()[1] |
|
1491 |
if first_week_number >= 52: |
|
1492 |
first_week_number = 0 |
|
1493 |
last_day = self.get_next(self.date.date()) - datetime.timedelta(days=1) |
|
1494 |
last_week_number = last_day.isocalendar()[1] |
|
1431 | 1495 | |
1432 |
if last_week_number < first_week_number: # new year |
|
1433 |
last_week_number = 53 |
|
1496 |
if last_week_number < first_week_number: # new year
|
|
1497 |
last_week_number = 53
|
|
1434 | 1498 | |
1435 | 1499 |
for week_number in range(first_week_number + first_week_offset, last_week_number + 1): |
1436 | 1500 |
yield self.get_week_timetable_infos( |
... | ... | |
1474 | 1538 |
desks_len = len(desks) |
1475 | 1539 |
max_date = day.replace(hour=self.max_display.hour, minute=0) |
1476 | 1540 | |
1477 |
# compute booking and opening hours only for current month |
|
1478 |
if self.date.month != day.month:
|
|
1541 |
# compute booking and opening hours only for current month/week
|
|
1542 |
if self.kind == 'month' and timetable['other_month']:
|
|
1479 | 1543 |
return timetable |
1480 | 1544 | |
1481 | 1545 |
while period <= max_date: |
... | ... | |
1536 | 1600 |
return timetable |
1537 | 1601 | |
1538 | 1602 | |
1603 |
class AgendaWeekView(AgendaWeekMonthMixin, AgendaDateView, WeekArchiveView): |
|
1604 |
week_format = "%W" |
|
1605 |
kind = 'week' |
|
1606 | ||
1607 |
def get_template_names(self): |
|
1608 |
if self.agenda.kind == 'virtual': |
|
1609 |
return ['chrono/manager_meetings_agenda_week_view.html'] |
|
1610 |
return ['chrono/manager_%s_agenda_week_view.html' % self.agenda.kind] |
|
1611 | ||
1612 |
def get_previous_week_url(self): |
|
1613 |
previous_week = self.get_previous_week(self.date.date()) |
|
1614 |
return reverse( |
|
1615 |
'chrono-manager-agenda-week-view', |
|
1616 |
kwargs={'pk': self.agenda.id, 'year': previous_week.year, 'week': previous_week.strftime('%W')}, |
|
1617 |
) |
|
1618 | ||
1619 |
def get_next_week_url(self): |
|
1620 |
next_week = self.get_next_week(self.date.date()) |
|
1621 |
return reverse( |
|
1622 |
'chrono-manager-agenda-week-view', |
|
1623 |
kwargs={'pk': self.agenda.id, 'year': next_week.year, 'week': next_week.strftime('%W')}, |
|
1624 |
) |
|
1625 | ||
1626 |
def get_next(self, date): |
|
1627 |
return self.get_next_week(date) |
|
1628 | ||
1629 |
def get_month(self): |
|
1630 |
date = datetime.datetime.strptime('%s-W%s-1' % (self.get_year(), self.get_week()), "%Y-W%W-%w") |
|
1631 |
return date.month |
|
1632 | ||
1633 |
def get_day(self): |
|
1634 |
date = datetime.datetime.strptime('%s-W%s-1' % (self.get_year(), self.get_week()), "%Y-W%W-%w") |
|
1635 |
return date.day |
|
1636 | ||
1637 | ||
1638 |
agenda_weekly_view = AgendaWeekView.as_view() |
|
1639 | ||
1640 | ||
1641 |
class AgendaMonthView(AgendaWeekMonthMixin, AgendaDateView, MonthArchiveView): |
|
1642 |
kind = 'month' |
|
1643 | ||
1644 |
def get_template_names(self): |
|
1645 |
if self.agenda.kind == 'virtual': |
|
1646 |
return ['chrono/manager_meetings_agenda_month_view.html'] |
|
1647 |
return ['chrono/manager_%s_agenda_month_view.html' % self.agenda.kind] |
|
1648 | ||
1649 |
def get_previous_month_url(self): |
|
1650 |
previous_month = self.get_previous_month(self.date.date()) |
|
1651 |
return reverse( |
|
1652 |
'chrono-manager-agenda-month-view', |
|
1653 |
kwargs={'pk': self.agenda.id, 'year': previous_month.year, 'month': previous_month.month}, |
|
1654 |
) |
|
1655 | ||
1656 |
def get_next_month_url(self): |
|
1657 |
next_month = self.get_next_month(self.date.date()) |
|
1658 |
return reverse( |
|
1659 |
'chrono-manager-agenda-month-view', |
|
1660 |
kwargs={'pk': self.agenda.id, 'year': next_month.year, 'month': next_month.month}, |
|
1661 |
) |
|
1662 | ||
1663 |
def get_next(self, date): |
|
1664 |
return self.get_next_month(date) |
|
1665 | ||
1666 |
def get_day(self): |
|
1667 |
return '1' |
|
1668 | ||
1669 | ||
1539 | 1670 |
agenda_monthly_view = AgendaMonthView.as_view() |
1540 | 1671 | |
1541 | 1672 |
tests/manager/test_all.py | ||
---|---|---|
127 | 127 |
resp = app.get('/manage/agendas/%s/' % agenda_id, status=302) |
128 | 128 |
assert resp.location.endswith('/manage/agendas/%s/day/' % agenda.pk) |
129 | 129 | |
130 |
agenda.default_view = 'week' |
|
131 |
agenda.save() |
|
132 |
for agenda_id in [agenda.pk, agenda.slug]: |
|
133 |
resp = app.get('/manage/agendas/%s/' % agenda_id, status=302) |
|
134 |
assert resp.location.endswith('/manage/agendas/%s/week/' % agenda.pk) |
|
135 | ||
130 | 136 | |
131 | 137 |
@freezegun.freeze_time('2020-07-12') |
132 | 138 |
def test_events_agenda_month_redirect(app, admin_user): |
... | ... | |
180 | 186 |
assert resp.location.endswith('/manage/agendas/%s/2020/7/' % agenda.pk) |
181 | 187 | |
182 | 188 | |
189 |
@freezegun.freeze_time('2020-07-12') |
|
190 |
def test_events_agenda_week_redirect(app, admin_user): |
|
191 |
agenda = Agenda.objects.create(label='Foo Bar', kind='events') |
|
192 | ||
193 |
app = login(app) |
|
194 |
# no event, redirect to current week |
|
195 |
resp = app.get('/manage/agendas/%s/week/' % agenda.pk, status=302) |
|
196 |
assert resp.location.endswith('/manage/agendas/%s/2020/week/27/' % agenda.pk) |
|
197 | ||
198 |
# only past events, redirect to last event month |
|
199 |
Event.objects.create( |
|
200 |
agenda=agenda, |
|
201 |
places=1, |
|
202 |
start_datetime=now() - datetime.timedelta(days=60), |
|
203 |
) |
|
204 |
resp = app.get('/manage/agendas/%s/week/' % agenda.pk, status=302) |
|
205 |
assert resp.location.endswith('/manage/agendas/%s/2020/week/19/' % agenda.pk) |
|
206 |
Event.objects.create( |
|
207 |
agenda=agenda, |
|
208 |
places=1, |
|
209 |
start_datetime=now() - datetime.timedelta(days=30), |
|
210 |
) |
|
211 |
resp = app.get('/manage/agendas/%s/week/' % agenda.pk, status=302) |
|
212 |
assert resp.location.endswith('/manage/agendas/%s/2020/week/23/' % agenda.pk) |
|
213 | ||
214 |
# future events |
|
215 |
Event.objects.create( |
|
216 |
agenda=agenda, |
|
217 |
places=1, |
|
218 |
start_datetime=now() + datetime.timedelta(days=60), |
|
219 |
) |
|
220 |
resp = app.get('/manage/agendas/%s/week/' % agenda.pk, status=302) |
|
221 |
assert resp.location.endswith('/manage/agendas/%s/2020/week/36/' % agenda.pk) |
|
222 |
Event.objects.create( |
|
223 |
agenda=agenda, |
|
224 |
places=1, |
|
225 |
start_datetime=now() + datetime.timedelta(days=30), |
|
226 |
) |
|
227 |
resp = app.get('/manage/agendas/%s/week/' % agenda.pk, status=302) |
|
228 |
assert resp.location.endswith('/manage/agendas/%s/2020/week/32/' % agenda.pk) |
|
229 | ||
230 |
# don't check events for meetings |
|
231 |
agenda.kind = 'virtual' |
|
232 |
agenda.save() |
|
233 |
resp = app.get('/manage/agendas/%s/week/' % agenda.pk, status=302) |
|
234 |
assert resp.location.endswith('/manage/agendas/%s/2020/week/27/' % agenda.pk) |
|
235 |
agenda.kind = 'meetings' |
|
236 |
agenda.save() |
|
237 |
resp = app.get('/manage/agendas/%s/week/' % agenda.pk, status=302) |
|
238 |
assert resp.location.endswith('/manage/agendas/%s/2020/week/27/' % agenda.pk) |
|
239 | ||
240 | ||
183 | 241 |
@freezegun.freeze_time('2020-07-12') |
184 | 242 |
def test_events_agenda_day_redirect(app, admin_user): |
185 | 243 |
agenda = Agenda.objects.create(label='Foo Bar', kind='events') |
... | ... | |
246 | 304 |
resp = app.get('/manage/agendas/%s/' % agenda_id, status=302) |
247 | 305 |
assert resp.location.endswith('/manage/agendas/%s/month/' % agenda.pk) |
248 | 306 | |
307 |
agenda.default_view = 'week' |
|
308 |
agenda.save() |
|
309 |
for agenda_id in [agenda.pk, agenda.slug]: |
|
310 |
resp = app.get('/manage/agendas/%s/' % agenda_id, status=302) |
|
311 |
assert resp.location.endswith('/manage/agendas/%s/week/' % agenda.pk) |
|
312 | ||
249 | 313 | |
250 | 314 |
def test_virtual_agenda_redirect(app, admin_user): |
251 | 315 |
agenda = Agenda.objects.create(label='Foo Bar', kind='virtual') |
... | ... | |
261 | 325 |
resp = app.get('/manage/agendas/%s/' % agenda_id, status=302) |
262 | 326 |
assert resp.location.endswith('/manage/agendas/%s/month/' % agenda.pk) |
263 | 327 | |
328 |
agenda.default_view = 'week' |
|
329 |
agenda.save() |
|
330 |
for agenda_id in [agenda.pk, agenda.slug]: |
|
331 |
resp = app.get('/manage/agendas/%s/' % agenda_id, status=302) |
|
332 |
assert resp.location.endswith('/manage/agendas/%s/week/' % agenda.pk) |
|
333 | ||
264 | 334 | |
265 | 335 |
def test_view_agendas_as_admin(app, admin_user): |
266 | 336 |
Agenda.objects.create(label='Bar Foo') |
... | ... | |
929 | 999 |
'view', |
930 | 1000 |
( |
931 | 1001 |
'/manage/agendas/%(agenda)s/%(year)d/%(month)d/%(day)d/', |
1002 |
'/manage/agendas/%(agenda)s/%(year)d/week/%(week)d/', |
|
932 | 1003 |
'/manage/agendas/%(agenda)s/%(year)d/%(month)d/', |
933 | 1004 |
), |
934 | 1005 |
) |
935 |
def test_agenda_day_month_view_backoffice_url_translation( |
|
1006 |
def test_agenda_day_week_month_view_backoffice_url_translation(
|
|
936 | 1007 |
app, admin_user, manager_user, api_user, settings, view |
937 | 1008 |
): |
938 | 1009 |
agenda = Agenda.objects.create(label='New Example', kind='meetings') |
... | ... | |
959 | 1030 |
booking = Booking.objects.get(pk=booking_id) |
960 | 1031 |
assert booking.backoffice_url == backoffice_url |
961 | 1032 |
date = booking.event.start_datetime |
962 |
url = view % {'agenda': agenda.id, 'year': date.year, 'month': date.month, 'day': date.day} |
|
1033 |
url = view % { |
|
1034 |
'agenda': agenda.id, |
|
1035 |
'year': date.year, |
|
1036 |
'month': date.month, |
|
1037 |
'week': int(date.strftime('%W')), |
|
1038 |
'day': date.day, |
|
1039 |
} |
|
963 | 1040 |
resp = app.get(url) |
964 | 1041 |
assert resp.text.count('div class="booking') == 1 |
965 | 1042 |
assert backoffice_url in resp.text |
... | ... | |
1139 | 1216 |
assert len(resp.pyquery.find('.event-info')) == 1 |
1140 | 1217 | |
1141 | 1218 | |
1219 |
@freezegun.freeze_time('2020-10-01') |
|
1220 |
def test_agenda_events_week_view(app, admin_user): |
|
1221 |
agenda = Agenda.objects.create(label='Events', kind='events') |
|
1222 |
Desk.objects.create(agenda=agenda, slug='_exceptions_holder') |
|
1223 |
today = datetime.date.today() |
|
1224 | ||
1225 |
login(app) |
|
1226 |
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.pk, today.year, today.strftime('%W'))) |
|
1227 |
assert 'Day view' in resp.text |
|
1228 |
assert "This week doesn't have any event configured." in resp.text |
|
1229 | ||
1230 |
# add event in a future month, a wednesday |
|
1231 |
Event.objects.create( |
|
1232 |
label='xyz', start_datetime=localtime().replace(day=11, month=11, year=2020), places=10, agenda=agenda |
|
1233 |
) |
|
1234 |
# current month still doesn't have events |
|
1235 |
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, today.year, today.strftime('%W'))) |
|
1236 |
assert "This week doesn't have any event configured." in resp.text |
|
1237 | ||
1238 |
# add recurring event on every Wednesday |
|
1239 |
start_datetime = localtime().replace(day=4, month=11, year=2020) |
|
1240 |
event = Event.objects.create( |
|
1241 |
label='abc', |
|
1242 |
start_datetime=start_datetime, |
|
1243 |
places=10, |
|
1244 |
agenda=agenda, |
|
1245 |
recurrence_days=[start_datetime.weekday()], |
|
1246 |
recurrence_end_date=start_datetime + datetime.timedelta(days=60), |
|
1247 |
) |
|
1248 |
event.create_all_recurrences() |
|
1249 | ||
1250 |
with CaptureQueriesContext(connection) as ctx: |
|
1251 |
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, 2020, 45)) |
|
1252 |
assert len(ctx.captured_queries) == 7 |
|
1253 |
assert len(resp.pyquery.find('.event-info')) == 2 |
|
1254 |
assert 'abc' in resp.pyquery.find('.event-info')[0].text |
|
1255 |
assert 'xyz' in resp.pyquery.find('.event-info')[1].text |
|
1256 | ||
1257 |
TimePeriodException.objects.create( |
|
1258 |
desk=agenda.desk_set.get(), |
|
1259 |
start_datetime=start_datetime + datetime.timedelta(days=6), |
|
1260 |
end_datetime=start_datetime + datetime.timedelta(days=8), |
|
1261 |
) |
|
1262 |
agenda.update_event_recurrences() |
|
1263 |
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, 2020, 45)) |
|
1264 |
assert len(resp.pyquery.find('.event-info')) == 1 |
|
1265 |
assert 'Exception: 11/10/2020' in resp.pyquery.find('li')[4].text_content() |
|
1266 |
assert 'xyz' in resp.pyquery.find('li')[5].text_content() |
|
1267 | ||
1268 |
# create another event with recurrence, the same day/time |
|
1269 |
start_datetime = localtime().replace(day=4, month=11, year=2020) |
|
1270 |
event = Event.objects.create( |
|
1271 |
label='def', |
|
1272 |
start_datetime=start_datetime, |
|
1273 |
places=10, |
|
1274 |
agenda=agenda, |
|
1275 |
recurrence_days=[start_datetime.weekday()], |
|
1276 |
recurrence_end_date=start_datetime + datetime.timedelta(days=60), |
|
1277 |
) |
|
1278 |
event.create_all_recurrences() |
|
1279 |
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, 2020, 49)) |
|
1280 |
assert len(resp.pyquery.find('.event-info')) == 2 |
|
1281 | ||
1282 |
time = localtime(event.start_datetime).strftime('%H%M') |
|
1283 |
resp = resp.click('Dec. 9, 2020, 1 a.m.', index=1) |
|
1284 |
resp = resp.click('Options') |
|
1285 |
resp.form['start_datetime_1'] = '13:12' |
|
1286 |
resp = resp.form.submit(status=302).follow() |
|
1287 |
agenda.update_event_recurrences() |
|
1288 | ||
1289 |
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, 2020, 49)) |
|
1290 |
assert len(resp.pyquery.find('.event-info')) == 2 |
|
1291 |
assert '1:12 p.m.' in resp.text |
|
1292 | ||
1293 |
Event.objects.get(slug='abc--2020-12-02-%s' % time).cancel() |
|
1294 |
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, 2020, 48)) |
|
1295 |
assert 'Cancelled' in resp.text |
|
1296 | ||
1297 | ||
1298 |
def test_agenda_events_week_view_midnight(app, admin_user): |
|
1299 |
agenda = Agenda.objects.create(label='Events', kind='events', default_view='day') |
|
1300 |
midnight = localtime(now().replace(day=1, month=11, year=2020)).replace(hour=0, minute=0) |
|
1301 |
Event.objects.create(label='xyz', start_datetime=midnight, places=10, agenda=agenda) |
|
1302 | ||
1303 |
login(app) |
|
1304 |
resp = app.get('/manage/agendas/%s/week/' % agenda.pk) |
|
1305 |
assert resp.location.endswith('/2020/week/43/') |
|
1306 |
resp = resp.follow() |
|
1307 |
assert len(resp.pyquery.find('.event-info')) == 1 |
|
1308 | ||
1309 | ||
1142 | 1310 |
@freezegun.freeze_time('2020-10-01') |
1143 | 1311 |
def test_agenda_events_month_view(app, admin_user): |
1144 | 1312 |
agenda = Agenda.objects.create(label='Events', kind='events') |
... | ... | |
1365 | 1533 |
resp = resp.click('Month view') |
1366 | 1534 |
assert resp.request.url.endswith('%s/%s/' % (today.year, today.month)) |
1367 | 1535 | |
1368 |
assert 'Day view' in resp.text # date view link should be present |
|
1536 |
assert 'Day view' in resp.text # day view link should be present |
|
1537 |
assert 'Week view' in resp.text # week view link should be present |
|
1369 | 1538 |
assert 'No opening hours this month.' in resp.text |
1370 | 1539 | |
1371 | 1540 |
today = datetime.date(2018, 11, 10) # fixed day |
... | ... | |
1744 | 1913 |
assert 'Saturday' in resp.text |
1745 | 1914 | |
1746 | 1915 | |
1747 |
def test_agenda_view_event(app, manager_user): |
|
1748 |
agenda = Agenda(label='Foo bar') |
|
1749 |
agenda.view_role = manager_user.groups.all()[0] |
|
1750 |
agenda.save() |
|
1751 |
event = Event.objects.create( |
|
1752 |
label='xyz', |
|
1753 |
start_datetime=make_aware(datetime.datetime(2019, 12, 22, 17, 0)), |
|
1754 |
places=10, |
|
1755 |
agenda=agenda, |
|
1756 |
) |
|
1757 |
for i in range(8): |
|
1758 |
booking = Booking.objects.create(event=event) |
|
1759 |
if i < 5: |
|
1760 |
booking.creation_datetime = make_aware(datetime.datetime(2019, 12, 21, 14, 0 + i)) |
|
1761 |
if i == 5: |
|
1762 |
booking.creation_datetime = make_aware(datetime.datetime(2019, 12, 21, 15, 0)) |
|
1763 |
booking.user_first_name = 'Foo Bar' |
|
1764 |
booking.user_last_name = 'User' |
|
1765 |
if i == 6: |
|
1766 |
booking.creation_datetime = make_aware(datetime.datetime(2019, 12, 21, 16, 0)) |
|
1767 |
booking.user_first_name = 'Foo Bar' |
|
1768 |
booking.user_last_name = 'User 2' |
|
1769 |
booking.label = 'Foo Bar Label 2' |
|
1770 |
if i == 7: |
|
1771 |
booking.creation_datetime = make_aware(datetime.datetime(2019, 12, 21, 17, 0)) |
|
1772 |
booking.label = 'Foo Bar Label 3' |
|
1773 |
booking.save() |
|
1774 |
Booking.objects.create(event=event, cancellation_datetime=now()) |
|
1775 |
app = login(app, username='manager', password='manager') |
|
1776 |
resp = app.get('/manage/agendas/%s/2019/12/' % agenda.id, status=200) |
|
1777 |
resp = resp.click('xyz') |
|
1778 |
assert 'Bookings (8/10): 2 remaining places' in resp.text |
|
1779 |
assert 'Waiting' not in resp.text |
|
1780 |
assert 'This event is overbooked.' not in resp.text |
|
1781 |
assert 'This event is full.' not in resp.text |
|
1782 |
event.waiting_list_places = 5 |
|
1783 |
event.save() |
|
1784 |
resp = app.get(resp.request.url) |
|
1785 |
assert 'Waiting List (0/5): 5 remaining places' in resp.text |
|
1786 |
assert 'Anonymous, Dec. 21, 2019, 2 p.m.' in resp.text |
|
1787 |
assert 'Anonymous, Dec. 21, 2019, 2:01 p.m.' in resp.text |
|
1788 |
assert 'Anonymous, Dec. 21, 2019, 2:02 p.m.' in resp.text |
|
1789 |
assert 'Anonymous, Dec. 21, 2019, 2:03 p.m.' in resp.text |
|
1790 |
assert 'Anonymous, Dec. 21, 2019, 2:04 p.m.' in resp.text |
|
1791 |
assert 'Foo Bar User, Dec. 21, 2019, 3 p.m.' in resp.text |
|
1792 |
assert 'Foo Bar User 2, Dec. 21, 2019, 4 p.m.' in resp.text |
|
1793 |
assert 'Foo Bar Label 3, Dec. 21, 2019, 5 p.m.' in resp.text |
|
1916 |
def test_agenda_week_view(app, admin_user, manager_user, api_user, get_proper_html_str): |
|
1917 |
agenda = Agenda.objects.create(label='Passeports', kind='meetings') |
|
1918 |
desk = Desk.objects.create(agenda=agenda, label='Desk A') |
|
1919 |
today = datetime.date.today() |
|
1794 | 1920 | |
1795 |
booking = Booking.objects.order_by('pk')[0] |
|
1796 |
booking.in_waiting_list = True |
|
1797 |
booking.save() |
|
1798 |
booking = Booking.objects.order_by('pk')[1] |
|
1799 |
booking.in_waiting_list = True |
|
1800 |
booking.save() |
|
1801 |
resp = app.get(resp.request.url) |
|
1802 |
assert 'Waiting List (2/5): 3 remaining places' in resp.text |
|
1803 |
assert 'Bookings (6/10): 4 remaining places' in resp.text |
|
1804 |
assert list(resp.context['booked']) == list(Booking.objects.order_by('creation_datetime')[2:8]) |
|
1805 |
assert list(resp.context['waiting']) == list(Booking.objects.order_by('creation_datetime')[0:2]) |
|
1921 |
meetingtype = MeetingType(agenda=agenda, label='passeport', duration=20) |
|
1922 |
meetingtype.save() |
|
1806 | 1923 | |
1807 |
event.places = 5
|
|
1808 |
event.save()
|
|
1809 |
resp = app.get(resp.request.url)
|
|
1810 |
assert 'This event is overbooked.' in resp.text
|
|
1811 |
assert 'This event is full.' not in resp.text
|
|
1924 |
login(app)
|
|
1925 |
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.pk, today.year, today.month, today.day))
|
|
1926 |
assert 'Week view' in resp.text
|
|
1927 |
resp = resp.click('Week view')
|
|
1928 |
assert resp.request.url.endswith('%s/week/%s/' % (today.year, today.strftime('%W')))
|
|
1812 | 1929 | |
1813 |
event.places = 6 |
|
1814 |
event.save() |
|
1815 |
resp = app.get(resp.request.url) |
|
1816 |
assert 'This event is overbooked.' not in resp.text |
|
1817 |
assert 'This event is full.' in resp.text |
|
1930 |
assert 'Day view' in resp.text # day view link should be present |
|
1931 |
assert 'Month view' in resp.text # month view link should be present |
|
1932 |
assert 'No opening hours this week.' in resp.text |
|
1818 | 1933 | |
1934 |
today = datetime.date(2018, 11, 10) # fixed day |
|
1935 |
timeperiod_weekday = today.weekday() |
|
1936 |
timeperiod = TimePeriod( |
|
1937 |
desk=desk, weekday=timeperiod_weekday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0) |
|
1938 |
) |
|
1939 |
timeperiod.save() |
|
1940 |
app.get('/manage/agendas/%s/%s/%s/' % (agenda.id, today.year, 72), status=404) |
|
1941 |
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, today.year, today.strftime('%W'))) |
|
1942 |
assert 'No opening hours this week.' not in resp.text |
|
1943 |
assert '<div class="booking' not in resp.text |
|
1944 |
assert resp.text.count('<tr') == 9 |
|
1819 | 1945 | |
1820 |
def test_agenda_view_edit_event(app, manager_user): |
|
1821 |
test_agenda_view_event(app, manager_user) |
|
1822 |
agenda = Agenda.objects.first() |
|
1823 |
resp = app.get('/manage/agendas/%s/2019/12/' % agenda.id, status=200) |
|
1824 |
resp = resp.click('xyz') |
|
1825 |
assert 'Options' not in resp.text |
|
1826 |
assert 'Delete' not in resp.text |
|
1946 |
# check opening hours cells |
|
1947 |
assert '<div class="opening-hours" style="height:800.0%;top:0.0%;width:97.0%;left:1.0%' in resp.text |
|
1827 | 1948 | |
1828 |
agenda.edit_role = manager_user.groups.all()[0]
|
|
1829 |
agenda.save()
|
|
1830 |
event_url = resp.request.url
|
|
1831 |
resp = app.get(event_url)
|
|
1832 |
assert 'Options' in resp.text
|
|
1833 |
resp = resp.click('Options')
|
|
1834 |
resp.form['start_datetime_0'] = agenda.event_set.first().start_datetime.strftime('%Y-%m-%d')
|
|
1835 |
resp.form['start_datetime_1'] = agenda.event_set.first().start_datetime.strftime('%H:%M')
|
|
1836 |
resp = resp.form.submit(status=302).follow()
|
|
1837 |
assert event_url == resp.request.url
|
|
1949 |
# book some slots
|
|
1950 |
app.reset()
|
|
1951 |
app.authorization = ('Basic', ('john.doe', 'password'))
|
|
1952 |
resp = app.get('/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meetingtype.slug))
|
|
1953 |
booking_url = resp.json['data'][0]['api']['fillslot_url']
|
|
1954 |
booking_url2 = resp.json['data'][2]['api']['fillslot_url']
|
|
1955 |
booking = app.post(booking_url)
|
|
1956 |
booking_2 = app.post_json(
|
|
1957 |
booking_url2, params={'label': 'foo book', 'user_last_name': "bar's", 'url': 'http://baz/'}
|
|
1958 |
)
|
|
1838 | 1959 | |
1839 |
resp = resp.click('Delete') |
|
1840 |
resp = resp.form.submit() |
|
1841 |
assert Event.objects.count() == 0 |
|
1960 |
app.reset() |
|
1961 |
login(app) |
|
1962 |
date = Booking.objects.all()[0].event.start_datetime |
|
1963 |
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, date.year, date.strftime('%W'))) |
|
1964 |
assert resp.text.count('<div class="booking" style="left:1.0%;height:33.0%;') == 2 # booking cells |
|
1965 |
assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == 'booked' |
|
1966 |
assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "foo book - bar's" |
|
1967 |
assert get_proper_html_str('foo book - bar's') in resp |
|
1968 |
assert len(resp.pyquery.find('span.desk')) == 0 |
|
1842 | 1969 | |
1970 |
agenda.booking_user_block_template = '<b>{{ booking.user_name }}</b> Foo Bar' |
|
1971 |
agenda.save() |
|
1972 |
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, date.year, date.strftime('%W'))) |
|
1973 |
assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == '<b></b> Foo Bar' |
|
1974 |
assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "<b>bar's</b> Foo Bar" |
|
1975 |
assert get_proper_html_str('<b>bar's</b> Foo Bar') in resp |
|
1843 | 1976 | |
1844 |
def test_virtual_agenda_add(app, admin_user): |
|
1845 |
app = login(app) |
|
1846 |
resp = app.get('/manage/', status=200) |
|
1977 |
desk = Desk.objects.create(agenda=agenda, label='Desk B') |
|
1978 |
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, date.year, date.strftime('%W'))) |
|
1979 |
assert len(resp.pyquery.find('span.desk')) == 2 |
|
1980 | ||
1981 |
timeperiod = TimePeriod( |
|
1982 |
desk=desk, weekday=timeperiod_weekday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0) |
|
1983 |
) |
|
1984 |
timeperiod.save() |
|
1985 | ||
1986 |
app.reset() |
|
1987 |
booking_3 = app.post(booking_url) |
|
1988 |
login(app) |
|
1989 |
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, today.year, today.strftime('%W'))) |
|
1990 | ||
1991 |
# count occurences of timeperiod weekday in current month |
|
1992 |
assert resp.text.count('<div class="opening-hours"') == 2 |
|
1993 |
current_month = today.strftime('%Y-%m') |
|
1994 |
if current_month in booking_url or current_month in booking_url2: |
|
1995 |
assert resp.text.count('<div class="booking"') == 3 |
|
1996 | ||
1997 |
# cancel bookings |
|
1998 |
app.reset() |
|
1999 |
app.post(booking.json['api']['cancel_url']) |
|
2000 |
app.post(booking_2.json['api']['cancel_url']) |
|
2001 |
app.post(booking_3.json['api']['cancel_url']) |
|
2002 | ||
2003 |
# make sure the are not |
|
2004 |
login(app) |
|
2005 |
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, today.year, today.strftime('%W'))) |
|
2006 |
assert resp.text.count('<div class="booking"') == 0 |
|
2007 | ||
2008 |
# check December is correctly displayed |
|
2009 |
today = datetime.date(2018, 12, 10) |
|
2010 |
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, today.year, today.strftime('%W'))) |
|
2011 |
assert 'No opening hours this week.' not in resp.text |
|
2012 | ||
2013 |
# display exception |
|
2014 |
unavailability_calendar = UnavailabilityCalendar.objects.create(label='calendar') |
|
2015 |
TimePeriodException.objects.create( |
|
2016 |
label='Calendar exception', |
|
2017 |
unavailability_calendar=unavailability_calendar, |
|
2018 |
start_datetime=make_aware(datetime.datetime(2018, 12, 15, 5, 0)), |
|
2019 |
end_datetime=make_aware(datetime.datetime(2018, 12, 15, 14, 0)), |
|
2020 |
) |
|
2021 |
unavailability_calendar.desks.add(desk) |
|
2022 |
TimePeriodException.objects.create( |
|
2023 |
label='Exception for a December day', |
|
2024 |
desk=desk, |
|
2025 |
start_datetime=make_aware(datetime.datetime(2018, 12, 15, 14, 0)), |
|
2026 |
end_datetime=make_aware(datetime.datetime(2018, 12, 15, 23, 0)), |
|
2027 |
) |
|
2028 |
TimePeriodException.objects.create( |
|
2029 |
label='Exception spanning multiple days', |
|
2030 |
desk=desk, |
|
2031 |
start_datetime=make_aware(datetime.datetime(2018, 12, 11, 14, 0)), |
|
2032 |
end_datetime=make_aware(datetime.datetime(2018, 12, 13, 16, 0)), |
|
2033 |
) |
|
2034 |
with CaptureQueriesContext(connection) as ctx: |
|
2035 |
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, today.year, today.strftime('%W'))) |
|
2036 |
assert len(ctx.captured_queries) == 10 |
|
2037 |
assert resp.pyquery.find('.exception-hours')[0].attrib == { |
|
2038 |
'class': 'exception-hours', |
|
2039 |
'style': 'height:400.0%;top:400.0%;width:48.0%;left:50.0%;', |
|
2040 |
'title': 'Exception spanning multiple days', |
|
2041 |
} |
|
2042 |
assert resp.pyquery.find('.exception-hours')[1].attrib == { |
|
2043 |
'class': 'exception-hours', |
|
2044 |
'style': 'height:800.0%;top:0.0%;width:48.0%;left:50.0%;', |
|
2045 |
'title': 'Exception spanning multiple days', |
|
2046 |
} |
|
2047 |
assert resp.pyquery.find('.exception-hours')[2].attrib == { |
|
2048 |
'class': 'exception-hours', |
|
2049 |
'style': 'height:600.0%;top:0.0%;width:48.0%;left:50.0%;', |
|
2050 |
'title': 'Exception spanning multiple days', |
|
2051 |
} |
|
2052 |
assert resp.pyquery.find('.exception-hours')[3].attrib == { |
|
2053 |
'class': 'exception-hours', |
|
2054 |
'style': 'height:400.0%;top:0.0%;width:48.0%;left:50.0%;', |
|
2055 |
'title': 'Calendar exception', |
|
2056 |
} |
|
2057 |
assert resp.pyquery.find('.exception-hours')[4].attrib == { |
|
2058 |
'class': 'exception-hours', |
|
2059 |
'style': 'height:400.0%;top:400.0%;width:48.0%;left:50.0%;', |
|
2060 |
'title': 'Exception for a December day', |
|
2061 |
} |
|
2062 | ||
2063 | ||
2064 |
@pytest.mark.parametrize('kind', ['meetings', 'virtual']) |
|
2065 |
def test_agenda_week_view_weekend(app, admin_user, kind): |
|
2066 |
week, year = '02', 2019 |
|
2067 |
monday = 0 |
|
2068 |
if kind == 'meetings': |
|
2069 |
agenda = Agenda.objects.create(label='Passeports', kind='meetings') |
|
2070 |
desk = Desk.objects.create(agenda=agenda, label='Desk A') |
|
2071 |
else: |
|
2072 |
agenda = Agenda.objects.create(label='Virtual', kind='virtual') |
|
2073 |
real_agenda = Agenda.objects.create(label='Real 1', kind='meetings') |
|
2074 |
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda) |
|
2075 |
desk = Desk.objects.create(agenda=real_agenda, label='New Desk') |
|
2076 |
TimePeriod.objects.create( |
|
2077 |
desk=desk, weekday=monday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0) |
|
2078 |
) |
|
2079 | ||
2080 |
login(app) |
|
2081 |
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, year, week)) |
|
2082 |
assert 'Sunday' not in resp.text |
|
2083 |
assert 'Saturday' not in resp.text |
|
2084 |
# Month starts a Tuesday, but monday is displayed |
|
2085 |
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0 |
|
2086 | ||
2087 |
week, year = 21, 2019 # month starts a Saturday |
|
2088 |
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, year, week)) |
|
2089 |
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0 |
|
2090 | ||
2091 |
saturday = 5 |
|
2092 |
timeperiod_sat = TimePeriod.objects.create( |
|
2093 |
desk=desk, weekday=saturday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0) |
|
2094 |
) |
|
2095 |
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, year, week)) |
|
2096 |
assert 'Sunday' not in resp.text |
|
2097 |
assert 'Saturday' in resp.text |
|
2098 |
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0 |
|
2099 | ||
2100 |
sunday = 6 |
|
2101 |
TimePeriod.objects.create( |
|
2102 |
desk=desk, weekday=sunday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0) |
|
2103 |
) |
|
2104 |
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, year, week)) |
|
2105 |
assert 'Sunday' in resp.text |
|
2106 |
assert 'Saturday' in resp.text |
|
2107 | ||
2108 |
timeperiod_sat.delete() |
|
2109 |
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, year, week)) |
|
2110 |
assert 'Sunday' in resp.text |
|
2111 |
assert 'Saturday' in resp.text |
|
2112 | ||
2113 | ||
2114 |
@pytest.mark.parametrize('kind', ['meetings', 'virtual']) |
|
2115 |
def test_agenda_week_view_dst_change(app, admin_user, kind): |
|
2116 |
if kind == 'meetings': |
|
2117 |
agenda = Agenda.objects.create(label='Passeports', kind='meetings') |
|
2118 |
desk = Desk.objects.create(agenda=agenda, label='Desk A') |
|
2119 |
meetingtype = MeetingType.objects.create(agenda=agenda, label='passeport', duration=20) |
|
2120 |
else: |
|
2121 |
agenda = Agenda.objects.create(label='Virtual', kind='virtual') |
|
2122 |
real_agenda = Agenda.objects.create(label='Real 1', kind='meetings') |
|
2123 |
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda) |
|
2124 |
desk = Desk.objects.create(agenda=real_agenda, label='New Desk') |
|
2125 |
meetingtype = MeetingType.objects.create(agenda=real_agenda, label='passeport', duration=20) |
|
2126 | ||
2127 |
for weekday in range(0, 7): # open all mornings |
|
2128 |
TimePeriod.objects.create( |
|
2129 |
desk=desk, weekday=weekday, start_time=datetime.time(9, 0), end_time=datetime.time(12, 0) |
|
2130 |
) |
|
2131 | ||
2132 |
login(app) |
|
2133 |
for date in ('2019-10-28', '2019-11-03'): |
|
2134 |
# dst change was on 2019-11-03 |
|
2135 |
with freezegun.freeze_time(date): |
|
2136 |
resp = app.get('/manage/agendas/%s/2019/week/43/' % agenda.id) |
|
2137 |
# check all days are correctly aligned |
|
2138 |
assert resp.text.count('height:300.0%;top:0.0%') == 7 |
|
2139 | ||
2140 |
# book some slots |
|
2141 |
for date_tuple in [(2019, 10, 29, 10, 0), (2019, 10, 30, 10, 0)]: |
|
2142 |
event = Event.objects.create( |
|
2143 |
agenda=desk.agenda, |
|
2144 |
places=1, |
|
2145 |
desk=desk, |
|
2146 |
meeting_type=meetingtype, |
|
2147 |
start_datetime=localtime(make_aware(datetime.datetime(*date_tuple))), |
|
2148 |
) |
|
2149 |
Booking.objects.create(event=event) |
|
2150 | ||
2151 |
# check booked slots are similarly aligned |
|
2152 |
resp = app.get('/manage/agendas/%s/2019/week/43/' % agenda.id) |
|
2153 |
assert resp.text.count('height:33.0%;top:100.0%;') == 2 |
|
2154 | ||
2155 | ||
2156 |
@pytest.mark.parametrize('kind', ['meetings', 'virtual']) |
|
2157 |
def test_agenda_week_view_januaries(app, admin_user, kind): |
|
2158 |
if kind == 'meetings': |
|
2159 |
agenda = Agenda.objects.create(label='Passports', kind='meetings') |
|
2160 |
desk = Desk.objects.create(agenda=agenda, label='Desk A') |
|
2161 |
MeetingType.objects.create(agenda=agenda, label='passport', duration=20) |
|
2162 |
else: |
|
2163 |
agenda = Agenda.objects.create(label='Virtual', kind='virtual') |
|
2164 |
real_agenda = Agenda.objects.create(label='Real 1', kind='meetings') |
|
2165 |
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda) |
|
2166 |
desk = Desk.objects.create(agenda=real_agenda, label='New Desk') |
|
2167 |
MeetingType.objects.create(agenda=real_agenda, label='passport', duration=20) |
|
2168 |
TimePeriod(desk=desk, weekday=2, start_time=datetime.time(9, 0), end_time=datetime.time(12, 0)).save() |
|
2169 | ||
2170 |
for year in range(2020, 2030): |
|
2171 |
date = datetime.date(year, 1, 1) |
|
2172 |
with freezegun.freeze_time(date): |
|
2173 |
login(app) |
|
2174 |
resp = app.get('/manage/agendas/%s/%s/week/01/' % (agenda.id, date.year)) |
|
2175 |
assert resp.text.count('<th></th>') == 1 |
|
2176 | ||
2177 | ||
2178 |
@pytest.mark.parametrize('kind', ['meetings', 'virtual']) |
|
2179 |
def test_agenda_week_view_event_outside_timeperiod(app, admin_user, kind): |
|
2180 |
middle_day = now().replace(day=15) |
|
2181 |
middle_day = middle_day + datetime.timedelta(days=4 - middle_day.weekday()) |
|
2182 |
if kind == 'meetings': |
|
2183 |
agenda = Agenda.objects.create(label='New Example', kind='meetings') |
|
2184 |
desk = Desk.objects.create(agenda=agenda, label='New Desk') |
|
2185 |
meetingtype = MeetingType.objects.create(agenda=agenda, label='Bar', duration=30) |
|
2186 |
else: |
|
2187 |
agenda = Agenda.objects.create(label='Virtual', kind='virtual') |
|
2188 |
real_agenda = Agenda.objects.create(label='Real 1', kind='meetings') |
|
2189 |
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda) |
|
2190 |
desk = Desk.objects.create(agenda=real_agenda, label='New Desk') |
|
2191 |
meetingtype = MeetingType.objects.create(agenda=real_agenda, label='passport', duration=20) |
|
2192 |
login(app) |
|
2193 | ||
2194 |
# no time period - no events |
|
2195 |
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.pk, middle_day.year, middle_day.strftime('%W'))) |
|
2196 |
assert 'No opening hours this week.' in resp.text |
|
2197 |
assert 'div class="booking' not in resp.text |
|
2198 | ||
2199 |
# book some slots |
|
2200 |
middle_day = now().replace(day=15) |
|
2201 |
for hour, minute in [(9, 0), (17, 0)]: |
|
2202 |
event = Event.objects.create( |
|
2203 |
agenda=desk.agenda, |
|
2204 |
places=1, |
|
2205 |
desk=desk, |
|
2206 |
meeting_type=meetingtype, |
|
2207 |
start_datetime=localtime(now().replace(day=middle_day.day - middle_day.weekday() + 2)).replace( |
|
2208 |
hour=hour, minute=minute |
|
2209 |
), |
|
2210 |
) |
|
2211 |
Booking.objects.create(event=event) |
|
2212 | ||
2213 |
# no time period - events are displayed |
|
2214 |
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.pk, middle_day.year, middle_day.strftime('%W'))) |
|
2215 |
assert resp.text.count('div class="booking') == 2 |
|
2216 | ||
2217 |
# bookings are cancelled |
|
2218 |
Booking.objects.update(cancellation_datetime=now()) |
|
2219 |
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.pk, middle_day.year, middle_day.strftime('%W'))) |
|
2220 |
assert 'No opening hours this week.' in resp.text |
|
2221 |
assert resp.text.count('div class="booking') == 0 |
|
2222 | ||
2223 |
# events outside time period |
|
2224 |
Booking.objects.update(cancellation_datetime=None) # reset |
|
2225 |
TimePeriod.objects.create( |
|
2226 |
desk=desk, weekday=2, start_time=datetime.time(10, 0), end_time=datetime.time(16, 0) |
|
2227 |
) |
|
2228 |
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.pk, middle_day.year, middle_day.strftime('%W'))) |
|
2229 |
assert resp.text.count('div class="booking') == 2 |
|
2230 |
assert '<div class="opening-hours" style="height:600.0%;top:100.0%;width:97.0%;left:1.0%' in resp.text |
|
2231 |
assert 'Sunday' not in resp.text |
|
2232 |
assert 'Saturday' not in resp.text |
|
2233 | ||
2234 |
# create an event on saturday |
|
2235 |
middle_day = now().replace(day=15) |
|
2236 |
middle_day = middle_day + datetime.timedelta(days=5 - middle_day.weekday()) |
|
2237 |
event = Event.objects.create( |
|
2238 |
agenda=desk.agenda, |
|
2239 |
places=1, |
|
2240 |
desk=desk, |
|
2241 |
meeting_type=meetingtype, |
|
2242 |
start_datetime=localtime(now()).replace(day=middle_day.day, hour=10, minute=0), |
|
2243 |
) |
|
2244 |
Booking.objects.create(event=event) |
|
2245 |
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.pk, middle_day.year, middle_day.strftime('%W'))) |
|
2246 |
assert resp.text.count('div class="booking') == 3 |
|
2247 |
assert 'Sunday' not in resp.text |
|
2248 |
assert 'Saturday' in resp.text |
|
2249 |
# bookings are cancelled |
|
2250 |
Booking.objects.update(cancellation_datetime=now()) |
|
2251 |
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.pk, middle_day.year, middle_day.strftime('%W'))) |
|
2252 |
assert resp.text.count('div class="booking') == 0 |
|
2253 |
# and a timeperiod |
|
2254 |
Booking.objects.update(cancellation_datetime=None) # reset |
|
2255 |
TimePeriod.objects.create( |
|
2256 |
desk=desk, weekday=5, start_time=datetime.time(11, 0), end_time=datetime.time(12, 0) |
|
2257 |
) |
|
2258 |
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.pk, middle_day.year, middle_day.strftime('%W'))) |
|
2259 |
assert resp.text.count('div class="booking') == 3 |
|
2260 |
assert 'Sunday' not in resp.text |
|
2261 |
assert 'Saturday' in resp.text |
|
2262 | ||
2263 |
# create an event on sunday |
|
2264 |
middle_day = now().replace(day=15) |
|
2265 |
middle_day = middle_day + datetime.timedelta(days=6 - middle_day.weekday()) |
|
2266 |
event = Event.objects.create( |
|
2267 |
agenda=desk.agenda, |
|
2268 |
places=1, |
|
2269 |
desk=desk, |
|
2270 |
meeting_type=meetingtype, |
|
2271 |
start_datetime=localtime(now()).replace(day=middle_day.day, hour=10, minute=0), |
|
2272 |
) |
|
2273 |
Booking.objects.create(event=event) |
|
2274 |
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.pk, middle_day.year, middle_day.strftime('%W'))) |
|
2275 |
assert resp.text.count('div class="booking') == 4 |
|
2276 |
assert 'Sunday' in resp.text |
|
2277 |
assert 'Saturday' in resp.text |
|
2278 |
# bookings are cancelled |
|
2279 |
Booking.objects.update(cancellation_datetime=now()) |
|
2280 |
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.pk, middle_day.year, middle_day.strftime('%W'))) |
|
2281 |
assert resp.text.count('div class="booking') == 0 |
|
2282 |
# and a timeperiod |
|
2283 |
Booking.objects.update(cancellation_datetime=None) # reset |
|
2284 |
TimePeriod.objects.create( |
|
2285 |
desk=desk, weekday=6, start_time=datetime.time(11, 0), end_time=datetime.time(12, 0) |
|
2286 |
) |
|
2287 |
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.pk, middle_day.year, middle_day.strftime('%W'))) |
|
2288 |
assert resp.text.count('div class="booking') == 4 |
|
2289 |
assert 'Sunday' in resp.text |
|
2290 |
assert 'Saturday' in resp.text |
|
2291 | ||
2292 | ||
2293 |
def test_agenda_view_event(app, manager_user): |
|
2294 |
agenda = Agenda(label='Foo bar') |
|
2295 |
agenda.view_role = manager_user.groups.all()[0] |
|
2296 |
agenda.save() |
|
2297 |
event = Event.objects.create( |
|
2298 |
label='xyz', |
|
2299 |
start_datetime=make_aware(datetime.datetime(2019, 12, 22, 17, 0)), |
|
2300 |
places=10, |
|
2301 |
agenda=agenda, |
|
2302 |
) |
|
2303 |
for i in range(8): |
|
2304 |
booking = Booking.objects.create(event=event) |
|
2305 |
if i < 5: |
|
2306 |
booking.creation_datetime = make_aware(datetime.datetime(2019, 12, 21, 14, 0 + i)) |
|
2307 |
if i == 5: |
|
2308 |
booking.creation_datetime = make_aware(datetime.datetime(2019, 12, 21, 15, 0)) |
|
2309 |
booking.user_first_name = 'Foo Bar' |
|
2310 |
booking.user_last_name = 'User' |
|
2311 |
if i == 6: |
|
2312 |
booking.creation_datetime = make_aware(datetime.datetime(2019, 12, 21, 16, 0)) |
|
2313 |
booking.user_first_name = 'Foo Bar' |
|
2314 |
booking.user_last_name = 'User 2' |
|
2315 |
booking.label = 'Foo Bar Label 2' |
|
2316 |
if i == 7: |
|
2317 |
booking.creation_datetime = make_aware(datetime.datetime(2019, 12, 21, 17, 0)) |
|
2318 |
booking.label = 'Foo Bar Label 3' |
|
2319 |
booking.save() |
|
2320 |
Booking.objects.create(event=event, cancellation_datetime=now()) |
|
2321 |
app = login(app, username='manager', password='manager') |
|
2322 |
resp = app.get('/manage/agendas/%s/2019/12/' % agenda.id, status=200) |
|
2323 |
resp = resp.click('xyz') |
|
2324 |
assert 'Bookings (8/10): 2 remaining places' in resp.text |
|
2325 |
assert 'Waiting' not in resp.text |
|
2326 |
assert 'This event is overbooked.' not in resp.text |
|
2327 |
assert 'This event is full.' not in resp.text |
|
2328 |
event.waiting_list_places = 5 |
|
2329 |
event.save() |
|
2330 |
resp = app.get(resp.request.url) |
|
2331 |
assert 'Waiting List (0/5): 5 remaining places' in resp.text |
|
2332 |
assert 'Anonymous, Dec. 21, 2019, 2 p.m.' in resp.text |
|
2333 |
assert 'Anonymous, Dec. 21, 2019, 2:01 p.m.' in resp.text |
|
2334 |
assert 'Anonymous, Dec. 21, 2019, 2:02 p.m.' in resp.text |
|
2335 |
assert 'Anonymous, Dec. 21, 2019, 2:03 p.m.' in resp.text |
|
2336 |
assert 'Anonymous, Dec. 21, 2019, 2:04 p.m.' in resp.text |
|
2337 |
assert 'Foo Bar User, Dec. 21, 2019, 3 p.m.' in resp.text |
|
2338 |
assert 'Foo Bar User 2, Dec. 21, 2019, 4 p.m.' in resp.text |
|
2339 |
assert 'Foo Bar Label 3, Dec. 21, 2019, 5 p.m.' in resp.text |
|
2340 | ||
2341 |
booking = Booking.objects.order_by('pk')[0] |
|
2342 |
booking.in_waiting_list = True |
|
2343 |
booking.save() |
|
2344 |
booking = Booking.objects.order_by('pk')[1] |
|
2345 |
booking.in_waiting_list = True |
|
2346 |
booking.save() |
|
2347 |
resp = app.get(resp.request.url) |
|
2348 |
assert 'Waiting List (2/5): 3 remaining places' in resp.text |
|
2349 |
assert 'Bookings (6/10): 4 remaining places' in resp.text |
|
2350 |
assert list(resp.context['booked']) == list(Booking.objects.order_by('creation_datetime')[2:8]) |
|
2351 |
assert list(resp.context['waiting']) == list(Booking.objects.order_by('creation_datetime')[0:2]) |
|
2352 | ||
2353 |
event.places = 5 |
|
2354 |
event.save() |
|
2355 |
resp = app.get(resp.request.url) |
|
2356 |
assert 'This event is overbooked.' in resp.text |
|
2357 |
assert 'This event is full.' not in resp.text |
|
2358 | ||
2359 |
event.places = 6 |
|
2360 |
event.save() |
|
2361 |
resp = app.get(resp.request.url) |
|
2362 |
assert 'This event is overbooked.' not in resp.text |
|
2363 |
assert 'This event is full.' in resp.text |
|
2364 | ||
2365 | ||
2366 |
def test_agenda_view_edit_event(app, manager_user): |
|
2367 |
test_agenda_view_event(app, manager_user) |
|
2368 |
agenda = Agenda.objects.first() |
|
2369 |
resp = app.get('/manage/agendas/%s/2019/12/' % agenda.id, status=200) |
|
2370 |
resp = resp.click('xyz') |
|
2371 |
assert 'Options' not in resp.text |
|
2372 |
assert 'Delete' not in resp.text |
|
2373 | ||
2374 |
agenda.edit_role = manager_user.groups.all()[0] |
|
2375 |
agenda.save() |
|
2376 |
event_url = resp.request.url |
|
2377 |
resp = app.get(event_url) |
|
2378 |
assert 'Options' in resp.text |
|
2379 |
resp = resp.click('Options') |
|
2380 |
resp.form['start_datetime_0'] = agenda.event_set.first().start_datetime.strftime('%Y-%m-%d') |
|
2381 |
resp.form['start_datetime_1'] = agenda.event_set.first().start_datetime.strftime('%H:%M') |
|
2382 |
resp = resp.form.submit(status=302).follow() |
|
2383 |
assert event_url == resp.request.url |
|
2384 | ||
2385 |
resp = resp.click('Delete') |
|
2386 |
resp = resp.form.submit() |
|
2387 |
assert Event.objects.count() == 0 |
|
2388 | ||
2389 | ||
2390 |
def test_virtual_agenda_add(app, admin_user): |
|
2391 |
app = login(app) |
|
2392 |
resp = app.get('/manage/', status=200) |
|
1847 | 2393 |
resp = resp.click('New') |
1848 | 2394 |
resp.form['label'] = 'Virtual agenda' |
1849 | 2395 |
resp.form['kind'] = 'virtual' |
... | ... | |
1997 | 2543 |
assert 'exceptions-hours' not in resp.text |
1998 | 2544 | |
1999 | 2545 | |
2546 |
def test_virtual_agenda_week_view(app, admin_user, get_proper_html_str): |
|
2547 |
agenda = Agenda.objects.create(label='Virtual', kind='virtual') |
|
2548 |
real_agenda_1 = Agenda.objects.create(label='Real 1', kind='meetings') |
|
2549 |
real_agenda_2 = Agenda.objects.create(label='Real 2', kind='meetings') |
|
2550 |
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda_1) |
|
2551 |
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda_2) |
|
2552 | ||
2553 |
desk1 = Desk.objects.create(agenda=real_agenda_1, label='New Desk') |
|
2554 |
desk2 = Desk.objects.create(agenda=real_agenda_2, label='New Desk') |
|
2555 |
today = datetime.date.today() |
|
2556 | ||
2557 |
meetingtype1 = MeetingType.objects.create(agenda=real_agenda_1, label='Bar', duration=30) |
|
2558 |
meetingtype2 = MeetingType.objects.create(agenda=real_agenda_2, label='Bar', duration=30) |
|
2559 | ||
2560 |
login(app) |
|
2561 |
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.pk, today.year, today.month, today.day)) |
|
2562 |
assert 'Week view' in resp.text |
|
2563 |
resp = resp.click('Week view') |
|
2564 |
assert resp.request.url.endswith('%s/week/%s/' % (today.year, today.strftime('%W'))) |
|
2565 | ||
2566 |
assert 'Day view' in resp.text # day view link should be present |
|
2567 |
assert 'Month view' in resp.text # month view link should be present |
|
2568 |
assert 'No opening hours this week.' in resp.text |
|
2569 | ||
2570 |
today = datetime.date(2018, 11, 10) # fixed day |
|
2571 |
timeperiod_weekday = today.weekday() |
|
2572 |
TimePeriod.objects.create( |
|
2573 |
desk=desk1, weekday=timeperiod_weekday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0) |
|
2574 |
) |
|
2575 |
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, today.year, today.strftime('%W'))) |
|
2576 |
assert 'No opening hours this week.' not in resp.text |
|
2577 |
assert '<div class="booking' not in resp.text |
|
2578 |
assert resp.text.count('<tr') == 9 |
|
2579 | ||
2580 |
# check opening hours cells |
|
2581 |
assert '<div class="opening-hours" style="height:800.0%;top:0.0%;width:48.0%;left:1.0%' in resp.text |
|
2582 | ||
2583 |
# book some slots |
|
2584 |
for hour, minute in [(10, 30), (14, 0)]: |
|
2585 |
event = Event.objects.create( |
|
2586 |
agenda=real_agenda_1, |
|
2587 |
places=1, |
|
2588 |
desk=desk1, |
|
2589 |
meeting_type=meetingtype1, |
|
2590 |
start_datetime=now().replace(hour=hour, minute=minute), |
|
2591 |
) |
|
2592 |
Booking.objects.create(event=event) |
|
2593 |
event = Event.objects.create( |
|
2594 |
agenda=real_agenda_2, |
|
2595 |
places=1, |
|
2596 |
desk=desk2, |
|
2597 |
meeting_type=meetingtype2, |
|
2598 |
start_datetime=now().replace(hour=hour, minute=minute), |
|
2599 |
) |
|
2600 |
Booking.objects.create(event=event, label='foo', user_last_name="bar's") |
|
2601 | ||
2602 |
date = Booking.objects.all()[0].event.start_datetime |
|
2603 |
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, date.year, date.strftime('%W'))) |
|
2604 |
assert resp.text.count('<div class="booking" style="left:1.0%;height:50.0%;') == 2 # booking cells |
|
2605 |
assert ( |
|
2606 |
resp.text.count('<div class="booking" style="left:50.0%;height:50.0%;min-height:50.0%;') == 2 |
|
2607 |
) # booking cells |
|
2608 |
assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == 'booked' |
|
2609 |
assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "foo - bar's" |
|
2610 |
assert resp.pyquery.find('div.booking a').not_('.cancel')[2].text.strip() == 'booked' |
|
2611 |
assert resp.pyquery.find('div.booking a').not_('.cancel')[3].text.strip() == "foo - bar's" |
|
2612 |
assert get_proper_html_str('foo - bar's') in resp |
|
2613 | ||
2614 |
real_agenda_1.booking_user_block_template = '<b>{{ booking.user_name }}</b> Foo Bar' |
|
2615 |
real_agenda_1.save() |
|
2616 |
real_agenda_2.booking_user_block_template = '<b>{{ booking.user_name }}</b> Bar Foo' |
|
2617 |
real_agenda_2.save() |
|
2618 |
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, date.year, date.month)) |
|
2619 |
assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == '<b></b> Foo Bar' |
|
2620 |
assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "<b>bar's</b> Bar Foo" |
|
2621 |
assert resp.pyquery.find('div.booking a').not_('.cancel')[2].text.strip() == '<b></b> Foo Bar' |
|
2622 |
assert resp.pyquery.find('div.booking a').not_('.cancel')[3].text.strip() == "<b>bar's</b> Bar Foo" |
|
2623 |
assert get_proper_html_str('<b>bar's</b> Bar Foo') in resp |
|
2624 | ||
2625 |
# cancel a booking |
|
2626 |
booking = Booking.objects.first() |
|
2627 |
booking.cancel() |
|
2628 |
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, date.year, date.strftime('%W'))) |
|
2629 |
assert resp.text.count('<div class="booking"') == 3 |
|
2630 | ||
2631 |
# check December is correctly displayed |
|
2632 |
today = datetime.date(2018, 12, 10) |
|
2633 |
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, today.year, today.strftime('%W'))) |
|
2634 |
assert 'No opening hours this month.' not in resp.text |
|
2635 | ||
2636 |
# display exception |
|
2637 |
TimePeriodException.objects.create( |
|
2638 |
label='Exception for a December day', |
|
2639 |
desk=desk1, |
|
2640 |
start_datetime=make_aware(datetime.datetime(2018, 12, 15, 5, 0)), |
|
2641 |
end_datetime=make_aware(datetime.datetime(2018, 12, 15, 23, 0)), |
|
2642 |
) |
|
2643 |
with CaptureQueriesContext(connection) as ctx: |
|
2644 |
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, today.year, today.strftime('%W'))) |
|
2645 |
assert len(ctx.captured_queries) == 12 |
|
2646 |
assert len(resp.pyquery.find('.exception-hours')) == 1 |
|
2647 |
assert resp.pyquery.find('.exception-hours')[0].attrib == { |
|
2648 |
'class': 'exception-hours', |
|
2649 |
'style': 'height:800.0%;top:0.0%;width:48.0%;left:1.0%;', |
|
2650 |
'title': 'Exception for a December day', |
|
2651 |
} |
|
2652 | ||
2653 |
# display excluded period |
|
2654 |
TimePeriod.objects.create( |
|
2655 |
agenda=agenda, weekday=today.weekday(), start_time=datetime.time(13, 0), end_time=datetime.time(23, 0) |
|
2656 |
) |
|
2657 |
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, today.year, today.strftime('%W'))) |
|
2658 |
assert len(resp.pyquery.find('.exception-hours')) == 3 |
|
2659 |
assert resp.pyquery.find('.exception-hours')[0].attrib == { |
|
2660 |
'class': 'exception-hours', |
|
2661 |
'style': 'height:500.0%;top:300.0%;width:48.0%;left:1.0%;', |
|
2662 |
} |
|
2663 |
assert resp.pyquery.find('.exception-hours')[1].attrib == { |
|
2664 |
'class': 'exception-hours', |
|
2665 |
'style': 'height:500.0%;top:300.0%;width:48.0%;left:50.0%;', |
|
2666 |
} |
|
2667 | ||
2668 | ||
2000 | 2669 |
def test_virtual_agenda_month_view(app, admin_user, get_proper_html_str): |
2001 | 2670 |
agenda = Agenda.objects.create(label='Virtual', kind='virtual') |
2002 | 2671 |
real_agenda_1 = Agenda.objects.create(label='Real 1', kind='meetings') |
... | ... | |
2017 | 2686 |
resp = resp.click('Month view') |
2018 | 2687 |
assert resp.request.url.endswith('%s/%s/' % (today.year, today.month)) |
2019 | 2688 | |
2020 |
assert 'Day view' in resp.text # date view link should be present |
|
2689 |
assert 'Day view' in resp.text # day view link should be present |
|
2690 |
assert 'Week view' in resp.text # week view link should be present |
|
2021 | 2691 |
assert 'No opening hours this month.' in resp.text |
2022 | 2692 | |
2023 | 2693 |
today = datetime.date(2018, 11, 10) # fixed day |
tests/manager/test_resource.py | ||
---|---|---|
220 | 220 |
app.get('/manage/resource/%s/%d/%d/%d/' % (resource.pk, today.year, today.month, today.day), status=403) |
221 | 221 | |
222 | 222 | |
223 |
@freezegun.freeze_time('2020-06-15') |
|
224 |
def test_resource_week_view(app, admin_user, get_proper_html_str): |
|
225 |
resource = Resource.objects.create(label='Foo bar') |
|
226 |
agenda = Agenda.objects.create(label='Agenda', kind='meetings') |
|
227 |
agenda.resources.add(resource) |
|
228 |
desk = Desk.objects.create(agenda=agenda, label='Desk') |
|
229 |
meetingtype = MeetingType.objects.create(agenda=agenda, label='Bar', duration=20) |
|
230 |
TimePeriod.objects.create( |
|
231 |
desk=desk, weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0) |
|
232 |
) |
|
233 | ||
234 |
login(app) |
|
235 |
today = datetime.date(2018, 11, 10) # fixed day |
|
236 |
app.get('/manage/resource/%s/%s/%s/' % (resource.pk, today.year, 72), status=404) |
|
237 |
resp = app.get('/manage/resource/%s/%s/week/%s/' % (resource.pk, today.year, today.strftime('%W'))) |
|
238 |
assert '<div class="booking' not in resp.text |
|
239 |
assert resp.text.count('<tr') == 9 |
|
240 | ||
241 |
# book some slots |
|
242 |
for hour, minute in [(10, 30), (14, 0)]: |
|
243 |
event = Event.objects.create( |
|
244 |
agenda=agenda, |
|
245 |
places=1, |
|
246 |
desk=desk, |
|
247 |
meeting_type=meetingtype, |
|
248 |
start_datetime=now().replace(hour=hour, minute=minute), |
|
249 |
) |
|
250 |
event.resources.add(resource) |
|
251 |
if hour == 10: |
|
252 |
Booking.objects.create(event=event) |
|
253 |
else: |
|
254 |
Booking.objects.create(event=event, label='foo', user_last_name="bar's") |
|
255 | ||
256 |
today = datetime.date.today() |
|
257 |
with CaptureQueriesContext(connection) as ctx: |
|
258 |
resp = app.get('/manage/resource/%s/%s/week/%s/' % (resource.pk, today.year, today.strftime('%W'))) |
|
259 |
assert len(ctx.captured_queries) == 8 |
|
260 |
assert resp.text.count('<div class="booking" style="height:33.0%;') == 2 # booking cells |
|
261 |
assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == 'booked' |
|
262 |
assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "foo - bar's" |
|
263 |
assert get_proper_html_str('foo - bar's') in resp |
|
264 | ||
265 |
agenda.booking_user_block_template = '<b>{{ booking.user_name }}</b> Foo Bar' |
|
266 |
agenda.save() |
|
267 |
resp = app.get('/manage/resource/%s/%s/week/%s/' % (resource.pk, today.year, today.strftime('%W'))) |
|
268 |
assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == '<b></b> Foo Bar' |
|
269 |
assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "<b>bar's</b> Foo Bar" |
|
270 |
assert get_proper_html_str('<b>bar's</b> Foo Bar') in resp |
|
271 | ||
272 |
# cancel booking |
|
273 |
booking = Booking.objects.first() |
|
274 |
booking.cancel() |
|
275 | ||
276 |
# make sure the are not |
|
277 |
resp = app.get('/manage/resource/%s/%s/week/%s/' % (resource.pk, today.year, today.strftime('%W'))) |
|
278 |
assert resp.text.count('<div class="booking"') == 1 |
|
279 | ||
280 | ||
281 |
def test_resource_week_view_weekend(app, admin_user): |
|
282 |
resource = Resource.objects.create(label='Foo bar') |
|
283 |
agenda = Agenda.objects.create(label='Agenda', kind='meetings') |
|
284 |
agenda.resources.add(resource) |
|
285 |
desk = Desk.objects.create(agenda=agenda, label='Desk') |
|
286 |
MeetingType.objects.create(agenda=agenda, label='Bar', duration=30) |
|
287 |
monday = 0 |
|
288 |
TimePeriod.objects.create( |
|
289 |
desk=desk, weekday=monday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0) |
|
290 |
) |
|
291 |
week, year = '01', 2019 |
|
292 | ||
293 |
login(app) |
|
294 |
resp = app.get('/manage/resource/%s/%s/week/%s/' % (resource.pk, year, week)) |
|
295 |
assert 'Sunday' not in resp.text |
|
296 |
assert 'Saturday' not in resp.text |
|
297 |
# Month starts a Tuesday, but monday is displayed |
|
298 |
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0 |
|
299 | ||
300 |
week, year = 21, 2019 # month starts a Saturday |
|
301 |
resp = app.get('/manage/resource/%s/%s/week/%s/' % (resource.pk, year, week)) |
|
302 |
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0 |
|
303 | ||
304 |
saturday = 5 |
|
305 |
timeperiod_sat = TimePeriod.objects.create( |
|
306 |
desk=desk, weekday=saturday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0) |
|
307 |
) |
|
308 |
resp = app.get('/manage/resource/%s/%s/week/%s/' % (resource.pk, year, week)) |
|
309 |
assert 'Sunday' not in resp.text |
|
310 |
assert 'Saturday' in resp.text |
|
311 |
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0 |
|
312 | ||
313 |
sunday = 6 |
|
314 |
TimePeriod.objects.create( |
|
315 |
desk=desk, weekday=sunday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0) |
|
316 |
) |
|
317 |
resp = app.get('/manage/resource/%s/%s/week/%s/' % (resource.pk, year, week)) |
|
318 |
assert 'Sunday' in resp.text |
|
319 |
assert 'Saturday' in resp.text |
|
320 | ||
321 |
timeperiod_sat.delete() |
|
322 |
resp = app.get('/manage/resource/%s/%s/week/%s/' % (resource.pk, year, week)) |
|
323 |
assert 'Sunday' in resp.text |
|
324 |
assert 'Saturday' in resp.text |
|
325 | ||
326 | ||
327 |
def test_resource_week_view_dst_change(app, admin_user): |
|
328 |
resource = Resource.objects.create(label='Foo bar') |
|
329 |
agenda = Agenda.objects.create(label='Agenda', kind='meetings') |
|
330 |
agenda.resources.add(resource) |
|
331 |
desk = Desk.objects.create(agenda=agenda, label='Desk') |
|
332 |
meetingtype = MeetingType.objects.create(agenda=agenda, label='Bar', duration=30) |
|
333 |
TimePeriod.objects.create( |
|
334 |
desk=desk, weekday=0, start_time=datetime.time(9, 0), end_time=datetime.time(12, 0) |
|
335 |
) |
|
336 | ||
337 |
login(app) |
|
338 |
# book some slots |
|
339 |
with freezegun.freeze_time('2019-10-01'): |
|
340 |
for start_datetime in [ |
|
341 |
make_aware(datetime.datetime(2019, 10, 2, 10, 0)), |
|
342 |
make_aware(datetime.datetime(2019, 10, 29, 10, 0)), |
|
343 |
]: |
|
344 |
event = Event.objects.create( |
|
345 |
agenda=agenda, |
|
346 |
places=1, |
|
347 |
desk=desk, |
|
348 |
meeting_type=meetingtype, |
|
349 |
start_datetime=start_datetime, |
|
350 |
) |
|
351 |
event.resources.add(resource) |
|
352 |
Booking.objects.create(event=event) |
|
353 | ||
354 |
# check booked slots are similarly aligned |
|
355 |
resp = app.get('/manage/resource/%s/2019/week/43/' % resource.pk) |
|
356 |
assert resp.text.count('height:50.0%;top:100.0%') == 1 |
|
357 | ||
358 | ||
359 |
def test_resource_week_view_januaries(app, admin_user): |
|
360 |
resource = Resource.objects.create(label='Foo bar') |
|
361 |
agenda = Agenda.objects.create(label='Agenda', kind='meetings') |
|
362 |
agenda.resources.add(resource) |
|
363 |
desk = Desk.objects.create(agenda=agenda, label='Desk') |
|
364 |
TimePeriod(desk=desk, weekday=2, start_time=datetime.time(9, 0), end_time=datetime.time(12, 0)).save() |
|
365 | ||
366 |
for year in range(2020, 2030): |
|
367 |
date = datetime.date(year, 1, 1) |
|
368 |
with freezegun.freeze_time(date): |
|
369 |
login(app) |
|
370 |
resp = app.get('/manage/resource/%s/%s/week/01/' % (resource.pk, date.year)) |
|
371 |
assert resp.text.count('<th></th>') == 1 |
|
372 | ||
373 | ||
374 |
def test_resource_week_view_event_outside_timeperiod(app, admin_user): |
|
375 |
middle_day = now().replace(day=15) |
|
376 |
middle_day = middle_day + datetime.timedelta(days=4 - middle_day.weekday()) |
|
377 |
resource = Resource.objects.create(label='Foo bar') |
|
378 |
agenda = Agenda.objects.create(label='Agenda', kind='meetings') |
|
379 |
agenda.resources.add(resource) |
|
380 |
desk = Desk.objects.create(agenda=agenda, label='Desk') |
|
381 |
meetingtype = MeetingType.objects.create(agenda=agenda, label='Bar', duration=30) |
|
382 |
login(app) |
|
383 | ||
384 |
# no time period - no events |
|
385 |
resp = app.get( |
|
386 |
'/manage/resource/%s/%d/week/%s/' % (resource.pk, middle_day.year, middle_day.strftime('%W')) |
|
387 |
) |
|
388 |
assert 'No bookings this week.' in resp.text |
|
389 |
assert 'div class="booking' not in resp.text |
|
390 | ||
391 |
# book some slots |
|
392 |
for hour, minute in [(9, 0), (17, 0)]: |
|
393 |
event = Event.objects.create( |
|
394 |
agenda=agenda, |
|
395 |
places=1, |
|
396 |
desk=desk, |
|
397 |
meeting_type=meetingtype, |
|
398 |
start_datetime=localtime(now()).replace( |
|
399 |
day=middle_day.day - middle_day.weekday() + 2, hour=hour, minute=minute |
|
400 |
), |
|
401 |
) |
|
402 |
event.resources.add(resource) |
|
403 |
Booking.objects.create(event=event) |
|
404 | ||
405 |
# no time period - events are displayed |
|
406 |
resp = app.get( |
|
407 |
'/manage/resource/%s/%d/week/%s/' % (resource.pk, middle_day.year, middle_day.strftime('%W')) |
|
408 |
) |
|
409 |
assert resp.text.count('div class="booking') == 2 |
|
410 | ||
411 |
# events outside time period |
|
412 |
TimePeriod.objects.create( |
|
413 |
desk=desk, weekday=2, start_time=datetime.time(10, 0), end_time=datetime.time(16, 0) |
|
414 |
) |
|
415 |
resp = app.get( |
|
416 |
'/manage/resource/%s/%d/week/%s/' % (resource.pk, middle_day.year, middle_day.strftime('%W')) |
|
417 |
) |
|
418 |
assert resp.text.count('div class="booking') == 2 |
|
419 |
assert 'Sunday' not in resp.text |
|
420 |
assert 'Saturday' not in resp.text |
|
421 | ||
422 |
# bookings are cancelled |
|
423 |
Booking.objects.update(cancellation_datetime=now()) |
|
424 |
resp = app.get( |
|
425 |
'/manage/resource/%s/%d/week/%s/' % (resource.pk, middle_day.year, middle_day.strftime('%W')) |
|
426 |
) |
|
427 |
assert resp.text.count('div class="booking') == 0 |
|
428 | ||
429 |
# create an event on saturday |
|
430 |
Booking.objects.update(cancellation_datetime=None) # reset |
|
431 |
middle_day = now().replace(day=15) |
|
432 |
middle_day = middle_day + datetime.timedelta(days=5 - middle_day.weekday()) |
|
433 |
event = Event.objects.create( |
|
434 |
agenda=agenda, |
|
435 |
places=1, |
|
436 |
desk=desk, |
|
437 |
meeting_type=meetingtype, |
|
438 |
start_datetime=localtime(now()).replace(day=middle_day.day, hour=10, minute=0), |
|
439 |
) |
|
440 |
event.resources.add(resource) |
|
441 |
Booking.objects.create(event=event) |
|
442 |
resp = app.get( |
|
443 |
'/manage/resource/%s/%d/week/%s/' % (resource.pk, middle_day.year, middle_day.strftime('%W')) |
|
444 |
) |
|
445 |
assert resp.text.count('div class="booking') == 3 |
|
446 |
assert 'Sunday' not in resp.text |
|
447 |
assert 'Saturday' in resp.text |
|
448 |
# bookings are cancelled |
|
449 |
Booking.objects.update(cancellation_datetime=now()) |
|
450 |
resp = app.get( |
|
451 |
'/manage/resource/%s/%d/week/%s/' % (resource.pk, middle_day.year, middle_day.strftime('%W')) |
|
452 |
) |
|
453 |
assert resp.text.count('div class="booking') == 0 |
|
454 |
# and a timeperiod |
|
455 |
Booking.objects.update(cancellation_datetime=None) # reset |
|
456 |
TimePeriod.objects.create( |
|
457 |
desk=desk, weekday=5, start_time=datetime.time(11, 0), end_time=datetime.time(12, 0) |
|
458 |
) |
|
459 |
resp = app.get( |
|
460 |
'/manage/resource/%s/%d/week/%s/' % (resource.pk, middle_day.year, middle_day.strftime('%W')) |
|
461 |
) |
|
462 |
assert resp.text.count('div class="booking') == 3 |
|
463 |
assert 'Sunday' not in resp.text |
|
464 |
assert 'Saturday' in resp.text |
|
465 | ||
466 |
# create an event on sunday |
|
467 |
middle_day = now().replace(day=15) |
|
468 |
middle_day = middle_day + datetime.timedelta(days=6 - middle_day.weekday()) |
|
469 |
event = Event.objects.create( |
|
470 |
agenda=agenda, |
|
471 |
places=1, |
|
472 |
desk=desk, |
|
473 |
meeting_type=meetingtype, |
|
474 |
start_datetime=localtime(now()).replace(day=middle_day.day, hour=10, minute=0), |
|
475 |
) |
|
476 |
event.resources.add(resource) |
|
477 |
Booking.objects.create(event=event) |
|
478 |
resp = app.get( |
|
479 |
'/manage/resource/%s/%d/week/%s/' % (resource.pk, middle_day.year, middle_day.strftime('%W')) |
|
480 |
) |
|
481 |
assert resp.text.count('div class="booking') == 4 |
|
482 |
assert 'Sunday' in resp.text |
|
483 |
assert 'Saturday' in resp.text |
|
484 |
# bookings are cancelled |
|
485 |
Booking.objects.update(cancellation_datetime=now()) |
|
486 |
resp = app.get( |
|
487 |
'/manage/resource/%s/%d/week/%s/' % (resource.pk, middle_day.year, middle_day.strftime('%W')) |
|
488 |
) |
|
489 |
assert resp.text.count('div class="booking') == 0 |
|
490 |
# and a timeperiod |
|
491 |
Booking.objects.update(cancellation_datetime=None) # reset |
|
492 |
TimePeriod.objects.create( |
|
493 |
desk=desk, weekday=6, start_time=datetime.time(11, 0), end_time=datetime.time(12, 0) |
|
494 |
) |
|
495 |
resp = app.get( |
|
496 |
'/manage/resource/%s/%d/week/%s/' % (resource.pk, middle_day.year, middle_day.strftime('%W')) |
|
497 |
) |
|
498 |
assert resp.text.count('div class="booking') == 4 |
|
499 |
assert 'Sunday' in resp.text |
|
500 |
assert 'Saturday' in resp.text |
|
501 | ||
502 | ||
503 |
def test_week_view_resource_as_manager(app, manager_user): |
|
504 |
agenda = Agenda.objects.create(label='Foo Bar', kind='meetings') |
|
505 |
agenda.view_role = manager_user.groups.all()[0] |
|
506 |
agenda.save() |
|
507 |
resource = Resource.objects.create(label='Resource 1') |
|
508 |
app = login(app, username='manager', password='manager') |
|
509 |
today = datetime.date.today() |
|
510 |
app.get('/manage/resource/%s/%d/week/%s/' % (resource.pk, today.year, today.strftime('%W')), status=403) |
|
511 | ||
512 | ||
223 | 513 |
@freezegun.freeze_time('2020-06-15') |
224 | 514 |
def test_resource_month_view(app, admin_user, get_proper_html_str): |
225 | 515 |
resource = Resource.objects.create(label='Foo bar') |
... | ... | |
261 | 551 |
today = datetime.date.today() |
262 | 552 |
with CaptureQueriesContext(connection) as ctx: |
263 | 553 |
resp = app.get('/manage/resource/%s/%s/%s/' % (resource.pk, today.year, today.month)) |
264 |
assert len(ctx.captured_queries) == 8
|
|
554 |
assert len(ctx.captured_queries) == 9
|
|
265 | 555 |
assert resp.text.count('<div class="booking" style="height:33.0%;') == 2 # booking cells |
266 | 556 |
assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == 'booked' |
267 | 557 |
assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "foo - bar's" |
268 |
- |